From 61d7661297c8473859bd0f2e20927e950ef6b103 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 22 Jul 2021 10:11:34 -0400 Subject: [PATCH 01/99] chore: add cooldown to channel_model.dart and test it --- .../stream_chat/lib/src/core/models/channel_model.dart | 8 ++++++++ .../stream_chat/test/src/core/models/channel_test.dart | 1 + 2 files changed, 9 insertions(+) diff --git a/packages/stream_chat/lib/src/core/models/channel_model.dart b/packages/stream_chat/lib/src/core/models/channel_model.dart index 37e587ff..9fdf3723 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.dart @@ -23,6 +23,7 @@ class ChannelModel { this.memberCount = 0, this.extraData = const {}, this.team, + this.cooldown = 0, }) : assert( (cid != null && cid.contains(':')) || (id != null && type != null), 'provide either a cid or an id and type', @@ -81,6 +82,9 @@ class ChannelModel { @JsonKey(includeIfNull: false, toJson: Serializer.readOnly, defaultValue: 0) final int memberCount; + @JsonKey(includeIfNull: false) + final int cooldown; + /// Map of custom channel extraData @JsonKey( includeIfNull: false, @@ -107,6 +111,7 @@ class ChannelModel { 'deleted_at', 'member_count', 'team', + 'cooldown', ]; /// Shortcut for channel name @@ -133,6 +138,7 @@ class ChannelModel { int? memberCount, Map? extraData, String? team, + int? cooldown, }) => ChannelModel( id: id ?? this.id, @@ -148,6 +154,7 @@ class ChannelModel { memberCount: memberCount ?? this.memberCount, extraData: extraData ?? this.extraData, team: team ?? this.team, + cooldown: cooldown ?? this.cooldown, ); /// Returns a new [ChannelModel] that is a combination of this channelModel @@ -168,6 +175,7 @@ class ChannelModel { memberCount: other.memberCount, extraData: other.extraData, team: other.team, + cooldown: other.cooldown, ); } } diff --git a/packages/stream_chat/test/src/core/models/channel_test.dart b/packages/stream_chat/test/src/core/models/channel_test.dart index ca734c44..31162bd6 100644 --- a/packages/stream_chat/test/src/core/models/channel_test.dart +++ b/packages/stream_chat/test/src/core/models/channel_test.dart @@ -12,6 +12,7 @@ void main() { expect(channel.cid, equals('livestream:test')); expect(channel.extraData['cats'], equals(true)); expect(channel.extraData['fruit'], equals(['bananas', 'apples'])); + expect(channel.cooldown, equals(0)); }); test('should serialize to json correctly', () { From da3cf4d6de168f1e183758fb6978cb61134b9a8c Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 22 Jul 2021 10:20:31 -0400 Subject: [PATCH 02/99] chore: start adding cooldown and cooldown stream to channel.dart --- packages/stream_chat/lib/src/client/channel.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 94a07f34..6bec5ce7 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -118,6 +118,18 @@ class Channel { return state?.channelStateStream.map((cs) => cs.channel?.frozen); } + /// Cooldown count + int? get cooldown { + _checkInitialized(); + return state?._channelState.channel?.cooldown; + } + + /// Cooldown count as a stream + Stream? get cooldownStream { + _checkInitialized(); + return state?.cooldownStateStream.map((cs) => cs.channel?.cooldown); + } + /// Channel creation date DateTime? get createdAt { _checkInitialized(); From c2b6ea13d816fd12818dba5ff1c1475aba23d111 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 22 Jul 2021 13:46:04 -0400 Subject: [PATCH 03/99] fix: use the right stream for cooldown stream --- packages/stream_chat/lib/src/client/channel.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 6bec5ce7..4a7cbbb5 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -127,7 +127,7 @@ class Channel { /// Cooldown count as a stream Stream? get cooldownStream { _checkInitialized(); - return state?.cooldownStateStream.map((cs) => cs.channel?.cooldown); + return state?.channelStateStream.map((cs) => cs.channel?.cooldown); } /// Channel creation date From 848aa550f763c2cef2bbaa500e9ff96e5e870b87 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 22 Jul 2021 13:47:58 -0400 Subject: [PATCH 04/99] chore: add doc for cooldown in channel_model.dart --- packages/stream_chat/lib/src/core/models/channel_model.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat/lib/src/core/models/channel_model.dart b/packages/stream_chat/lib/src/core/models/channel_model.dart index 9fdf3723..3df04007 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.dart @@ -82,6 +82,7 @@ class ChannelModel { @JsonKey(includeIfNull: false, toJson: Serializer.readOnly, defaultValue: 0) final int memberCount; + /// The number of seconds in a cooldown @JsonKey(includeIfNull: false) final int cooldown; From 9fb60e93c1c93d13b7b540a4f2bd3ef5dee6e9e7 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 26 Jul 2021 11:42:24 -0400 Subject: [PATCH 05/99] progress on slow mode --- .../stream_chat/lib/src/client/channel.dart | 20 ++++ .../stream_chat/lib/src/client/client.dart | 22 +++++ .../lib/src/core/api/channel_api.dart | 29 ++++++ .../lib/src/core/models/channel_model.dart | 2 +- .../lib/src/core/models/channel_model.g.dart | 2 + .../lib/src/core/models/own_user.g.dart | 3 + .../stream_chat_flutter/example/lib/main.dart | 14 ++- .../lib/src/message_input.dart | 98 +++++++++++++++++-- .../lib/src/message_list_view.dart | 4 +- 9 files changed, 178 insertions(+), 16 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 4a7cbbb5..8e298fc9 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -130,6 +130,9 @@ class Channel { return state?.channelStateStream.map((cs) => cs.channel?.cooldown); } + /// + DateTime? cooldownStartedAt; + /// Channel creation date DateTime? get createdAt { _checkInitialized(); @@ -429,6 +432,9 @@ class Channel { skipPush: skipPush, ); state!.addMessage(response.message); + if (cooldown! > 0) { + cooldownStartedAt = DateTime.now(); + } return response; } catch (e) { if (e is StreamChatNetworkError && e.isRetriable) { @@ -827,6 +833,20 @@ class Channel { return _client.updateChannelPartial(id!, type, set: set, unset: unset); } + /// Enable slow mode + Future enableSlowMode({ + required int cooldownInterval, + }) async { + _checkInitialized(); + return _client.enableSlowdown(id!, type, cooldownInterval); + } + + /// Disable slow mode + Future disableSlowMode() async { + _checkInitialized(); + return _client.disableSlowdown(id!, type); + } + /// Delete this channel. Messages are permanently removed. Future delete() async { _checkInitialized(); diff --git a/packages/stream_chat/lib/src/client/client.dart b/packages/stream_chat/lib/src/client/client.dart index 050d36f1..2ea20e60 100644 --- a/packages/stream_chat/lib/src/client/client.dart +++ b/packages/stream_chat/lib/src/client/client.dart @@ -1244,6 +1244,28 @@ class StreamChatClient { language, ); + /// Enables slow mode + Future enableSlowdown( + String channelId, + String channelType, + int cooldown, + ) async => + _chatApi.channel.enableSlowdown( + channelId, + channelType, + cooldown, + ); + + /// Disables slow mode + Future disableSlowdown( + String channelId, + String channelType, + ) async => + _chatApi.channel.disableSlowdown( + channelId, + channelType, + ); + /// Pins provided message /// [timeoutOrExpirationDate] can either be a [DateTime] or a value in seconds /// to be added to [DateTime.now] diff --git a/packages/stream_chat/lib/src/core/api/channel_api.dart b/packages/stream_chat/lib/src/core/api/channel_api.dart index 1ba7f333..31a64cf8 100644 --- a/packages/stream_chat/lib/src/core/api/channel_api.dart +++ b/packages/stream_chat/lib/src/core/api/channel_api.dart @@ -123,6 +123,35 @@ class ChannelApi { return PartialUpdateChannelResponse.fromJson(response.data); } + /// Enable slowdown + Future enableSlowdown( + String channelId, + String channelType, + int cooldown, + ) async { + final response = await _client.post( + _getChannelUrl(channelId, channelType), + data: { + 'cooldown': cooldown, + }, + ); + return UpdateChannelResponse.fromJson(response.data); + } + + /// Disable slowdown + Future disableSlowdown( + String channelId, + String channelType, + ) async { + final response = await _client.post( + _getChannelUrl(channelId, channelType), + data: { + 'cooldown': 0, + }, + ); + return UpdateChannelResponse.fromJson(response.data); + } + /// Accept invitation to the channel Future acceptChannelInvite( String channelId, diff --git a/packages/stream_chat/lib/src/core/models/channel_model.dart b/packages/stream_chat/lib/src/core/models/channel_model.dart index 3df04007..a4e6db79 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.dart @@ -83,7 +83,7 @@ class ChannelModel { final int memberCount; /// The number of seconds in a cooldown - @JsonKey(includeIfNull: false) + @JsonKey(includeIfNull: false, defaultValue: 0) final int cooldown; /// Map of custom channel extraData diff --git a/packages/stream_chat/lib/src/core/models/channel_model.g.dart b/packages/stream_chat/lib/src/core/models/channel_model.g.dart index 4bde3d4a..d9adf94b 100644 --- a/packages/stream_chat/lib/src/core/models/channel_model.g.dart +++ b/packages/stream_chat/lib/src/core/models/channel_model.g.dart @@ -33,6 +33,7 @@ ChannelModel _$ChannelModelFromJson(Map json) { memberCount: json['member_count'] as int? ?? 0, extraData: json['extra_data'] as Map? ?? {}, team: json['team'] as String?, + cooldown: json['cooldown'] as int? ?? 0, ); } @@ -57,6 +58,7 @@ Map _$ChannelModelToJson(ChannelModel instance) { writeNotNull('updated_at', readonly(instance.updatedAt)); writeNotNull('deleted_at', readonly(instance.deletedAt)); writeNotNull('member_count', readonly(instance.memberCount)); + val['cooldown'] = instance.cooldown; val['extra_data'] = instance.extraData; writeNotNull('team', readonly(instance.team)); return val; diff --git a/packages/stream_chat/lib/src/core/models/own_user.g.dart b/packages/stream_chat/lib/src/core/models/own_user.g.dart index 26e4786e..465faff2 100644 --- a/packages/stream_chat/lib/src/core/models/own_user.g.dart +++ b/packages/stream_chat/lib/src/core/models/own_user.g.dart @@ -36,5 +36,8 @@ OwnUser _$OwnUserFromJson(Map json) { online: json['online'] as bool? ?? false, extraData: json['extra_data'] as Map? ?? {}, banned: json['banned'] as bool? ?? false, + teams: + (json['teams'] as List?)?.map((e) => e as String).toList() ?? + [], ); } diff --git a/packages/stream_chat_flutter/example/lib/main.dart b/packages/stream_chat_flutter/example/lib/main.dart index 89362d81..6f038616 100644 --- a/packages/stream_chat_flutter/example/lib/main.dart +++ b/packages/stream_chat_flutter/example/lib/main.dart @@ -13,7 +13,7 @@ void main() async { /// Create a new instance of [StreamChatClient] passing the apikey obtained /// from your project dashboard. final client = StreamChatClient( - 's2dxdhpxd94g', + 'kv7mcsxr24p8', logLevel: Level.INFO, )..chatPersistenceClient = chatPersistentClient; @@ -24,15 +24,19 @@ void main() async { /// Please see the following for more information: /// https://getstream.io/chat/docs/ios_user_setup_and_tokens/ await client.connectUser( - User(id: 'super-band-9'), - 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.' - '0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', + User(id: 'salvatore'), + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.pgiJz7sIc7iP29BHKFwe3nLm5-OaR_1l2P-SlgiC9a8', ); - final channel = client.channel('messaging', id: 'godevs'); + final channel = client.channel('messaging', id: 'godevs2', extraData: { + 'members': ['salvatore'], + }); await channel.watch(); + await channel.enableSlowMode(cooldownInterval: 20); + print('Channel cooldown set to ${channel.cooldown}'); + runApp( MyApp( client: client, diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 5a4f6822..c3c2e30a 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -291,9 +291,13 @@ class MessageInputState extends State { bool get _hasQuotedMessage => widget.quotedMessage != null; + late DateTime? _cooldownStartedAt; + int? _timeOut; + @override void initState() { super.initState(); + _startSlowMode(); _focusNode = widget.focusNode ?? FocusNode(); _emojiNames = Emoji.all().where((it) => it.name != null).map((e) => e.name!); @@ -324,6 +328,25 @@ class MessageInputState extends State { }); } + void _startSlowMode() { + if (StreamChannel.of(context).channel.cooldownStartedAt != null) { + _cooldownStartedAt = StreamChannel.of(context).channel.cooldownStartedAt; + if (DateTime.now().difference(_cooldownStartedAt!).inSeconds < + StreamChannel.of(context).channel.cooldown!) { + _timeOut = StreamChannel.of(context).channel.cooldown! - + DateTime.now().difference(_cooldownStartedAt!).inSeconds; + Timer.periodic(const Duration(seconds: 1), (timer) { + if (_timeOut == 0) { + timer.cancel(); + } else { + print('Time left until cooldown is over: $_timeOut'); + setState(() => _timeOut = _timeOut! - 1); + } + }); + } + } + } + @override Widget build(BuildContext context) { Widget child = DecoratedBox( @@ -472,13 +495,44 @@ class MessageInputState extends State { ); Widget _animateSendButton(BuildContext context) { - final sendButton = widget.activeSendButton != null - ? InkWell( - onTap: sendMessage, - child: widget.activeSendButton, - ) - : _buildSendButton(context); - return AnimatedCrossFade( + late Widget sendButton; + if (_timeOut != null && _timeOut! > 0) { + sendButton = _CountdownButton( + count: _timeOut!, + ); + } else if (!_messageIsPresent && _attachments.isEmpty) { + sendButton = widget.idleSendButton ?? _buildIdleSendButton(context); + } else { + sendButton = widget.activeSendButton != null + ? InkWell( + onTap: sendMessage, + child: widget.activeSendButton, + ) + : _buildSendButton(context); + } + + /*if (_timeOut == null || _timeOut == 0) { + sendButton = widget.activeSendButton != null + ? InkWell( + onTap: sendMessage, + child: widget.activeSendButton, + ) + : _buildSendButton(context); + } else { + sendButton = _CountdownButton( + count: _timeOut!, + ); + } + + if (!_messageIsPresent && _attachments.isEmpty) { + sendButton = widget.idleSendButton ?? _buildIdleSendButton(context); + }*/ + + return AnimatedSwitcher( + duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!, + child: sendButton, + ); + /*return AnimatedCrossFade( crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) ? CrossFadeState.showFirst : CrossFadeState.showSecond, @@ -486,7 +540,7 @@ class MessageInputState extends State { secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!, alignment: Alignment.center, - ); + );*/ } Widget _buildExpandActionsButton() { @@ -2082,6 +2136,7 @@ class MessageInputState extends State { if (resp.message?.type == 'error') { _parseExistingMessage(message); } + _startSlowMode(); widget.onMessageSent?.call(resp.message); } catch (e, stk) { if (widget.onError != null) { @@ -2347,3 +2402,30 @@ class __PickerWidgetState extends State<_PickerWidget> { }); } } + +class _CountdownButton extends StatelessWidget { + const _CountdownButton({ + Key? key, + required this.count, + }) : super(key: key); + + final int count; + + @override + Widget build(BuildContext context) => Padding( + padding: const EdgeInsets.all(8), + child: DecoratedBox( + decoration: BoxDecoration( + color: StreamChatTheme.of(context).colorTheme.disabled, + shape: BoxShape.circle, + ), + child: SizedBox( + height: 24, + width: 24, + child: Center( + child: Text('$count'), + ), + ), + ), + ); +} diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 3d0a3acd..8a236cbd 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -942,7 +942,7 @@ class _MessageListViewState extends State { final currentUser = StreamChat.of(context).user; final members = StreamChannel.of(context).channel.state?.members ?? []; final currentUserMember = - members.firstWhere((e) => e.user!.id == currentUser!.id); + members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); Widget messageWidget = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), @@ -1049,7 +1049,7 @@ class _MessageListViewState extends State { } FocusScope.of(context).unfocus(); }, - showPinButton: widget.pinPermissions.contains(currentUserMember.role), + showPinButton: widget.pinPermissions.contains(currentUserMember?.role), ); if (widget.messageBuilder != null) { From b989fbc3ad3908b690705d08bd6bc21c432ed6e3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 30 Jul 2021 11:48:23 +0200 Subject: [PATCH 06/99] fix(llc): use channel partial update for slowmode --- .../stream_chat/lib/src/client/channel.dart | 4 ++-- .../stream_chat/lib/src/client/client.dart | 4 ++-- .../lib/src/core/api/channel_api.dart | 24 +++++++++---------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index fb579a56..1f6d3edd 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -834,7 +834,7 @@ class Channel { } /// Enable slow mode - Future enableSlowMode({ + Future enableSlowMode({ required int cooldownInterval, }) async { _checkInitialized(); @@ -842,7 +842,7 @@ class Channel { } /// Disable slow mode - Future disableSlowMode() async { + Future disableSlowMode() async { _checkInitialized(); return _client.disableSlowdown(id!, type); } diff --git a/packages/stream_chat/lib/src/client/client.dart b/packages/stream_chat/lib/src/client/client.dart index 7b5cbb35..788bc9cf 100644 --- a/packages/stream_chat/lib/src/client/client.dart +++ b/packages/stream_chat/lib/src/client/client.dart @@ -1248,7 +1248,7 @@ class StreamChatClient { ); /// Enables slow mode - Future enableSlowdown( + Future enableSlowdown( String channelId, String channelType, int cooldown, @@ -1260,7 +1260,7 @@ class StreamChatClient { ); /// Disables slow mode - Future disableSlowdown( + Future disableSlowdown( String channelId, String channelType, ) async => diff --git a/packages/stream_chat/lib/src/core/api/channel_api.dart b/packages/stream_chat/lib/src/core/api/channel_api.dart index 31a64cf8..e8782feb 100644 --- a/packages/stream_chat/lib/src/core/api/channel_api.dart +++ b/packages/stream_chat/lib/src/core/api/channel_api.dart @@ -124,32 +124,32 @@ class ChannelApi { } /// Enable slowdown - Future enableSlowdown( + Future enableSlowdown( String channelId, String channelType, int cooldown, ) async { - final response = await _client.post( - _getChannelUrl(channelId, channelType), - data: { + final response = await updateChannelPartial( + channelId, + channelType, + set: { 'cooldown': cooldown, }, ); - return UpdateChannelResponse.fromJson(response.data); + return response; } /// Disable slowdown - Future disableSlowdown( + Future disableSlowdown( String channelId, String channelType, ) async { - final response = await _client.post( - _getChannelUrl(channelId, channelType), - data: { - 'cooldown': 0, - }, + final response = await updateChannelPartial( + channelId, + channelType, + unset: ['cooldown'], ); - return UpdateChannelResponse.fromJson(response.data); + return response; } /// Accept invitation to the channel From e14258c3906554b659ad73439f27b9273308ad16 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 2 Aug 2021 15:19:12 -0400 Subject: [PATCH 07/99] feat: support for japanese --- .../lib/src/stream_chat_localizations.dart | 5 + .../lib/src/stream_chat_localizations_ja.dart | 360 ++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart index a6a66b93..e65aab1f 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart @@ -11,6 +11,8 @@ part 'stream_chat_localizations_fr.dart'; part 'stream_chat_localizations_it.dart'; +part 'stream_chat_localizations_ja.dart'; + part 'stream_chat_localizations_hi.dart'; /// The set of supported languages, as language code strings. @@ -27,6 +29,7 @@ const kStreamChatSupportedLanguages = { 'fr', 'it', 'es', + 'ja', }; /// Creates a [GlobalStreamChatLocalizations] instance for the given `locale`. @@ -59,6 +62,8 @@ GlobalStreamChatLocalizations? getStreamChatTranslation(Locale locale) { return const StreamChatLocalizationsIt(); case 'es': return const StreamChatLocalizationsEs(); + case 'ja': + return const StreamChatLocalizationsJa(); } } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart new file mode 100644 index 00000000..96ffec25 --- /dev/null +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -0,0 +1,360 @@ +part of 'stream_chat_localizations.dart'; + +/// The translations for English (`ja`). +class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { + /// Create an instance of the translation bundle for Japanese. + const StreamChatLocalizationsJa({String localeName = 'ja'}) + : super(localeName: localeName); + + @override + String get launchUrlError => 'ユーアーレルの起動ができない'; + + @override + String get loadingUsersError => 'ユーザーの読み込みエラー'; + + @override + String get noUsersLabel => '現在、ユーザーはいません。'; + + @override + String get retryLabel => '再試行'; + + @override + String get userLastOnlineText => '前回のオンライン'; + + @override + String get userOnlineText => 'オンライン'; + + @override + String userTypingText(Iterable users) { + if (users.isEmpty) return ''; + final first = users.first; + if (users.length == 1) { + return '${first.name}がタイプしている'; + } + return '${first.name}とあと${users.length - 1}人が入力しています'; + } + + @override + String get threadReplyLabel => 'スレッド返信'; + + @override + String get onlyVisibleToYouText => '自分にしか見えない'; + + @override + String threadReplyCountText(int count) => '$countスレッドの返信'; + + @override + String attachmentsUploadProgressText({ + required int remaining, + required int total, + }) => + '$remaining/${total}mbのアップロード 。。。'; + + @override + String pinnedByUserText({ + required User pinnedBy, + required User currentUser, + }) { + final pinnedByCurrentUser = currentUser.id == pinnedBy.id; + if (pinnedByCurrentUser) return 'あなたのピン留'; + return '${pinnedBy.name}のピン留'; + } + + @override + String get emptyMessagesText => '現在、メッセージはありません。'; + + @override + String get genericErrorText => '何かが間違っていた'; + + @override + String get loadingMessagesError => 'メッセージの読み込みエラー'; + + @override + String resultCountText(int count) => '$countつの結果'; + + @override + String get messageDeletedText => 'このメッセージは削除されました。'; + + @override + String get messageDeletedLabel => 'メッセージ削除'; + + @override + String get messageReactionsLabel => 'メッセージに対する反応'; + + @override + String get emptyChatMessagesText => 'ここではまだ会話はありませんが。。。'; + + @override + String threadSeparatorText(int replyCount) { + if (replyCount == 1) return '1 回答'; + return '$replyCount件の返信'; + } + + @override + String get connectedLabel => 'コネクテッド'; + + @override + String get disconnectedLabel => '接続切れ'; + + @override + String get reconnectingLabel => 'リコネクティング。。。'; + + @override + String get alsoSendAsDirectMessageLabel => 'ダイレクトメッセージでも送信可能'; + + @override + String get addACommentOrSendLabel => 'コメントの追加や送信'; + + @override + String get searchGifLabel => '検索用GIF'; + + @override + String get writeAMessageLabel => 'メッセージを書く'; + + @override + String get instantCommandsLabel => 'インスタントコマンド'; + + @override + String fileTooLargeAfterCompressionError(double limitInMB) => + 'ファイルのサイズが大きすぎてアップロードできません。' + 'ファイルサイズの制限は${limitInMB}MBです。' + '圧縮してみましたが、十分ではありませんでした。'; + + @override + String fileTooLargeError(double limitInMB) => + 'ファイルが大きすぎてアップロードできません。ファイルサイズの制限は${limitInMB}MBです。'; + + @override + String emojiMatchingQueryText(String query) => '「"$query"」とお揃いの絵文字'; + + @override + String get addAFileLabel => 'ファイルの追加'; + + @override + String get photoFromCameraLabel => 'カメラからの写真'; + + @override + String get uploadAFileLabel => 'ファイルのアップロード'; + + @override + String get uploadAPhotoLabel => '写真のアップロード'; + + @override + String get uploadAVideoLabel => '動画のアップロード'; + + @override + String get videoFromCameraLabel => 'カメラからの動画'; + + @override + String get okLabel => 'よし'; + + @override + String get somethingWentWrongError => '何かが間違っていたのだ。'; + + @override + String get addMoreFilesLabel => 'ファイルの追加'; + + @override + String get enablePhotoAndVideoAccessMessage => 'お友達と共有できるように、写真' + '\nやビデオへのアクセスを有効にしてください。'; + @override + String get allowGalleryAccessMessage => 'お客様のギャラリーへのアクセスを許可する'; + + @override + String get flagMessageLabel => 'メッセージフラグが'; + + @override + String get flagMessageQuestion => 'このメッセージのコピーを' + '\nモデレーターに送って、さらに調査してもらいますか?'; + + @override + String get flagLabel => 'フラグが'; + + @override + String get cancelLabel => 'キャンセル'; + + @override + String get flagMessageSuccessfulLabel => 'フラグ付メッセージ'; + + @override + String get flagMessageSuccessfulText => + 'このメッセージはモデレーターに報告されました。'; + + @override + String get deleteLabel => '消す'; + + @override + String get deleteMessageLabel => 'メッセージを削除する '; + + @override + String get deleteMessageQuestion => + 'このメッセージ' + '\nを完全に削除してもよろしいですか?'; + + @override + String get operationCouldNotBeCompletedText => + '操作を完了できませんでした。'; + + @override + String get replyLabel => '返信'; + + @override + String togglePinUnpinText({required bool pinned}) { + if (pinned) return 'カンバセーションからピンを外す '; + return '会話へのピン'; + } + + @override + String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed}) { + if (isDeleteFailed) return 'メッセージの削除を再試行してください'; + return 'メッセージを削除する'; + } + + @override + String get copyMessageLabel => 'コピーメッセージ'; + + @override + String get editMessageLabel => 'メッセージの編集'; + + @override + String toggleResendOrResendEditedMessage({required bool isUpdateFailed}) { + if (isUpdateFailed) return '編集したメッセージの再送'; + return '再送'; + } + + @override + String get photosLabel => '写真'; + + String _getDay(DateTime dateTime) { + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + final yesterday = DateTime(now.year, now.month, now.day - 1); + + final date = DateTime(dateTime.year, dateTime.month, dateTime.day); + + if (date == today) { + return '今日'; + } else if (date == yesterday) { + return '昨日'; + } else { + return '${Jiffy(date).MMMd}に'; + } + } + + @override + String sentAtText({required DateTime date, required DateTime time}) => + '${_getDay(date)} at ${Jiffy(time.toLocal()).format('HH:mm')}に送信 '; + + @override + String get todayLabel => '今日'; + + @override + String get yesterdayLabel => '昨日'; + + @override + String get channelIsMutedText => 'チャンネルがミュートされています'; + + @override + String get noTitleText => 'タイトル無し'; + + @override + String get letsStartChattingLabel => 'さあ、チャットを始めよう'; + + @override + String get sendingFirstMessageLabel => + 'どのように友人にあなたの最初のメッセージを送ることについてはどうですか?'; + + @override + String get startAChatLabel => 'チャットを開始する'; + + @override + String get loadingChannelsError => 'チャネルのロード中にエラーが発生しました'; + + @override + String get deleteConversationLabel => '会話を削除する'; + + @override + String get deleteConversationQuestion => + 'この会話を削除してもよろしいですか?'; + + @override + String get streamChatLabel => 'ストリームチャット'; + + @override + String get searchingForNetworkText => 'ネットワークの検索'; + + @override + String get offlineLabel => 'オフライン。。。'; + + @override + String get tryAgainLabel => '再試行する'; + + @override + String membersCountText(int count) { + if (count == 1) return '1人のメンバー'; + return '$count人のメンバー'; + } + + @override + String watchersCountText(int count) { + if (count == 1) return '1オンライン'; + return '$countオンライン'; + } + + @override + String get viewInfoLabel => '情報を見る'; + + @override + String get leaveGroupLabel => 'グループを離れる'; + + @override + String get leaveLabel => '離れる'; + + @override + String get leaveConversationLabel => '会話を離れる'; + + @override + String get leaveConversationQuestion => + 'この会話を離れてもよろしいですか?'; + + @override + String get showInChatLabel => 'チャットで表示'; + + @override + String get saveImageLabel => '画像を保存'; + + @override + String get saveVideoLabel => 'ビデオを保存'; + + @override + String get uploadErrorLabel => 'アップロードエラー'; + + @override + String get giphyLabel => 'ギフィー'; + + @override + String get shuffleLabel => 'ミックス'; + + @override + String get sendLabel => '送信'; + + @override + String get withText => 'と'; + + @override + String get inText => 'は'; + + @override + String get youText => '君'; + + @override + String get ofText => 'の';//TODO: break + // galleryPaginationText( + // {required int currentPage, required int totalPages}) + + @override + String get fileText => 'ファイル'; + + @override + String get replyToMessageLabel => 'メッセージに返信'; +} From e44a4ce3a1dc88ba89137f4c3baa3fcaabb4d794 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 2 Aug 2021 15:19:55 -0400 Subject: [PATCH 08/99] update fr translation: discussion->conversation --- .../lib/src/stream_chat_localizations_fr.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart index 9d8586d5..373558b9 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart @@ -207,7 +207,7 @@ class StreamChatLocalizationsFr extends GlobalStreamChatLocalizations { @override String togglePinUnpinText({required bool pinned}) { if (pinned) return 'Décrocher de la conversation'; - return 'Épingler à la discussion'; + return 'Épingler à la conversation'; } @override @@ -354,7 +354,7 @@ class StreamChatLocalizationsFr extends GlobalStreamChatLocalizations { String get youText => 'Vous'; @override - String get ofText => 'de'; + String galleryPaginationText({required int currentPage, required int totalPages}) => '${currentPage+1} de $totalPages'; @override String get fileText => 'Fichier'; From 59b4f5568c77ccae4b56d919216bd82058050ffb Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 2 Aug 2021 15:30:58 -0400 Subject: [PATCH 09/99] breaking change: ofText->galleryPaginationText --- .../lib/src/gallery_footer.dart | 6 ++--- .../lib/src/localization/translations.dart | 9 ++++--- .../test/src/default_translations_test.dart | 2 +- .../example/lib/add_new_lang.dart | 4 +++- .../lib/src/stream_chat_localizations_en.dart | 4 +++- .../lib/src/stream_chat_localizations_es.dart | 7 ++++-- .../lib/src/stream_chat_localizations_fr.dart | 4 +++- .../lib/src/stream_chat_localizations_hi.dart | 8 ++++--- .../lib/src/stream_chat_localizations_it.dart | 4 +++- .../lib/src/stream_chat_localizations_ja.dart | 24 +++++++------------ .../test/translations_test.dart | 2 +- 11 files changed, 42 insertions(+), 32 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/gallery_footer.dart b/packages/stream_chat_flutter/lib/src/gallery_footer.dart index 03d575ae..6df301d3 100644 --- a/packages/stream_chat_flutter/lib/src/gallery_footer.dart +++ b/packages/stream_chat_flutter/lib/src/gallery_footer.dart @@ -136,9 +136,9 @@ class _GalleryFooterState extends State { mainAxisSize: MainAxisSize.min, children: [ Text( - '${widget.currentPage + 1} ' - '${context.translations.ofText} ' - '${widget.totalPages}', + context.translations.galleryPaginationText( + currentPage: widget.currentPage, + totalPages: widget.totalPages), style: galleryFooterThemeData.titleTextStyle, ), ], diff --git a/packages/stream_chat_flutter/lib/src/localization/translations.dart b/packages/stream_chat_flutter/lib/src/localization/translations.dart index d6e5add0..d3b3e8cb 100644 --- a/packages/stream_chat_flutter/lib/src/localization/translations.dart +++ b/packages/stream_chat_flutter/lib/src/localization/translations.dart @@ -296,8 +296,9 @@ abstract class Translations { /// The text shown for "You" String get youText; - /// The text shown for "Of" - String get ofText; + /// Gallery footer pagination text + String galleryPaginationText( + {required int currentPage, required int totalPages}); /// The text shown for "File" String get fileText; @@ -657,7 +658,9 @@ class DefaultTranslations implements Translations { String get youText => 'You'; @override - String get ofText => 'of'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} of $totalPages'; @override String get fileText => 'File'; diff --git a/packages/stream_chat_flutter/test/src/default_translations_test.dart b/packages/stream_chat_flutter/test/src/default_translations_test.dart index e78c0115..14a4a318 100644 --- a/packages/stream_chat_flutter/test/src/default_translations_test.dart +++ b/packages/stream_chat_flutter/test/src/default_translations_test.dart @@ -167,7 +167,7 @@ void main() { expect(translations.withText, isNotNull); expect(translations.inText, isNotNull); expect(translations.youText, isNotNull); - expect(translations.ofText, isNotNull); + expect(translations.galleryPaginationText, isNotNull); expect(translations.fileText, isNotNull); expect(translations.replyToMessageLabel, isNotNull); }); diff --git a/packages/stream_chat_localizations/example/lib/add_new_lang.dart b/packages/stream_chat_localizations/example/lib/add_new_lang.dart index 1412f4e0..2f373691 100644 --- a/packages/stream_chat_localizations/example/lib/add_new_lang.dart +++ b/packages/stream_chat_localizations/example/lib/add_new_lang.dart @@ -374,7 +374,9 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations { String get youText => 'You'; @override - String get ofText => 'of'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '$currentPage of $totalPages'; @override String get fileText => 'File'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart index 5041d398..13de9729 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart @@ -350,7 +350,9 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations { String get youText => 'You'; @override - String get ofText => 'of'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} of $totalPages'; @override String get fileText => 'File'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart index 75bed1e3..f6cd5e7c 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart @@ -68,7 +68,8 @@ class StreamChatLocalizationsEs extends GlobalStreamChatLocalizations { String get genericErrorText => 'Hubo un problema'; @override - String get loadingMessagesError => 'Hubo un error mientras se cargaba el mensaje'; + String get loadingMessagesError => + 'Hubo un error mientras se cargaba el mensaje'; @override String resultCountText(int count) => '$count resultados'; @@ -354,7 +355,9 @@ class StreamChatLocalizationsEs extends GlobalStreamChatLocalizations { String get youText => 'Usted'; @override - String get ofText => 'de'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} de $totalPages'; @override String get fileText => 'Archivo'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart index 373558b9..2331b522 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart @@ -354,7 +354,9 @@ class StreamChatLocalizationsFr extends GlobalStreamChatLocalizations { String get youText => 'Vous'; @override - String galleryPaginationText({required int currentPage, required int totalPages}) => '${currentPage+1} de $totalPages'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} de $totalPages'; @override String get fileText => 'Fichier'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart index 850e481b..11d7d486 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart @@ -340,16 +340,18 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { String get sendLabel => 'भेजें'; @override - String get withText => 'विद'; + String get withText => 'विद';//TODO: break? @override - String get inText => 'इन'; + String get inText => 'इन';//TODO: break? @override String get youText => 'आप'; @override - String get ofText => 'ऑफ़'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} ऑफ़ $totalPages'; @override String get fileText => 'फ़ाइल'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart index 8b2e1692..313e1e26 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart @@ -351,7 +351,9 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.'''; String get youText => 'te'; @override - String get ofText => 'di'; + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '${currentPage + 1} di $totalPages'; @override String get fileText => 'file'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index 96ffec25..6522fbf7 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -177,8 +177,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get flagMessageSuccessfulLabel => 'フラグ付メッセージ'; @override - String get flagMessageSuccessfulText => - 'このメッセージはモデレーターに報告されました。'; + String get flagMessageSuccessfulText => 'このメッセージはモデレーターに報告されました。'; @override String get deleteLabel => '消す'; @@ -187,13 +186,11 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get deleteMessageLabel => 'メッセージを削除する '; @override - String get deleteMessageQuestion => - 'このメッセージ' + String get deleteMessageQuestion => 'このメッセージ' '\nを完全に削除してもよろしいですか?'; @override - String get operationCouldNotBeCompletedText => - '操作を完了できませんでした。'; + String get operationCouldNotBeCompletedText => '操作を完了できませんでした。'; @override String get replyLabel => '返信'; @@ -261,8 +258,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get letsStartChattingLabel => 'さあ、チャットを始めよう'; @override - String get sendingFirstMessageLabel => - 'どのように友人にあなたの最初のメッセージを送ることについてはどうですか?'; + String get sendingFirstMessageLabel => 'どのように友人にあなたの最初のメッセージを送ることについてはどうですか?'; @override String get startAChatLabel => 'チャットを開始する'; @@ -274,8 +270,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get deleteConversationLabel => '会話を削除する'; @override - String get deleteConversationQuestion => - 'この会話を削除してもよろしいですか?'; + String get deleteConversationQuestion => 'この会話を削除してもよろしいですか?'; @override String get streamChatLabel => 'ストリームチャット'; @@ -314,8 +309,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get leaveConversationLabel => '会話を離れる'; @override - String get leaveConversationQuestion => - 'この会話を離れてもよろしいですか?'; + String get leaveConversationQuestion => 'この会話を離れてもよろしいですか?'; @override String get showInChatLabel => 'チャットで表示'; @@ -348,9 +342,9 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get youText => '君'; @override - String get ofText => 'の';//TODO: break - // galleryPaginationText( - // {required int currentPage, required int totalPages}) + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '$totalPagesの${currentPage + 1}'; @override String get fileText => 'ファイル'; diff --git a/packages/stream_chat_localizations/test/translations_test.dart b/packages/stream_chat_localizations/test/translations_test.dart index 0e621159..c7314a58 100644 --- a/packages/stream_chat_localizations/test/translations_test.dart +++ b/packages/stream_chat_localizations/test/translations_test.dart @@ -174,7 +174,7 @@ void main() { expect(localizations.withText, isNotNull); expect(localizations.inText, isNotNull); expect(localizations.youText, isNotNull); - expect(localizations.ofText, isNotNull); + expect(localizations.galleryPaginationText, isNotNull); expect(localizations.fileText, isNotNull); expect(localizations.replyToMessageLabel, isNotNull); }); From 8ca7dab6da9d6f235f95dd476874b076c5baf988 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 2 Aug 2021 15:36:43 -0400 Subject: [PATCH 10/99] update docs --- docusaurus/docs/Flutter/guides/adding_localization.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx index 9eb4dd68..3a81187a 100644 --- a/docusaurus/docs/Flutter/guides/adding_localization.mdx +++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx @@ -26,7 +26,7 @@ At the moment we support the following languages: - [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) - [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) - [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) - +- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. ### Add dependency @@ -64,6 +64,7 @@ class MyApp extends StatelessWidget { Locale('fr'), Locale('it'), Locale('es'), + Locale('ja'), ], // Add GlobalStreamChatLocalizations.delegates localizationsDelegates: GlobalStreamChatLocalizations.delegates, @@ -133,6 +134,7 @@ Here is an example of how that would look like: Locale('fr'), Locale('it'), Locale('es'), + Locale('ja'), ], // locales are the locales of the device // supportedLocales are the app supported locales @@ -176,5 +178,6 @@ Example: fr it es + ja ``` From 95e3467ac49a19aea1e9cc3f8cf6af48e59f38cd Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 2 Aug 2021 16:50:57 -0400 Subject: [PATCH 11/99] support for korean --- .../lib/src/stream_chat_localizations.dart | 5 + .../lib/src/stream_chat_localizations_ko.dart | 360 ++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart index e65aab1f..4094dcaa 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations.dart @@ -13,6 +13,8 @@ part 'stream_chat_localizations_it.dart'; part 'stream_chat_localizations_ja.dart'; +part 'stream_chat_localizations_ko.dart'; + part 'stream_chat_localizations_hi.dart'; /// The set of supported languages, as language code strings. @@ -30,6 +32,7 @@ const kStreamChatSupportedLanguages = { 'it', 'es', 'ja', + 'ko' }; /// Creates a [GlobalStreamChatLocalizations] instance for the given `locale`. @@ -64,6 +67,8 @@ GlobalStreamChatLocalizations? getStreamChatTranslation(Locale locale) { return const StreamChatLocalizationsEs(); case 'ja': return const StreamChatLocalizationsJa(); + case 'ko': + return const StreamChatLocalizationsKo(); } } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart new file mode 100644 index 00000000..6fe285b7 --- /dev/null +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -0,0 +1,360 @@ +part of 'stream_chat_localizations.dart'; + +/// The translations for Korean (`ko`). +class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { + /// Create an instance of the translation bundle for Korean. + const StreamChatLocalizationsKo({String localeName = 'ko'}) + : super(localeName: localeName); + + @override + String get launchUrlError => 'URL을 시작할 수 없습니다.'; + + @override + String get loadingUsersError => '사용자를 로드하는 중 오류 발생'; + + @override + String get noUsersLabel => '현재 사용자가 없습니다.'; + + @override + String get retryLabel => '다시 시도하십시오.'; + + @override + String get userLastOnlineText => '마지막 온라인입니다.'; + + @override + String get userOnlineText => '온라인.'; + + @override + String userTypingText(Iterable users) { + if (users.isEmpty) return ''; + final first = users.first; + if (users.length == 1) { + return '${first.name} 타이핑하고 있어요.'; + } + return '${first.name}스와 ${users.length - 1}명이 타자를 치고 있습니다'; + } + + @override + String get threadReplyLabel => '스레드 응답입니다.'; + + @override + String get onlyVisibleToYouText => '당신만 볼 수 있습니다.'; + + @override + String threadReplyCountText(int count) => '$count스레드 응답입니다.'; + + @override + String attachmentsUploadProgressText({ + required int remaining, + required int total, + }) => + '${total}mb 중 ${remaining}mb를 업로드하는 중입니다...'; + + @override + String pinnedByUserText({ + required User pinnedBy, + required User currentUser, + }) { + final pinnedByCurrentUser = currentUser.id == pinnedBy.id; + if (pinnedByCurrentUser) return '당신에 의해 고정됩니다.'; + return '${pinnedBy.name} 핀으로 고정했습니다.'; + } + + @override + String get emptyMessagesText => '현재 메시지가 없습니다.'; + + @override + String get genericErrorText => '뭔가 잘못됐어요'; + + @override + String get loadingMessagesError => '메시지를 로드하는 동안 오류가 발생했습니다.'; + + @override + String resultCountText(int count) => '$count개 결과입니다.'; + + @override + String get messageDeletedText => '이 메시지는 삭제되었습니다.'; + + @override + String get messageDeletedLabel => '메시지가 삭제되었습니다.'; + + @override + String get messageReactionsLabel => '메시지에 대한 응답.'; + + @override + String get emptyChatMessagesText => '아직 채팅이 없습니다...'; + + @override + String threadSeparatorText(int replyCount) { + if (replyCount == 1) return '1 회신합니다.'; + return '$replyCount개의 응답입니다.'; + } + + @override + String get connectedLabel => '연결된'; + + @override + String get disconnectedLabel => '연결이 끊겼습니다.'; + + @override + String get reconnectingLabel => '다시 연결하는 중...'; + + @override + String get alsoSendAsDirectMessageLabel => '다이렉트 메시지로도 보냅니다.'; + + @override + String get addACommentOrSendLabel => '주석을 추가하거나 보냅니다.'; + + @override + String get searchGifLabel => 'GIF를 검색합니다.'; + + @override + String get writeAMessageLabel => '메시지를 쓰세요.'; + + @override + String get instantCommandsLabel => '인스턴트 커맨즈'; + + @override + String fileTooLargeAfterCompressionError(double limitInMB) => + '파일이 너무 커서 업로드할 수 없습니다. ' + '파일 크기 제한은 ${limitInMB}MB입니다. ' + '우리는 압축해 보았지만 충분하지 않았습니다.'; + + @override + String fileTooLargeError(double limitInMB) => + '파일이 너무 커서 업로드할 수 없습니다. 파일 크기 제한은 ${limitInMB}MB입니다.'; + + @override + String emojiMatchingQueryText(String query) => '"$query"과 일치하는 이모티콘입니다.'; + + @override + String get addAFileLabel => '파일을 추가합니다.'; + + @override + String get photoFromCameraLabel => '카메라에서 찍은 사진입니다.'; + + @override + String get uploadAFileLabel => '파일을 업로드합니다.'; + + @override + String get uploadAPhotoLabel => '사진을 업로드합니다.'; + + @override + String get uploadAVideoLabel => '비디오를 업로드하세요'; + + @override + String get videoFromCameraLabel => '카메라의 비디오입니다.'; + + @override + String get okLabel => '알았지'; + + @override + String get somethingWentWrongError => '뭔가 잘못됐어요'; + + @override + String get addMoreFilesLabel => '파일을 추가합니다.'; + + @override + String get enablePhotoAndVideoAccessMessage => '친구와 공유할 수 있도록 사진과' + '\n동영상에 액세스할 수 있도록 설정하십시오.'; + + @override + String get allowGalleryAccessMessage => '갤러리에 대한 액세스를 허용합니다.'; + + @override + String get flagMessageLabel => '플래그 메시지'; + + @override + String get flagMessageQuestion => '추가 조사를 위해 진행자에게 이 메시지의 복사본을 전송하시겠습니까?'; + + @override + String get flagLabel => '플래그를 지정합니다.'; + + @override + String get cancelLabel => '취소하십시오.'; + + @override + String get flagMessageSuccessfulLabel => '메시지에 플래그가 지정되었습니다.'; + + @override + String get flagMessageSuccessfulText => + '메시지가 진행자에게 보고되었습니다.'; + + @override + String get deleteLabel => '삭제합니다.'; + + @override + String get deleteMessageLabel => '메시지를 삭제합니다.'; + + @override + String get deleteMessageQuestion => + '이 메시지를 완전히 삭제하시겠습니까?'; + + @override + String get operationCouldNotBeCompletedText => + '작업을 완료할 수 없습니다.'; + + @override + String get replyLabel => '답글'; + + @override + String togglePinUnpinText({required bool pinned}) { + if (pinned) return '대화에서 연결을 해제합니다.'; + return '대화에 고정합니다.'; + } + + @override + String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed}) { + if (isDeleteFailed) return '메시지 삭제를 다시 시도하십시오.'; + return '메시지를 삭제합니다.'; + } + + @override + String get copyMessageLabel => '메시지를 복사합니다.'; + + @override + String get editMessageLabel => '메시지를 편집합니다.'; + + @override + String toggleResendOrResendEditedMessage({required bool isUpdateFailed}) { + if (isUpdateFailed) return '편집된 메시지를 다시 보냅니다.'; + return '다시 보냅니다.'; + } + + @override + String get photosLabel => '사진들'; + + String _getDay(DateTime dateTime) { + final now = DateTime.now(); + final today = DateTime(now.year, now.month, now.day); + final yesterday = DateTime(now.year, now.month, now.day - 1); + + final date = DateTime(dateTime.year, dateTime.month, dateTime.day); + + if (date == today) { + return '오늘이요'; + } else if (date == yesterday) { + return '어제요'; + } else { + return '${Jiffy(date).MMMd}입니다.'; + } + } + + @override + String sentAtText({required DateTime date, required DateTime time}) => + '${_getDay(date)} 오전 ${Jiffy(time.toLocal()).format('HH:mm')}에 보냈습니다'; + + @override + String get todayLabel => '오늘이요'; + + @override + String get yesterdayLabel => '어제요'; + + @override + String get channelIsMutedText => '채널이 음소거됩니다.'; + + @override + String get noTitleText => '제목이 없습니다.'; + + @override + String get letsStartChattingLabel => '채팅 시작해요!'; + + @override + String get sendingFirstMessageLabel => + '친구에게 당신의 첫 번째 메시지를 보내는 것은 어떤가요?'; + + @override + String get startAChatLabel => '대화를 시작합니다.'; + + @override + String get loadingChannelsError => '채널을 로드하는 동안 오류가 발생했습니다.'; + + @override + String get deleteConversationLabel => '대화를 삭제합니다.'; + + @override + String get deleteConversationQuestion => + '이 대화를 삭제하시겠습니까?'; + + @override + String get streamChatLabel => '채팅을 스트리밍합니다.'; + + @override + String get searchingForNetworkText => '네트워크를 검색하는 중입니다.'; + + @override + String get offlineLabel => '오프라인...'; + + @override + String get tryAgainLabel => '다시 한 번 해 봐!'; + + @override + String membersCountText(int count) { + if (count == 1) return '회원 1명입니다.'; + return '$count 구성원'; + } + + @override + String watchersCountText(int count) { + if (count == 1) return '1 온라인입니다.'; + return '$count 온라인입니다'; + } + + @override + String get viewInfoLabel => '정보를 봅니다.'; + + @override + String get leaveGroupLabel => '그룹을 떠납니다.'; + + @override + String get leaveLabel => '떠나요'; + + @override + String get leaveConversationLabel => '대화에서 떠납니다.'; + + @override + String get leaveConversationQuestion => + '정말 이 대화에서 나가시겠습니까?'; + + @override + String get showInChatLabel => '채팅에 표시합니다.'; + + @override + String get saveImageLabel => '이미지를 저장합니다.'; + + @override + String get saveVideoLabel => '비디오를 저장합니다.'; + + @override + String get uploadErrorLabel => '업로드 오류입니다.'; + + @override + String get giphyLabel => '지피요'; + + @override + String get shuffleLabel => '섞으세요'; + + @override + String get sendLabel => '보냅니다'; + + @override + String get withText => '함께요'; + + @override + String get inText => '에 있습니다.'; + + @override + String get youText => '너'; + + @override + String galleryPaginationText( + {required int currentPage, required int totalPages}) => + '$totalPages장 ${currentPage + 1}장입니다'; + //11장 3장. + + @override + String get fileText => '파일'; + + @override + String get replyToMessageLabel => '메시지에 회신합니다.'; +} From bd8e4675c66595c0187ae2cf763166fbaf115588 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Wed, 4 Aug 2021 09:06:56 -0400 Subject: [PATCH 12/99] update korean based on Eric's review --- .../lib/src/stream_chat_localizations_ko.dart | 158 +++++++++--------- 1 file changed, 75 insertions(+), 83 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index 6fe285b7..689544c7 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -7,48 +7,48 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { : super(localeName: localeName); @override - String get launchUrlError => 'URL을 시작할 수 없습니다.'; + String get launchUrlError => 'URL을 시작할 수 없습니다'; @override String get loadingUsersError => '사용자를 로드하는 중 오류 발생'; @override - String get noUsersLabel => '현재 사용자가 없습니다.'; + String get noUsersLabel => '현재 사용자가 없습니다'; @override - String get retryLabel => '다시 시도하십시오.'; + String get retryLabel => '다시 시도하십시오'; @override - String get userLastOnlineText => '마지막 온라인입니다.'; + String get userLastOnlineText => '마지막 온라인입니다'; @override - String get userOnlineText => '온라인.'; + String get userOnlineText => '온라인'; @override String userTypingText(Iterable users) { if (users.isEmpty) return ''; final first = users.first; if (users.length == 1) { - return '${first.name} 타이핑하고 있어요.'; + return '${first.name} 타이핑중'; } - return '${first.name}스와 ${users.length - 1}명이 타자를 치고 있습니다'; + return '${first.name}하고 ${users.length - 1}명 타이핑중'; } @override - String get threadReplyLabel => '스레드 응답입니다.'; + String get threadReplyLabel => '스레드 응답입니다'; @override - String get onlyVisibleToYouText => '당신만 볼 수 있습니다.'; + String get onlyVisibleToYouText => '당신만 볼 수 있습니다'; @override - String threadReplyCountText(int count) => '$count스레드 응답입니다.'; + String threadReplyCountText(int count) => '$count스레드 답장'; @override String attachmentsUploadProgressText({ required int remaining, required int total, }) => - '${total}mb 중 ${remaining}mb를 업로드하는 중입니다...'; + '$remaining/${total}mb를 업로드중...'; @override String pinnedByUserText({ @@ -56,60 +56,59 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { required User currentUser, }) { final pinnedByCurrentUser = currentUser.id == pinnedBy.id; - if (pinnedByCurrentUser) return '당신에 의해 고정됩니다.'; - return '${pinnedBy.name} 핀으로 고정했습니다.'; + if (pinnedByCurrentUser) return '당신의 핀'; + return '${pinnedBy.name}의 핀'; } @override - String get emptyMessagesText => '현재 메시지가 없습니다.'; + String get emptyMessagesText => '현재 메시지가 없습니다'; @override - String get genericErrorText => '뭔가 잘못됐어요'; + String get genericErrorText => '뭔가 잘못됐습니다'; @override - String get loadingMessagesError => '메시지를 로드하는 동안 오류가 발생했습니다.'; + String get loadingMessagesError => '메시지를 로드하는 동안 오류가 발생했습니다'; @override - String resultCountText(int count) => '$count개 결과입니다.'; + String resultCountText(int count) => '$count개의 결과'; @override String get messageDeletedText => '이 메시지는 삭제되었습니다.'; @override - String get messageDeletedLabel => '메시지가 삭제되었습니다.'; + String get messageDeletedLabel => '메시지가 삭제되었습니다'; @override - String get messageReactionsLabel => '메시지에 대한 응답.'; + String get messageReactionsLabel => '메시지에 대한 응답'; @override String get emptyChatMessagesText => '아직 채팅이 없습니다...'; @override String threadSeparatorText(int replyCount) { - if (replyCount == 1) return '1 회신합니다.'; - return '$replyCount개의 응답입니다.'; + return '$replyCount개의 답장'; } @override - String get connectedLabel => '연결된'; + String get connectedLabel => '연결중'; @override - String get disconnectedLabel => '연결이 끊겼습니다.'; + String get disconnectedLabel => '연결이 끊겼습니다'; @override String get reconnectingLabel => '다시 연결하는 중...'; @override - String get alsoSendAsDirectMessageLabel => '다이렉트 메시지로도 보냅니다.'; + String get alsoSendAsDirectMessageLabel => '다이렉트 메시지로도 보냅니다'; @override - String get addACommentOrSendLabel => '주석을 추가하거나 보냅니다.'; + String get addACommentOrSendLabel => '주석을 추가하거나 보냅니다'; @override - String get searchGifLabel => 'GIF를 검색합니다.'; + String get searchGifLabel => 'GIF 검색'; @override - String get writeAMessageLabel => '메시지를 쓰세요.'; + String get writeAMessageLabel => '메시지 쓰기'; @override String get instantCommandsLabel => '인스턴트 커맨즈'; @@ -125,88 +124,85 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { '파일이 너무 커서 업로드할 수 없습니다. 파일 크기 제한은 ${limitInMB}MB입니다.'; @override - String emojiMatchingQueryText(String query) => '"$query"과 일치하는 이모티콘입니다.'; + String emojiMatchingQueryText(String query) => '"$query"과 일치하는 이모티콘입니다'; @override - String get addAFileLabel => '파일을 추가합니다.'; + String get addAFileLabel => '파일을 추가함'; @override - String get photoFromCameraLabel => '카메라에서 찍은 사진입니다.'; + String get photoFromCameraLabel => '카메라에서 찍은 사진'; @override - String get uploadAFileLabel => '파일을 업로드합니다.'; + String get uploadAFileLabel => '파일을 업로드함'; @override - String get uploadAPhotoLabel => '사진을 업로드합니다.'; + String get uploadAPhotoLabel => '사진을 업로드함'; @override - String get uploadAVideoLabel => '비디오를 업로드하세요'; + String get uploadAVideoLabel => '비디오를 업로드함'; @override - String get videoFromCameraLabel => '카메라의 비디오입니다.'; + String get videoFromCameraLabel => '카메라의 비디오.'; @override - String get okLabel => '알았지'; + String get okLabel => 'ㅇㅋ'; @override - String get somethingWentWrongError => '뭔가 잘못됐어요'; + String get somethingWentWrongError => '뭔가 잘못됐습느다'; @override - String get addMoreFilesLabel => '파일을 추가합니다.'; + String get addMoreFilesLabel => '파일을 추가함'; @override String get enablePhotoAndVideoAccessMessage => '친구와 공유할 수 있도록 사진과' '\n동영상에 액세스할 수 있도록 설정하십시오.'; @override - String get allowGalleryAccessMessage => '갤러리에 대한 액세스를 허용합니다.'; + String get allowGalleryAccessMessage => '갤러리에 대한 액세스를 허용합니다'; @override - String get flagMessageLabel => '플래그 메시지'; + String get flagMessageLabel => ' 메시지를 플래그함'; @override String get flagMessageQuestion => '추가 조사를 위해 진행자에게 이 메시지의 복사본을 전송하시겠습니까?'; @override - String get flagLabel => '플래그를 지정합니다.'; + String get flagLabel => '플래그함'; @override - String get cancelLabel => '취소하십시오.'; + String get cancelLabel => '취소'; @override - String get flagMessageSuccessfulLabel => '메시지에 플래그가 지정되었습니다.'; + String get flagMessageSuccessfulLabel => '메시지에 플래그가 지정되었습니다'; @override - String get flagMessageSuccessfulText => - '메시지가 진행자에게 보고되었습니다.'; + String get flagMessageSuccessfulText => '메시지가 진행자에게 보고되었습니다.'; @override - String get deleteLabel => '삭제합니다.'; + String get deleteLabel => '삭제'; @override String get deleteMessageLabel => '메시지를 삭제합니다.'; @override - String get deleteMessageQuestion => - '이 메시지를 완전히 삭제하시겠습니까?'; + String get deleteMessageQuestion => '이 메시지를 완전히 삭제하시겠습니까?'; @override - String get operationCouldNotBeCompletedText => - '작업을 완료할 수 없습니다.'; + String get operationCouldNotBeCompletedText => '작업을 완료할 수 없습니다.'; @override String get replyLabel => '답글'; @override String togglePinUnpinText({required bool pinned}) { - if (pinned) return '대화에서 연결을 해제합니다.'; - return '대화에 고정합니다.'; + if (pinned) return '대화의 핀을 분리합니다'; + return '대화에 고정합니다'; } @override String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed}) { - if (isDeleteFailed) return '메시지 삭제를 다시 시도하십시오.'; - return '메시지를 삭제합니다.'; + if (isDeleteFailed) return '메시지 삭제를 다시 시도합니다'; + return '메시지를 삭제합니다'; } @override @@ -222,7 +218,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { } @override - String get photosLabel => '사진들'; + String get photosLabel => '사진'; String _getDay(DateTime dateTime) { final now = DateTime.now(); @@ -232,23 +228,23 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { final date = DateTime(dateTime.year, dateTime.month, dateTime.day); if (date == today) { - return '오늘이요'; + return '오늘'; } else if (date == yesterday) { - return '어제요'; + return '어제'; } else { - return '${Jiffy(date).MMMd}입니다.'; + return '${Jiffy(date).MMMd}에'; } } @override String sentAtText({required DateTime date, required DateTime time}) => - '${_getDay(date)} 오전 ${Jiffy(time.toLocal()).format('HH:mm')}에 보냈습니다'; + '${_getDay(date)} ${Jiffy(time.toLocal()).format('HH:mm')}에 보냈습니다'; @override - String get todayLabel => '오늘이요'; + String get todayLabel => '오늘'; @override - String get yesterdayLabel => '어제요'; + String get yesterdayLabel => '어제'; @override String get channelIsMutedText => '채널이 음소거됩니다.'; @@ -260,8 +256,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get letsStartChattingLabel => '채팅 시작해요!'; @override - String get sendingFirstMessageLabel => - '친구에게 당신의 첫 번째 메시지를 보내는 것은 어떤가요?'; + String get sendingFirstMessageLabel => '친구에게 첫 메시지를 보내 볼까요?'; @override String get startAChatLabel => '대화를 시작합니다.'; @@ -273,11 +268,10 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get deleteConversationLabel => '대화를 삭제합니다.'; @override - String get deleteConversationQuestion => - '이 대화를 삭제하시겠습니까?'; + String get deleteConversationQuestion => '대화를 삭제하시겠습니까?'; @override - String get streamChatLabel => '채팅을 스트리밍합니다.'; + String get streamChatLabel => '스트림 채팅'; @override String get searchingForNetworkText => '네트워크를 검색하는 중입니다.'; @@ -286,35 +280,32 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get offlineLabel => '오프라인...'; @override - String get tryAgainLabel => '다시 한 번 해 봐!'; + String get tryAgainLabel => '다시 시도합니다'; @override String membersCountText(int count) { - if (count == 1) return '회원 1명입니다.'; - return '$count 구성원'; + return '$count명'; } @override String watchersCountText(int count) { - if (count == 1) return '1 온라인입니다.'; - return '$count 온라인입니다'; + return '$count명이 온라인'; } @override - String get viewInfoLabel => '정보를 봅니다.'; + String get viewInfoLabel => '정보를 보기'; @override String get leaveGroupLabel => '그룹을 떠납니다.'; @override - String get leaveLabel => '떠나요'; + String get leaveLabel => '떠나다'; @override String get leaveConversationLabel => '대화에서 떠납니다.'; @override - String get leaveConversationQuestion => - '정말 이 대화에서 나가시겠습니까?'; + String get leaveConversationQuestion => '정말 이 대화에서 나가시겠습니까?'; @override String get showInChatLabel => '채팅에 표시합니다.'; @@ -326,31 +317,32 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get saveVideoLabel => '비디오를 저장합니다.'; @override - String get uploadErrorLabel => '업로드 오류입니다.'; + String get uploadErrorLabel => '업로드 오류'; @override - String get giphyLabel => '지피요'; + String get giphyLabel => '지피'; @override - String get shuffleLabel => '섞으세요'; + String get shuffleLabel => '섞기'; @override - String get sendLabel => '보냅니다'; + String get sendLabel => '보내기'; @override - String get withText => '함께요'; + String get withText => '함께'; @override - String get inText => '에 있습니다.'; + String get inText => '에'; @override - String get youText => '너'; + String get youText => '고객님'; + // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude @override String galleryPaginationText( {required int currentPage, required int totalPages}) => - '$totalPages장 ${currentPage + 1}장입니다'; - //11장 3장. + '${currentPage + 1} / $totalPages'; + //3 / 11 @override String get fileText => '파일'; From f311c13e4bc621b5e5a5b973861fb1be019d1c18 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Wed, 4 Aug 2021 09:20:28 -0400 Subject: [PATCH 13/99] update japanese based on Eric's input --- .../lib/src/stream_chat_localizations_ja.dart | 103 +++++++++--------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index 6522fbf7..a30bfe2f 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -1,16 +1,16 @@ part of 'stream_chat_localizations.dart'; -/// The translations for English (`ja`). +/// The translations for Japanese (`ja`). class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { /// Create an instance of the translation bundle for Japanese. const StreamChatLocalizationsJa({String localeName = 'ja'}) : super(localeName: localeName); @override - String get launchUrlError => 'ユーアーレルの起動ができない'; + String get launchUrlError => 'URLの起動ができません'; @override - String get loadingUsersError => 'ユーザーの読み込みエラー'; + String get loadingUsersError => 'ユーザーの読み込みができません'; @override String get noUsersLabel => '現在、ユーザーはいません。'; @@ -29,26 +29,26 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { if (users.isEmpty) return ''; final first = users.first; if (users.length == 1) { - return '${first.name}がタイプしている'; + return '${first.name}が入力しています'; } - return '${first.name}とあと${users.length - 1}人が入力しています'; + return '${first.name}と${users.length - 1}人が入力しています'; } @override String get threadReplyLabel => 'スレッド返信'; @override - String get onlyVisibleToYouText => '自分にしか見えない'; + String get onlyVisibleToYouText => '自分しか見れません'; @override - String threadReplyCountText(int count) => '$countスレッドの返信'; + String threadReplyCountText(int count) => '$countつのスレッド返信'; @override String attachmentsUploadProgressText({ required int remaining, required int total, }) => - '$remaining/${total}mbのアップロード 。。。'; + '$remaining/${total}mbのアップロード中 。。。'; @override String pinnedByUserText({ @@ -56,21 +56,21 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { required User currentUser, }) { final pinnedByCurrentUser = currentUser.id == pinnedBy.id; - if (pinnedByCurrentUser) return 'あなたのピン留'; - return '${pinnedBy.name}のピン留'; + if (pinnedByCurrentUser) return 'あなたのピン'; + return '${pinnedBy.name}のピン'; } @override String get emptyMessagesText => '現在、メッセージはありません。'; @override - String get genericErrorText => '何かが間違っていた'; + String get genericErrorText => 'エラーが発生しました'; @override String get loadingMessagesError => 'メッセージの読み込みエラー'; @override - String resultCountText(int count) => '$countつの結果'; + String resultCountText(int count) => '$count件の結果'; @override String get messageDeletedText => 'このメッセージは削除されました。'; @@ -79,34 +79,32 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get messageDeletedLabel => 'メッセージ削除'; @override - String get messageReactionsLabel => 'メッセージに対する反応'; + String get messageReactionsLabel => 'メッセージのリアクション'; @override - String get emptyChatMessagesText => 'ここではまだ会話はありませんが。。。'; + String get emptyChatMessagesText => 'チャットがありませんが。。。'; @override - String threadSeparatorText(int replyCount) { - if (replyCount == 1) return '1 回答'; - return '$replyCount件の返信'; - } + String threadSeparatorText(int replyCount)=> '$replyCount件の返信'; + @override - String get connectedLabel => 'コネクテッド'; + String get connectedLabel => '接続しています'; @override String get disconnectedLabel => '接続切れ'; @override - String get reconnectingLabel => 'リコネクティング。。。'; + String get reconnectingLabel => '再接続中。。。'; @override - String get alsoSendAsDirectMessageLabel => 'ダイレクトメッセージでも送信可能'; + String get alsoSendAsDirectMessageLabel => 'ダイレクトメッセージでも送信'; @override String get addACommentOrSendLabel => 'コメントの追加や送信'; @override - String get searchGifLabel => '検索用GIF'; + String get searchGifLabel => 'GIFの検索'; @override String get writeAMessageLabel => 'メッセージを書く'; @@ -149,7 +147,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get okLabel => 'よし'; @override - String get somethingWentWrongError => '何かが間違っていたのだ。'; + String get somethingWentWrongError => 'エラーが発生しました'; @override String get addMoreFilesLabel => 'ファイルの追加'; @@ -158,29 +156,29 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get enablePhotoAndVideoAccessMessage => 'お友達と共有できるように、写真' '\nやビデオへのアクセスを有効にしてください。'; @override - String get allowGalleryAccessMessage => 'お客様のギャラリーへのアクセスを許可する'; + String get allowGalleryAccessMessage => 'ギャラリーへのアクセスを許可する'; @override - String get flagMessageLabel => 'メッセージフラグが'; + String get flagMessageLabel => 'メッセージをフラグする'; @override String get flagMessageQuestion => 'このメッセージのコピーを' '\nモデレーターに送って、さらに調査してもらいますか?'; @override - String get flagLabel => 'フラグが'; + String get flagLabel => 'フラグする'; @override String get cancelLabel => 'キャンセル'; @override - String get flagMessageSuccessfulLabel => 'フラグ付メッセージ'; + String get flagMessageSuccessfulLabel => 'メッセージにフラグが付けられました'; @override String get flagMessageSuccessfulText => 'このメッセージはモデレーターに報告されました。'; @override - String get deleteLabel => '消す'; + String get deleteLabel => '削除'; @override String get deleteMessageLabel => 'メッセージを削除する '; @@ -197,25 +195,25 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String togglePinUnpinText({required bool pinned}) { - if (pinned) return 'カンバセーションからピンを外す '; - return '会話へのピン'; + if (pinned) return '会話のピンを外す'; + return '会話にピンする'; } @override String toggleDeleteRetryDeleteMessageText({required bool isDeleteFailed}) { - if (isDeleteFailed) return 'メッセージの削除を再試行してください'; + if (isDeleteFailed) return 'メッセージの削除を再試行する'; return 'メッセージを削除する'; } @override - String get copyMessageLabel => 'コピーメッセージ'; + String get copyMessageLabel => 'メッセージをコピーする'; @override - String get editMessageLabel => 'メッセージの編集'; + String get editMessageLabel => 'メッセージを編集する'; @override String toggleResendOrResendEditedMessage({required bool isUpdateFailed}) { - if (isUpdateFailed) return '編集したメッセージの再送'; + if (isUpdateFailed) return '編集したメッセージを再送する'; return '再送'; } @@ -240,7 +238,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String sentAtText({required DateTime date, required DateTime time}) => - '${_getDay(date)} at ${Jiffy(time.toLocal()).format('HH:mm')}に送信 '; + '${_getDay(date)}の${Jiffy(time.toLocal()).format('HH:mm')}に送信しました '; @override String get todayLabel => '今日'; @@ -249,16 +247,16 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get yesterdayLabel => '昨日'; @override - String get channelIsMutedText => 'チャンネルがミュートされています'; + String get channelIsMutedText => 'チャンネルが無音されています'; @override String get noTitleText => 'タイトル無し'; @override - String get letsStartChattingLabel => 'さあ、チャットを始めよう'; + String get letsStartChattingLabel => 'チャットを始めよう!'; @override - String get sendingFirstMessageLabel => 'どのように友人にあなたの最初のメッセージを送ることについてはどうですか?'; + String get sendingFirstMessageLabel => '友人に最初のメッセージを送りましょうか?'; @override String get startAChatLabel => 'チャットを開始する'; @@ -270,13 +268,13 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get deleteConversationLabel => '会話を削除する'; @override - String get deleteConversationQuestion => 'この会話を削除してもよろしいですか?'; + String get deleteConversationQuestion => '本当に会話を削除しますか?'; @override String get streamChatLabel => 'ストリームチャット'; @override - String get searchingForNetworkText => 'ネットワークの検索'; + String get searchingForNetworkText => 'ネットワークを検索中'; @override String get offlineLabel => 'オフライン。。。'; @@ -285,16 +283,10 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get tryAgainLabel => '再試行する'; @override - String membersCountText(int count) { - if (count == 1) return '1人のメンバー'; - return '$count人のメンバー'; - } + String membersCountText(int count) => '$count人のメンバー'; @override - String watchersCountText(int count) { - if (count == 1) return '1オンライン'; - return '$countオンライン'; - } + String watchersCountText(int count) => '$count人がオンライン'; @override String get viewInfoLabel => '情報を見る'; @@ -309,7 +301,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get leaveConversationLabel => '会話を離れる'; @override - String get leaveConversationQuestion => 'この会話を離れてもよろしいですか?'; + String get leaveConversationQuestion => '本当に会話を離れますか?'; @override String get showInChatLabel => 'チャットで表示'; @@ -336,15 +328,18 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get withText => 'と'; @override - String get inText => 'は'; + String get inText => 'に'; @override - String get youText => '君'; + String get youText => 'お客様'; + // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude @override - String galleryPaginationText( - {required int currentPage, required int totalPages}) => - '$totalPagesの${currentPage + 1}'; + String galleryPaginationText({ + required int currentPage, + required int totalPages, + }) => + '${currentPage + 1} / $totalPages'; @override String get fileText => 'ファイル'; From 74f3e109fd02615d55dda0abd80c092db70a85a0 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Wed, 4 Aug 2021 09:59:29 -0400 Subject: [PATCH 14/99] =?UTF-8?q?update=20okLabel:=20=E3=85=87=E3=85=8B->?= =?UTF-8?q?=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/stream_chat_localizations_ko.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index 689544c7..36c578e3 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -145,7 +145,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get videoFromCameraLabel => '카메라의 비디오.'; @override - String get okLabel => 'ㅇㅋ'; + String get okLabel => '확인'; @override String get somethingWentWrongError => '뭔가 잘못됐습느다'; From 1c3927101513e9012ffb6429aeab0ecb0f2439f9 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Wed, 4 Aug 2021 17:30:56 +0200 Subject: [PATCH 15/99] docs: fix links, grammar --- .../docs/Flutter/basics/introduction.mdx | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docusaurus/docs/Flutter/basics/introduction.mdx b/docusaurus/docs/Flutter/basics/introduction.mdx index 756bd33f..ad1df5af 100644 --- a/docusaurus/docs/Flutter/basics/introduction.mdx +++ b/docusaurus/docs/Flutter/basics/introduction.mdx @@ -8,13 +8,14 @@ Exploring The Basics Of Stream Chat ![](../assets/sdk_title.png) -Stream Chat is a service that helps you easily build a full chat experience in your Flutter (and more) apps. +Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps. +We also support a variety of other SDKs. This section of the documentation focuses on our Flutter SDK which helps you easily -ship high quality messaging experiences in apps and programs built with the [Flutter toolkit made +ship high quality messaging experiences in apps and programs built with the [Flutter toolkit by Google](https://flutter.dev). -The Stream Chat Flutter SDK comprises of four different packages to choose from ranging from ones +The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones giving you complete control to ones that give you a rich out-of-the-box chat experience. The packages that make up the Stream Chat SDK are: @@ -30,28 +31,28 @@ reusable and customisable UI components. saving chat data locally. 5. Localizations (stream_chat_localizations): provides a set of localizations for the SDK. -We recommend building prototypes using the full UI package since it contains UI widgets already -integrated with Stream's API. [stream_chat_flutter](https://pub.dev/packages/stream_chat_flutter) -is the fastest way to get up and running using Stream chat in your app. +We recommend building prototypes using the full UI package, [stream_chat_flutter](https://pub.dev/packages/stream_chat_flutter), +since it contains UI widgets already integrated with Stream's API. Is the fastest way to get up +and running using Stream chat in your app. The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web and Desktop. If you're building a very custom UI and would prefer a more lean package, -our [core package](https://pub.dev/packages/stream_chat_flutter) will be suited to this use case. Core allows you to build custom, -expressive UIs while retaining the benefits of our full Flutter SDK. -APIs for accessing and controlling users, sending messages, etc are seamlessly integrated into -this package and accessible via providers and builders. +[stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this +use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full +Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated +into this package and accessible via providers and builders. Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured. ### Basic Structure -There are two core elements in chat, Users and Channels. +There are two core elements in chat, Users and Channels. Channels are groups of one or more users that can message each other. In an app, you need to have a user connected to query channels. -There is no specific distinction between a chat between two people and a group chat, +There is no specific distinction between a chat with only two people and a group chat, but there is a way to create a unique chat between a certain number of people by creating a distinct channel. ![](../assets/chat_basics.png) @@ -68,7 +69,7 @@ While this is a simplistic overview of the service, the Flutter SDK handles the Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/), it is a nice way to learn how the API works. -It's in-browser so Javascript-based but the ideas are pretty much the same as Dart. +It's in-browser so you'll need to use Javascript but the core conceps are pretty much the same as Dart. You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/) which focuses on using the UI package to get Stream Chat integrated into a Flutter app. From 3cddec630122dfe89fea816b604f6d4a31bab8ce Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Wed, 4 Aug 2021 17:34:34 +0200 Subject: [PATCH 16/99] docs: mention localization --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0faad799..3bb5a923 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,6 +52,8 @@ Stream's Flutter code is kept in a single mono-repository consisting of multiple `stream_chat_persistence` - This package provides a persistence client for fetching and saving chat data locally. Stream Chat Persistence uses Moor as a disk cache. +`stream_chat_localizations` - This package provides a set of localizations for the SDK. + ### Local Setup Congratulations! 🎉. You've successfully cloned our repo, and you are ready to make your first contribution. Before you can start making code changes, there are a few things to configure. From 3ef2c4027c2189fd3f5cad3a0349e029e853b648 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Wed, 4 Aug 2021 17:55:56 +0200 Subject: [PATCH 17/99] docs: grammar fixes --- docusaurus/docs/Flutter/basics/introduction.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/Flutter/basics/introduction.mdx b/docusaurus/docs/Flutter/basics/introduction.mdx index ad1df5af..99170774 100644 --- a/docusaurus/docs/Flutter/basics/introduction.mdx +++ b/docusaurus/docs/Flutter/basics/introduction.mdx @@ -13,7 +13,7 @@ We also support a variety of other SDKs. This section of the documentation focuses on our Flutter SDK which helps you easily ship high quality messaging experiences in apps and programs built with the [Flutter toolkit -by Google](https://flutter.dev). +made by Google](https://flutter.dev). The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones giving you complete control to ones that give you a rich out-of-the-box chat experience. @@ -32,7 +32,7 @@ saving chat data locally. 5. Localizations (stream_chat_localizations): provides a set of localizations for the SDK. We recommend building prototypes using the full UI package, [stream_chat_flutter](https://pub.dev/packages/stream_chat_flutter), -since it contains UI widgets already integrated with Stream's API. Is the fastest way to get up +since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up and running using Stream chat in your app. The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web From e1d97feaabb50b51edd87c1b468cceb8c41563af Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Wed, 4 Aug 2021 16:33:52 -0400 Subject: [PATCH 18/99] add korean to tranlsation docs --- docusaurus/docs/Flutter/guides/adding_localization.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx index 3a81187a..5a8813c2 100644 --- a/docusaurus/docs/Flutter/guides/adding_localization.mdx +++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx @@ -27,6 +27,7 @@ At the moment we support the following languages: - [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) - [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) - [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) +- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. ### Add dependency @@ -65,6 +66,7 @@ class MyApp extends StatelessWidget { Locale('it'), Locale('es'), Locale('ja'), + Locale('ko'), ], // Add GlobalStreamChatLocalizations.delegates localizationsDelegates: GlobalStreamChatLocalizations.delegates, @@ -135,6 +137,7 @@ Here is an example of how that would look like: Locale('it'), Locale('es'), Locale('ja'), + Locale('ko'), ], // locales are the locales of the device // supportedLocales are the app supported locales @@ -179,5 +182,6 @@ Example: it es ja + ko ``` From 2b57076a32ddd7ac4a2ea9d65f0c43d045f25e98 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 5 Aug 2021 15:11:12 +0530 Subject: [PATCH 19/99] added new guide --- .../guides/adding_local_data_persistence.mdx | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx diff --git a/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx new file mode 100644 index 00000000..76e84524 --- /dev/null +++ b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx @@ -0,0 +1,76 @@ +--- +id: adding_local_data_persistence +sidebar_position: 9 +title: Adding Local Data Persistence +--- + +Adding Local Data Persistence + +### Introduction + +Most messaging apps need to work regardless of whether the app is currently connected to the internet. +Local data persistence stores the fetched data from the backend on a local SQLite database using the +moor package in Flutter. All packages in the SDK can use local data persistence to store messages +across multiple platforms. + +### Implementation + +To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient. + +```dart +class CustomChatPersistentClient extends ChatPersistenceClient { +... +} + +final client = StreamChatClient( + apiKey ?? kDefaultStreamApiKey, + logLevel: Level.INFO, +)..chatPersistenceClient = CustomChatPersistentClient(); +``` + +We provide an official persistent client in the [stream_chat_persistence](https://pub.dev/packages/stream_chat_persistence) +package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM. + +Add this to your package's `pubspec.yaml` file, using the latest version. + +```yaml +dependencies: + stream_chat_persistence: ^latest_version +``` + +You should then run `flutter packages get` + +The usage is pretty simple. + +1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode` + +```dart +final chatPersistentClient = StreamChatPersistenceClient( + logLevel: Level.INFO, + connectionMode: ConnectionMode.background, +); +``` + +2. Pass the instance to the official `StreamChatClient` + +```dart + final client = StreamChatClient( + apiKey ?? kDefaultStreamApiKey, + logLevel: Level.INFO, + )..chatPersistenceClient = chatPersistentClient; +``` + +And you are ready to go... + +Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread. +The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest +information every time it receives new data about channels/messages/users. + +### Multi-user + +The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. +Calling `client.disconnect(flushOfflineStorage: true)` flushes all current database data. + +### Updating/deleting/sending a message while offline + +The information about the action is saved in offline storage. When the client returns online, everything is retried. \ No newline at end of file From 291d33434da1981c6ec021a70afb5ee217898a43 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 5 Aug 2021 15:15:03 +0530 Subject: [PATCH 20/99] Update docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx Co-authored-by: Sahil Kumar --- .../docs/Flutter/guides/adding_local_data_persistence.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx index 76e84524..e6283ca0 100644 --- a/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx +++ b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx @@ -69,8 +69,8 @@ information every time it receives new data about channels/messages/users. ### Multi-user The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database. -Calling `client.disconnect(flushOfflineStorage: true)` flushes all current database data. +Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data. ### Updating/deleting/sending a message while offline -The information about the action is saved in offline storage. When the client returns online, everything is retried. \ No newline at end of file +The information about the action is saved in offline storage. When the client returns online, everything is retried. From 57e9552248230c16291989f4509e074bc33afd61 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Thu, 5 Aug 2021 13:36:15 -0400 Subject: [PATCH 21/99] updating youText in ja + ko based on Eric's input --- .../lib/src/stream_chat_localizations_ja.dart | 2 +- .../lib/src/stream_chat_localizations_ko.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index a30bfe2f..e8d9759e 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -331,7 +331,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get inText => 'に'; @override - String get youText => 'お客様'; + String get youText => 'あなた'; // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude @override diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index 36c578e3..dbd9609d 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -335,7 +335,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get inText => '에'; @override - String get youText => '고객님'; + String get youText => '당신'; // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude @override From 2c0eaaafab89179e2f8ed94468672cfa1876310e Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Sun, 8 Aug 2021 22:27:40 +0530 Subject: [PATCH 22/99] added new guide --- .../docs/Flutter/guides/understanding_filters.mdx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docusaurus/docs/Flutter/guides/understanding_filters.mdx diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx new file mode 100644 index 00000000..47d72e1f --- /dev/null +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -0,0 +1,15 @@ +--- +id: understanding_filters +sidebar_position: 10 +title: Understanding Filters +--- + +Understanding Filters + +### Introduction + +Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which +fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe +filters. This guide aims to explain the different types of filters and how to use them. + + From ff4baabcad05c9b75deae446fef636e24b731673 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 9 Aug 2021 16:38:02 +0530 Subject: [PATCH 23/99] added guides --- .../Flutter/guides/understanding_filters.mdx | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx index 47d72e1f..8a6fc925 100644 --- a/docusaurus/docs/Flutter/guides/understanding_filters.mdx +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -12,4 +12,132 @@ Filters are used to get a specific subset of objects (channels, users, messages, fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe filters. This guide aims to explain the different types of filters and how to use them. +### Types Of Filters +#### Filter.equal + +The 'equal' filter gets the objects where the given key has the specified value. + +```dart +Filter.equal('type', 'messaging'), +``` + +#### Filter.notEqual + +The 'notEqual' filter gets the objects where the given key does not have the specified value. + +```dart +Filter.notEqual('type', 'messaging'), +``` + +#### Filter.greater + +The 'greater' filter gets the objects where the given key has a higher value than the specified value. + +```dart +Filter.greater('count', 5), +``` + +#### Filter.greaterOrEqual + +The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value. + +```dart +Filter.greaterOrEqual('count', 5), +``` + +#### Filter.less + +The 'less' filter gets the objects where the given key has a lesser value than the specified value. + +```dart +Filter.less('count', 5), +``` + +#### Filter.lessOrEqual + +The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value. + +```dart +Filter.lessOrEqual('count', 5), +``` + +#### Filter.in_ + +The 'in_' filter allows getting objects where the key matches any in a specified array. + +```dart +Filter.in_('members', [user.id]) +``` + +:::note +Since 'in' is a keyword in Dart, the filter has an underscore added. This does not apply to the 'notIn' +keyword. +::: + +#### Filter.notIn + +The 'notIn' filter allows getting objects where the key matches none in a specified array. + +```dart +Filter.notIn('members', [user.id]) +``` + +#### Filter.query + +Matches values by performing text search with the specified value. + +```dart +Filter.query('name', 'demo') +``` + +#### Filter.autoComplete + +Matches values with the specified prefix. + +```dart +Filter.autoComplete('name', 'demo') +``` + +#### Filter.exists + +Matches values that exist/don't exist based on the specified boolean value. + +```dart +Filter.exists('name', true) +``` + +### Group Queries + +#### FilterOperator.and + +The 'and' operator combines multiple queries. + +```dart +final filter = Filter.and([ + Filter.equal('type', 'messaging'), + Filter.in_('members', [user.id]) +]) +``` + +#### FilterOperator.or + +Combines the provided filters and matches the values matched by at least one of the filters. + +```dart +final filter = Filter.or([ + Filter.in_('bannedUsers', [user.id]), + Filter.in_('shadowBannedUsers', [user.id]) +]) +``` + +#### FilterOperator.nor + +Combines the provided filters and matches the values not matched by all the filters. + +```dart +final filter = Filter.nor([ + Filter.in_('bannedUsers', [user.id]), + Filter.in_('shadowBannedUsers', [user.id]) +]) +``` From f8a6539d09fb364f345f88750d95a45a2cb2ab7e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 9 Aug 2021 16:48:23 +0530 Subject: [PATCH 24/99] feat(ui): add support for `attachmentButtonBuilder`, `commandButtonBuilder` in `MessageInput` Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 144 +++++++++++------- .../lib/src/extension.dart | 51 ++++++- .../lib/src/message_input.dart | 104 ++++++++----- .../lib/stream_chat_flutter.dart | 1 + 4 files changed, 198 insertions(+), 102 deletions(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 5289ec30..341d481b 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -2,21 +2,35 @@ ✅ Added -- [#516](https://github.com/GetStream/stream-chat-flutter/issues/516): Added `StreamChatThemeData.placeholderUserImage` for - building a widget when the `UserAvatar` image is loading +- [#516](https://github.com/GetStream/stream-chat-flutter/issues/516): + Added `StreamChatThemeData.placeholderUserImage` for building a widget when the `UserAvatar` image + is loading - Added a `backgroundColor` property to the following widgets: - - `ChannelHeader` - - `ChannelListHeader` - - `GalleryHeader` - - `GalleryFooter` - - `ThreadHeader` + - `ChannelHeader` + - `ChannelListHeader` + - `GalleryHeader` + - `GalleryFooter` + - `ThreadHeader` +- Added `MessageInput.attachmentButtonBuilder` and `MessageInput.commandButtonBuilder` for more + customizations. + +```dart +typedef ActionButtonBuilder = Widget Function( + BuildContext context, + IconButton defaultActionButton, + ); +``` + +> **_NOTE:_** The last parameter is the default `ActionButton` +You can call `.copyWith` to customize just a subset of properties. 🔄 Changed -Theming has been upgraded! Most theme classes now have `InheritedTheme` classes -associated with them, and have been upgraded with some goodies like `lerp` functions. -Here's the full naming breakdown: +Theming has been upgraded! Most theme classes now have `InheritedTheme` classes associated with +them, and have been upgraded with some goodies like `lerp` functions. Here's the full naming +breakdown: + * `AvatarTheme` is now `AvatarThemeData` * `ChannelHeaderTheme` is now `ChannelHeaderThemeData` * `ChannelListHeaderTheme` is now `ChannelListHeaderThemeData` @@ -32,8 +46,9 @@ Here's the full naming breakdown: 🐞 Fixed -- [#590](https://github.com/GetStream/stream-chat-flutter/issues/590): livestream use case, no members when sending message - +- [#590](https://github.com/GetStream/stream-chat-flutter/issues/590): livestream use case, no + members when sending message + ## 2.1.1 - Updated core dependency @@ -50,7 +65,8 @@ Here's the full naming breakdown: 🔄 Changed - `StreamChat.of(context).user` is now deprecated in favor of `StreamChat.of(context).currentUser`. -- `StreamChat.of(context).userStream` is now deprecated in favor of `StreamChat.of(context).currentUserStream`. +- `StreamChat.of(context).userStream` is now deprecated in favor + of `StreamChat.of(context).currentUserStream`. 🐞 Fixed @@ -64,17 +80,17 @@ Here's the full naming breakdown: - Renamed `ChannelImage` to `ChannelAvatar` - Updated `StreamChatThemeData.reactionIcons` to accept custom builder - Renamed `ColorTheme` properties to reflect the purpose of the colors - - `ColorTheme.black` -> `ColorTheme.textHighEmphasis` - - `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` - - `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` - - `ColorTheme.greyWhisper` -> `ColorTheme.borders` - - `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` - - `ColorTheme.whiteSnow` -> `ColorTheme.appBg` - - `ColorTheme.white` -> `ColorTheme.barsBg` - - `ColorTheme.blueAlice` -> `ColorTheme.linkBg` - - `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` - - `ColorTheme.accentRed` -> `ColorTheme.accentError` - - `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` + - `ColorTheme.black` -> `ColorTheme.textHighEmphasis` + - `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` + - `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` + - `ColorTheme.greyWhisper` -> `ColorTheme.borders` + - `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` + - `ColorTheme.whiteSnow` -> `ColorTheme.appBg` + - `ColorTheme.white` -> `ColorTheme.barsBg` + - `ColorTheme.blueAlice` -> `ColorTheme.linkBg` + - `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` + - `ColorTheme.accentRed` -> `ColorTheme.accentError` + - `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` - `ChannelListCore` options property is removed in favor of individual properties - `options.state` -> bool state @@ -95,7 +111,7 @@ typedef MessageBuilder = Widget Function( ); ``` -the last parameter is the default `MessageWidget` +> **_NOTE:_** the last parameter is the default `MessageWidget` You can call `.copyWith` to customize just a subset of properties @@ -103,7 +119,8 @@ You can call `.copyWith` to customize just a subset of properties - Added video compress options (frame and quality) to `MessageInput` - TypingIndicator now has a property called `parentId` to show typing indicator specific to threads -- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView header/footer +- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView + header/footer - `MessageWidget` accepts a `userAvatarBuilder` - Added pinMessage ui support - Added `MessageListView.threadSeparatorBuilder` property @@ -112,10 +129,12 @@ You can call `.copyWith` to customize just a subset of properties 🐞 Fixed -- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text box when editing - message -- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator use case -- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without a reload +- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text + box when editing message +- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator + use case +- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without + a reload - `MessageListView` not rendering if the user is not a member of the channel - Fix `MessageInput` overflow when there are no actions - Minor fixes and improvements @@ -125,17 +144,17 @@ You can call `.copyWith` to customize just a subset of properties 🛑️ Breaking Changes from `2.0.0-nullsafety.8` - Renamed `ColorTheme` properties to reflect the purpose of the colors - - `ColorTheme.black` -> `ColorTheme.textHighEmphasis` - - `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` - - `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` - - `ColorTheme.greyWhisper` -> `ColorTheme.borders` - - `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` - - `ColorTheme.whiteSnow` -> `ColorTheme.appBg` - - `ColorTheme.white` -> `ColorTheme.barsBg` - - `ColorTheme.blueAlice` -> `ColorTheme.linkBg` - - `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` - - `ColorTheme.accentRed` -> `ColorTheme.accentError` - - `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` + - `ColorTheme.black` -> `ColorTheme.textHighEmphasis` + - `ColorTheme.grey` -> `ColorTheme.textLowEmphasis` + - `ColorTheme.greyGainsboro` -> `ColorTheme.disabled` + - `ColorTheme.greyWhisper` -> `ColorTheme.borders` + - `ColorTheme.whiteSmoke` -> `ColorTheme.inputBg` + - `ColorTheme.whiteSnow` -> `ColorTheme.appBg` + - `ColorTheme.white` -> `ColorTheme.barsBg` + - `ColorTheme.blueAlice` -> `ColorTheme.linkBg` + - `ColorTheme.accentBlue` -> `ColorTheme.accentPrimary` + - `ColorTheme.accentRed` -> `ColorTheme.accentError` + - `ColorTheme.accentGreen` -> `ColorTheme.accentInfo` ✅ Added @@ -162,21 +181,24 @@ typedef MessageBuilder = Widget Function( ); ``` -the last parameter is the default `MessageWidget` -You can call `.copyWith` to customize just a subset of properties +> **_NOTE:_** The last parameter is the default `MessageWidget` +You can call `.copyWith` to customize just a subset of properties. ✅ Added - TypingIndicator now has a property called `parentId` to show typing indicator specific to threads -- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView header/footer +- [#493](https://github.com/GetStream/stream-chat-flutter/pull/493): add support for messageListView + header/footer - `MessageWidget` accepts a `userAvatarBuilder` 🐞 Fixed -- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text box when editing - message -- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator use case -- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without a reload +- [#483](https://github.com/GetStream/stream-chat-flutter/issues/483): Keyboard covers input text + box when editing message +- Modals are shown using the nearest `Navigator` to make using the SDK easier in a nested navigator + use case +- [#484](https://github.com/GetStream/stream-chat-flutter/issues/484): messages don't update without + a reload - `MessageListView` not rendering if the user is not a member of the channel ## 2.0.0-nullsafety.7 @@ -246,7 +268,8 @@ You can call `.copyWith` to customize just a subset of properties - Show error messages as system and keep them in the message input - Remove notification badge logic - Use shimmer while loading images -- Polished `StreamChatTheme` adding more options and a new `MessageInputTheme` dedicated to `MessageInput` +- Polished `StreamChatTheme` adding more options and a new `MessageInputTheme` dedicated + to `MessageInput` - Add possibility to specify custom message actions using `MessageWidget.customActions` - Added `MessageListView.onAttachmentTap` callback - Fixed message newline issue @@ -303,7 +326,8 @@ You can call `.copyWith` to customize just a subset of properties - Improved api documentation - Updated `stream_chat` dependency to `^1.0.0-beta` - Extracted sample app into dedicated [repo](https://github.com/GetStream/flutter-samples) -- Reimplemented existing widgets using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core) +- Reimplemented existing widgets + using [stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core) ## 0.2.21 @@ -320,8 +344,8 @@ You can call `.copyWith` to customize just a subset of properties ## 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 +- 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 @@ -355,7 +379,8 @@ You can call `.copyWith` to customize just a subset of properties ## 0.2.16 -- Do not wrap channel preview builder. Users will have to implement they're custom onTap/onLongPress implementation +- 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 @@ -540,10 +565,11 @@ You can call `.copyWith` to customize just a subset of properties ## 0.2.1-alpha+1 -- Removed the additional `Navigator` in `StreamChat` widget. It was added to make the app have the `StreamChat` widget - as ancestor in every route. Now the recommended way to add `StreamChat` to your app is using the `builder` property of - your `MaterialApp` widget. Otherwise you can use it in the usual way, but you need to add a `StreamChat` widget to - every route of your app. Read [this issue](https://github.com/GetStream/stream-chat-flutter/issues/47) for more +- Removed the additional `Navigator` in `StreamChat` widget. It was added to make the app have + the `StreamChat` widget as ancestor in every route. Now the recommended way to add `StreamChat` to + your app is using the `builder` property of your `MaterialApp` widget. Otherwise you can use it in + the usual way, but you need to add a `StreamChat` widget to every route of your app. + Read [this issue](https://github.com/GetStream/stream-chat-flutter/issues/47) for more information. ```dart @@ -645,8 +671,8 @@ Widget build(BuildContext context) { - Add gesture (vertical drag down) to close the keyboard -- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will even close the - keyboard) +- Add keyboard type parameters (set it to TextInputType.text to show the submit button that will + even close the keyboard) The property showVideoFullScreen was added mainly because of this issue brianegan/chewie#261 diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index b975941e..2780e1c8 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -46,9 +46,9 @@ extension PlatformFileX on PlatformFile { ); } -/// +/// Extension on [InputDecoration] extension InputDecorationX on InputDecoration { - /// + /// Merges this [AvatarThemeData] with the [other] InputDecoration merge(InputDecoration? other) { if (other == null) return this; return copyWith( @@ -123,3 +123,50 @@ extension FlipBorder on BorderRadius { bottomRight: bottomLeft) : this; } + +/// Extension on [IconButton] +extension IconButtonX on IconButton { + /// Creates a copy of [IconButton] with specified attributes overridden. + IconButton copyWith({ + double? iconSize, + VisualDensity? visualDensity, + EdgeInsetsGeometry? padding, + AlignmentGeometry? alignment, + double? splashRadius, + Color? color, + Color? focusColor, + Color? hoverColor, + Color? highlightColor, + Color? splashColor, + Color? disabledColor, + void Function()? onPressed, + MouseCursor? mouseCursor, + FocusNode? focusNode, + bool? autofocus, + String? tooltip, + bool? enableFeedback, + BoxConstraints? constraints, + Widget? icon, + }) => + IconButton( + iconSize: iconSize ?? this.iconSize, + visualDensity: visualDensity ?? this.visualDensity, + padding: padding ?? this.padding, + alignment: alignment ?? this.alignment, + splashRadius: splashRadius ?? this.splashRadius, + color: color ?? this.color, + focusColor: focusColor ?? this.focusColor, + hoverColor: hoverColor ?? this.hoverColor, + highlightColor: highlightColor ?? this.highlightColor, + splashColor: splashColor ?? this.splashColor, + disabledColor: disabledColor ?? this.disabledColor, + onPressed: onPressed ?? this.onPressed, + mouseCursor: mouseCursor ?? this.mouseCursor, + focusNode: focusNode ?? this.focusNode, + autofocus: autofocus ?? this.autofocus, + tooltip: tooltip ?? this.tooltip, + enableFeedback: enableFeedback ?? this.enableFeedback, + constraints: constraints ?? this.constraints, + icon: icon ?? this.icon, + ); +} diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 9431cd22..f5e4158a 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -50,6 +50,14 @@ typedef MentionTileBuilder = Widget Function( Member member, ); +/// Widget builder for action button +/// [defaultActionButton] is the default [IconButton] configuration +/// Use [defaultActionButton.copyWith] to easily customize it +typedef ActionButtonBuilder = Widget Function( + BuildContext context, + IconButton defaultActionButton, +); + /// Location for actions on the [MessageInput] enum ActionsLocation { /// Align to left @@ -164,6 +172,8 @@ class MessageInput extends StatefulWidget { this.compressedVideoQuality = VideoQuality.DefaultQuality, this.compressedVideoFrameRate = 30, this.onError, + this.attachmentButtonBuilder, + this.commandButtonBuilder, }) : super(key: key); /// Message to edit @@ -247,6 +257,12 @@ class MessageInput extends StatefulWidget { /// A callback for error reporting final ErrorListener? onError; + /// Builder for customizing attachment button. + final ActionButtonBuilder? attachmentButtonBuilder; + + /// Builder for customizing command button. + final ActionButtonBuilder? commandButtonBuilder; + @override MessageInputState createState() => MessageInputState(); @@ -403,11 +419,11 @@ class MessageInputState extends State { children: [ if (!_commandEnabled && widget.actionsLocation == ActionsLocation.left) - _buildExpandActionsButton(), + _buildExpandActionsButton(context), _buildTextInput(context), if (!_commandEnabled && widget.actionsLocation == ActionsLocation.right) - _buildExpandActionsButton(), + _buildExpandActionsButton(context), if (widget.sendButtonLocation == SendButtonLocation.outside) _animateSendButton(context), ], @@ -490,7 +506,7 @@ class MessageInputState extends State { ); } - Widget _buildExpandActionsButton() { + Widget _buildExpandActionsButton(BuildContext context) { final channel = StreamChannel.of(context).channel; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), @@ -528,12 +544,13 @@ class MessageInputState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - if (!widget.disableAttachments) _buildAttachmentButton(), + if (!widget.disableAttachments) + _buildAttachmentButton(context), if (widget.showCommandsButton && widget.editMessage == null && channel.state != null && channel.config?.commands.isNotEmpty == true) - _buildCommandButton(), + _buildCommandButton(context), ...widget.actions ?? [], ].insertBetween(const SizedBox(width: 8)), ), @@ -669,9 +686,7 @@ class MessageInputState extends State { : (widget.actionsLocation == ActionsLocation.leftInside ? Row( mainAxisSize: MainAxisSize.min, - children: [ - _buildExpandActionsButton(), - ], + children: [_buildExpandActionsButton(context)], ) : null), suffixIconConstraints: const BoxConstraints.tightFor(height: 40), @@ -697,7 +712,7 @@ class MessageInputState extends State { ), if (!_commandEnabled && widget.actionsLocation == ActionsLocation.rightInside) - _buildExpandActionsButton(), + _buildExpandActionsButton(context), if (widget.sendButtonLocation == SendButtonLocation.inside) _animateSendButton(context), ], @@ -1681,10 +1696,9 @@ class MessageInputState extends State { } } - Widget _buildCommandButton() { + Widget _buildCommandButton(BuildContext context) { final s = textEditingController.text.trim(); - - return IconButton( + final defaultButton = IconButton( icon: StreamSvgIcon.lightning( color: s.isNotEmpty ? _streamChatTheme.colorTheme.disabled @@ -1722,38 +1736,46 @@ class MessageInputState extends State { } }, ); + + return widget.commandButtonBuilder?.call(context, defaultButton) ?? + defaultButton; } - Widget _buildAttachmentButton() => IconButton( - icon: StreamSvgIcon.attach( - color: _openFilePickerSection - ? _messageInputTheme.actionButtonColor - : _messageInputTheme.actionButtonIdleColor, - ), - padding: const EdgeInsets.all(0), - constraints: const BoxConstraints.tightFor( - height: 24, - width: 24, - ), - splashRadius: 24, - onPressed: () async { - _emojiOverlay?.remove(); - _emojiOverlay = null; - _commandsOverlay?.remove(); - _commandsOverlay = null; - _mentionsOverlay?.remove(); - _mentionsOverlay = null; + Widget _buildAttachmentButton(BuildContext context) { + final defaultButton = IconButton( + icon: StreamSvgIcon.attach( + color: _openFilePickerSection + ? _messageInputTheme.actionButtonColor + : _messageInputTheme.actionButtonIdleColor, + ), + padding: const EdgeInsets.all(0), + constraints: const BoxConstraints.tightFor( + height: 24, + width: 24, + ), + splashRadius: 24, + onPressed: () async { + _emojiOverlay?.remove(); + _emojiOverlay = null; + _commandsOverlay?.remove(); + _commandsOverlay = null; + _mentionsOverlay?.remove(); + _mentionsOverlay = null; - if (_openFilePickerSection) { - setState(() { - _openFilePickerSection = false; - _filePickerSize = _kMinMediaPickerSize; - }); - } else { - showAttachmentModal(); - } - }, - ); + if (_openFilePickerSection) { + setState(() { + _openFilePickerSection = false; + _filePickerSize = _kMinMediaPickerSize; + }); + } else { + showAttachmentModal(); + } + }, + ); + + return widget.attachmentButtonBuilder?.call(context, defaultButton) ?? + defaultButton; + } /// Show the attachment modal, making the user choose where to /// pick a media from diff --git a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart index 89c6450c..42188fa0 100644 --- a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart +++ b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart @@ -12,6 +12,7 @@ export 'src/channel_preview.dart'; export 'src/connection_status_builder.dart'; export 'src/date_divider.dart'; export 'src/deleted_message.dart'; +export 'src/extension.dart' show IconButtonX; export 'src/full_screen_media.dart'; export 'src/gallery_footer.dart'; export 'src/gallery_header.dart'; From aa223ce25877d9c9ba5aec6f247f27a40f0a7f3b Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Mon, 9 Aug 2021 14:30:07 +0200 Subject: [PATCH 25/99] chore: format comments --- .../stream_chat/lib/src/client/channel.dart | 232 ++++++++++-------- 1 file changed, 123 insertions(+), 109 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index a05587ab..4d4a3858 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -63,145 +63,145 @@ class Channel { _extraData.addAll(extraData); } - /// Returns true if the channel is muted + /// Returns true if the channel is muted. bool get isMuted => _client.state.currentUser?.channelMutes .any((element) => element.channel.cid == cid) == true; - /// Returns true if the channel is muted as a stream + /// Returns true if the channel is muted, as a stream. Stream? get isMutedStream => _client.state.currentUserStream .map((event) => event!.channelMutes.any((element) => element.channel.cid == cid) == true) .distinct(); - /// True if the channel is a group + /// True if the channel is a group. bool get isGroup => memberCount != 2; - /// True if the channel is distinct + /// True if the channel is distinct. bool get isDistinct => id?.startsWith('!members') == true; - /// Channel configuration + /// Channel configuration. ChannelConfig? get config { _checkInitialized(); return state?._channelState.channel?.config; } - /// Channel configuration as a stream + /// Channel configuration as a stream. Stream? get configStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.config); } - /// Channel user creator + /// Channel user creator. User? get createdBy { _checkInitialized(); return state?._channelState.channel?.createdBy; } - /// Channel user creator as a stream + /// Channel user creator as a stream. Stream? get createdByStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.createdBy); } - /// Channel frozen status + /// Channel frozen status. bool? get frozen { _checkInitialized(); return state?._channelState.channel?.frozen; } - /// Channel frozen status as a stream + /// Channel frozen status as a stream. Stream? get frozenStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.frozen); } - /// Channel creation date + /// Channel creation date. DateTime? get createdAt { _checkInitialized(); return state?._channelState.channel?.createdAt; } - /// Channel creation date as a stream + /// Channel creation date as a stream. Stream? get createdAtStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.createdAt); } - /// Channel last message date + /// Channel last message date. DateTime? get lastMessageAt { _checkInitialized(); return state?._channelState.channel?.lastMessageAt; } - /// Channel last message date as a stream + /// Channel last message date as a stream. Stream? get lastMessageAtStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.lastMessageAt); } - /// Channel updated date + /// Channel updated date. DateTime? get updatedAt { _checkInitialized(); return state?._channelState.channel?.updatedAt; } - /// Channel updated date as a stream + /// Channel updated date as a stream. Stream? get updatedAtStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.updatedAt); } - /// Channel deletion date + /// Channel deletion date. DateTime? get deletedAt { _checkInitialized(); return state?._channelState.channel?.deletedAt; } - /// Channel deletion date as a stream + /// Channel deletion date as a stream. Stream? get deletedAtStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.deletedAt); } - /// Channel member count + /// Channel member count. int? get memberCount { _checkInitialized(); return state?._channelState.channel?.memberCount; } - /// Channel member count as a stream + /// Channel member count as a stream. Stream? get memberCountStream { _checkInitialized(); return state?.channelStateStream.map((cs) => cs.channel?.memberCount); } - /// Channel id + /// Channel id. String? get id => state?._channelState.channel?.id ?? _id; - /// Channel type + /// Channel type. String get type => state?._channelState.channel?.type ?? _type; - /// Channel cid + /// Channel cid. String? get cid => state?._channelState.channel?.cid ?? _cid; - /// Channel team + /// Channel team. String? get team { _checkInitialized(); return state?._channelState.channel?.team; } - /// Channel extra data + /// Channel extra data. Map get extraData { var data = state?._channelState.channel?.extraData; if (data == null || data.isEmpty) { @@ -210,7 +210,7 @@ class Channel { return data; } - /// Channel extra data as a stream + /// Channel extra data as a stream. Stream> get extraDataStream { _checkInitialized(); return state!.channelStateStream.map( @@ -224,9 +224,10 @@ class Channel { final Completer _initializedCompleter = Completer(); - /// True if this is initialized + /// True if this is initialized. + /// /// Call [watch] to initialize the client or instantiate it using - /// [Channel.fromState] + /// [Channel.fromState]. Future get initialized => _initializedCompleter.future; final _cancelableAttachmentUploadRequest = {}; @@ -362,7 +363,9 @@ class Channel { } /// Send a [message] to this channel. - /// If [skipPush] is true the message will not send a push notification + /// + /// If [skipPush] is true the message will not send a push notification. + /// /// Waits for a [_messageAttachmentsUploadCompleter] to complete /// before actually sending the message. Future sendMessage( @@ -427,6 +430,7 @@ class Channel { } /// Updates the [message] in this channel. + /// /// Waits for a [_messageAttachmentsUploadCompleter] to complete /// before actually updating the message. Future updateMessage(Message message) async { @@ -489,8 +493,10 @@ class Channel { } /// Partially updates the [message] in this channel. - /// Use [set] to define values to be set - /// Use [unset] to define values to be unset + /// + /// Use [set] to define values to be set. + /// + /// Use [unset] to define values to be unset. Future partialUpdateMessage( Message message, { Map? set, @@ -590,7 +596,7 @@ class Channel { ); } - /// Unpins provided message + /// Unpins provided message. Future unpinMessage(Message message) => partialUpdateMessage( message, @@ -599,7 +605,7 @@ class Channel { }, ); - /// Send a file to this channel + /// Send a file to this channel. Future sendFile( AttachmentFile file, { ProgressCallback? onSendProgress, @@ -615,7 +621,7 @@ class Channel { ); } - /// Send an image to this channel + /// Send an image to this channel. Future sendImage( AttachmentFile file, { ProgressCallback? onSendProgress, @@ -631,7 +637,7 @@ class Channel { ); } - /// A message search. + /// Search for a message with the given options. Future search({ String? query, Filter? messageFilters, @@ -648,7 +654,7 @@ class Channel { ); } - /// Delete a file from this channel + /// Delete a file from this channel. Future deleteFile( String url, { CancelToken? cancelToken, @@ -662,7 +668,7 @@ class Channel { ); } - /// Delete an image from this channel + /// Delete an image from this channel. Future deleteImage( String url, { CancelToken? cancelToken, @@ -676,14 +682,15 @@ class Channel { ); } - /// Send an event on this channel + /// Send an event on this channel. Future sendEvent(Event event) { _checkInitialized(); return _client.sendEvent(id!, type, event); } - /// Send a reaction to this channel - /// Set [enforceUnique] to true to remove the existing user reaction + /// Send a reaction to this channel. + /// + /// Set [enforceUnique] to true to remove the existing user reaction. Future sendReaction( Message message, String type, { @@ -746,7 +753,7 @@ class Channel { } } - /// Delete a reaction from this channel + /// Delete a reaction from this channel. Future deleteReaction( Message message, Reaction reaction) async { final type = reaction.type; @@ -821,25 +828,25 @@ class Channel { return _client.deleteChannel(id!, type); } - /// Removes all messages from the channel + /// Removes all messages from the channel. Future truncate() async { _checkInitialized(); return _client.truncateChannel(id!, type); } - /// Accept invitation to the channel + /// Accept invitation to the channel. Future acceptInvite([Message? message]) async { _checkInitialized(); return _client.acceptChannelInvite(id!, type, message: message); } - /// Reject invitation to the channel + /// Reject invitation to the channel. Future rejectInvite([Message? message]) async { _checkInitialized(); return _client.rejectChannelInvite(id!, type, message: message); } - /// Add members to the channel + /// Add members to the channel. Future addMembers( List memberIds, [ Message? message, @@ -848,7 +855,7 @@ class Channel { return _client.addChannelMembers(id!, type, memberIds, message: message); } - /// Invite members to the channel + /// Invite members to the channel. Future inviteMembers( List memberIds, [ Message? message, @@ -857,7 +864,7 @@ class Channel { return _client.inviteChannelMembers(id!, type, memberIds, message: message); } - /// Remove members from the channel + /// Remove members from the channel. Future removeMembers( List memberIds, [ Message? message, @@ -866,7 +873,7 @@ class Channel { return _client.removeChannelMembers(id!, type, memberIds, message: message); } - /// Send action for a specific message of this channel + /// Send action for a specific message of this channel. Future sendAction( Message message, Map formData, @@ -913,9 +920,10 @@ class Channel { return res; } - /// Mark all messages as read + /// Mark all messages as read. + /// /// Optionally provide a [messageId] if you want to mark a - /// particular message as read + /// particular message as read. Future markRead({String? messageId}) async { _checkInitialized(); client.state.totalUnreadCount = @@ -924,7 +932,7 @@ class Channel { return _client.markChannelRead(id!, type, messageId: messageId); } - /// Loads the initial channel state and watches for changes + /// Loads the initial channel state and watches for changes. Future watch() async { ChannelState response; @@ -955,15 +963,16 @@ class Channel { } } - /// Stop watching the channel + /// Stop watching the channel. Future stopWatching() async { _checkInitialized(); return _client.stopChannelWatching(id!, type); } - /// List the message replies for a parent message + /// List the message replies for a parent message. + /// /// Set [preferOffline] to true to avoid the api call if the data is already - /// in the offline storage + /// in the offline storage. Future getReplies( String parentId, { PaginationParams? options, @@ -987,7 +996,7 @@ class Channel { return repliesResponse; } - /// List the reactions for a message in the channel + /// List the reactions for a message in the channel. Future getReactions( String messageId, { PaginationParams? pagination, @@ -997,7 +1006,7 @@ class Channel { pagination: pagination, ); - /// Retrieves a list of messages by ID + /// Retrieves a list of messages by given [messageIDs]. Future getMessagesById( List messageIDs, ) async { @@ -1008,7 +1017,7 @@ class Channel { return res; } - /// Retrieves a list of messages by ID + /// Translate a message by given [messageId] and [language]. Future translateMessage( String messageId, String language, @@ -1018,12 +1027,13 @@ class Channel { language, ); - /// Creates a new channel + /// Creates a new channel. Future create() async => query(state: false); - /// Query the API, get messages, members or other channel fields - /// Set [preferOffline] to true to avoid the api call if the data is already - /// in the offline storage + /// Query the API, get messages, members or other channel fields. + /// + /// Set [preferOffline] to true to avoid the API call if the data is already + /// in the offline storage. Future query({ bool state = true, bool watch = false, @@ -1077,7 +1087,7 @@ class Channel { } } - /// Query channel members + /// Query channel members. Future queryMembers({ Filter? filter, List? sort, @@ -1092,19 +1102,19 @@ class Channel { pagination: pagination, ); - /// Mutes the channel + /// Mutes the channel. Future mute({Duration? expiration}) { _checkInitialized(); return _client.muteChannel(cid!, expiration: expiration); } - /// Unmutes the channel + /// Unmute the channel. Future unmute() { _checkInitialized(); return _client.unmuteChannel(cid!); } - /// Bans a user from the channel + /// Bans the user with given [userID] from the channel. Future banUser( String userID, Map options, @@ -1118,7 +1128,7 @@ class Channel { return _client.banUser(userID, opts); } - /// Remove the ban for a user in the channel + /// Remove the ban for the user with given [userID] in the channel. Future unbanUser(String userID) async { _checkInitialized(); return _client.unbanUser(userID, { @@ -1127,7 +1137,7 @@ class Channel { }); } - /// Shadow bans a user from the channel + /// Shadow bans the user with the given [userID] from the channel. Future shadowBan( String userID, Map options, @@ -1141,7 +1151,7 @@ class Channel { return _client.shadowBan(userID, opts); } - /// Remove the shadow ban for a user in the channel + /// Remove the shadow ban for the user with the given [userID] in the channel. Future removeShadowBan(String userID) async { _checkInitialized(); return _client.removeShadowBan(userID, { @@ -1151,8 +1161,10 @@ class Channel { } /// Hides the channel from [StreamChatClient.queryChannels] for the user - /// until a message is added If [clearHistory] is set to true - all messages - /// will be removed for the user + /// until a message is added. + /// + /// If [clearHistory] is set to true - all messages + /// will be removed for the user. Future hide({bool clearHistory = false}) async { _checkInitialized(); final response = await _client.hideChannel( @@ -1170,7 +1182,7 @@ class Channel { return response; } - /// Removes the hidden status for the channel + /// Removes the hidden status for the channel. Future show() async { _checkInitialized(); return _client.showChannel(id!, type); @@ -1178,7 +1190,7 @@ class Channel { /// Stream of [Event] coming from websocket connection specific for the /// channel. Pass an eventType as parameter in order to filter just a type - /// of event + /// of event. Stream on([ String? eventType, String? eventType2, @@ -1216,7 +1228,7 @@ class Channel { } } - /// Sets last typing to null and sends the typing.stop event + /// Sets last typing to null and sends the typing.stop event. Future stopTyping([String? parentId]) async { if (config?.typingEvents == false) { return; @@ -1230,7 +1242,7 @@ class Channel { )); } - /// Call this method to dispose the channel client + /// Call this method to dispose the channel client. void dispose() { state?.dispose(); } @@ -1244,9 +1256,9 @@ class Channel { } } -/// The class that handles the state of the channel listening to the events +/// The class that handles the state of the channel listening to the events. class ChannelClientState { - /// Creates a new instance listening to events and updating the state + /// Creates a new instance listening to events and updating the state. ChannelClientState( this._channel, ChannelState channelState, @@ -1393,23 +1405,25 @@ class ChannelClientState { } /// Flag which indicates if [ChannelClientState] contain latest/recent messages or not. + /// /// This flag should be managed by UI sdks. - /// When false, any new message (received by WebSocket event - /// - [EventType.messageNew]) will not be pushed on to message list. + /// + /// When false, any new message received by WebSocket event + /// [EventType.messageNew] will not be pushed on to message list. bool get isUpToDate => _isUpToDateController.value; set isUpToDate(bool isUpToDate) => _isUpToDateController.add(isUpToDate); - /// [isUpToDate] flag count as a stream + /// [isUpToDate] flag count as a stream. Stream get isUpToDateStream => _isUpToDateController.stream; final BehaviorSubject _isUpToDateController = BehaviorSubject.seeded(true); - /// The retry queue associated to this channel + /// The retry queue associated to this channel. late final RetryQueue _retryQueue; - /// Retry failed message + /// Retry failed message. Future retryFailedMessages() async { final failedMessages = [...messages, ...threads.values.expand((v) => v)] @@ -1502,7 +1516,7 @@ class ChannelClientState { })); } - /// Add a message to this channel + /// Add a message to this channel. void addMessage(Message message) { if (message.parentId == null || message.showInChannel == true) { final newMessages = List.from(_channelState.messages); @@ -1567,36 +1581,36 @@ class ChannelClientState { ); } - /// Channel message list + /// Channel message list. List get messages => _channelState.messages; - /// Channel message list as a stream + /// Channel message list as a stream. Stream?> get messagesStream => channelStateStream .map((cs) => cs.messages) .distinct(const ListEquality().equals); - /// Channel pinned message list + /// Channel pinned message list. List? get pinnedMessages => _channelState.pinnedMessages.toList(); - /// Channel pinned message list as a stream + /// Channel pinned message list as a stream. Stream?> get pinnedMessagesStream => channelStateStream.map((cs) => cs.pinnedMessages.toList()); - /// Get channel last message + /// Get channel last message. Message? get lastMessage => _channelState.messages.isNotEmpty == true ? _channelState.messages.last : null; - /// Get channel last message + /// Get channel last message. Stream get lastMessageStream => messagesStream .map((event) => event?.isNotEmpty == true ? event!.last : null); - /// Channel members list + /// Channel members list. List get members => _channelState.members .map((e) => e.copyWith(user: _channel.client.state.users[e.user!.id])) .toList(); - /// Channel members list as a stream + /// Channel members list as a stream. Stream> get membersStream => CombineLatestStream.combine2< List?, Map, List>( channelStateStream.map((cs) => cs.members), @@ -1605,19 +1619,19 @@ class ChannelClientState { members!.map((e) => e!.copyWith(user: users[e.user!.id])).toList(), ).distinct(const ListEquality().equals); - /// Channel watcher count + /// Channel watcher count. int? get watcherCount => _channelState.watcherCount; - /// Channel watcher count as a stream + /// Channel watcher count as a stream. Stream get watcherCountStream => channelStateStream.map((cs) => cs.watcherCount); - /// Channel watchers list + /// Channel watchers list. List get watchers => _channelState.watchers .map((e) => _channel.client.state.users[e.id] ?? e) .toList(); - /// Channel watchers list as a stream + /// Channel watchers list as a stream. Stream> get watchersStream => CombineLatestStream.combine2< List?, Map, List>( channelStateStream.map((cs) => cs.watchers), @@ -1625,20 +1639,20 @@ class ChannelClientState { (watchers, users) => watchers!.map((e) => users[e.id] ?? e).toList(), ); - /// Channel read list + /// Channel read list. List? get read => _channelState.read; - /// Channel read list as a stream + /// Channel read list as a stream. Stream?> get readStream => channelStateStream.map((cs) => cs.read); final BehaviorSubject _unreadCountController = BehaviorSubject.seeded(0); set unreadCount(int value) => _unreadCountController.add(value); - /// Unread count getter as a stream + /// Unread count getter as a stream. Stream get unreadCountStream => _unreadCountController.stream.distinct(); - /// Unread count getter + /// Unread count getter. int get unreadCount => _unreadCountController.value; bool _countMessageAsUnread(Message message) { @@ -1654,7 +1668,7 @@ class ChannelClientState { !userIsMuted; } - /// Update threads with updated information about messages + /// Update threads with updated information about messages. void updateThreadInfo(String parentId, List messages) { final newThreads = Map>.from(threads); @@ -1676,7 +1690,7 @@ class ChannelClientState { _threads = newThreads; } - /// Delete all channel messages + /// Delete all channel messages. void truncate() { _channelState = _channelState.copyWith( messages: [], @@ -1685,7 +1699,7 @@ class ChannelClientState { final List _updatedMessagesIds = []; - /// Update channelState with updated information + /// Update channelState with updated information. void updateChannelState(ChannelState updatedState) { final newMessages = [ ...updatedState.messages, @@ -1737,13 +1751,13 @@ class ChannelClientState { int _sortByCreatedAt(Message a, Message b) => a.createdAt.compareTo(b.createdAt); - /// The channel state related to this client + /// The channel state related to this client. ChannelState get _channelState => _channelStateController.value; - /// The channel state related to this client as a stream + /// The channel state related to this client as a stream. Stream get channelStateStream => _channelStateController.stream; - /// The channel state related to this client + /// The channel state related to this client. ChannelState get channelState => _channelStateController.value; late BehaviorSubject _channelStateController; @@ -1754,11 +1768,11 @@ class ChannelClientState { _debouncedUpdatePersistenceChannelState.call([v]); } - /// The channel threads related to this channel + /// The channel threads related to this channel. Map> get threads => _threadsController.value.map((key, value) => MapEntry(key, value)); - /// The channel threads related to this channel as a stream + /// The channel threads related to this channel as a stream. Stream>> get threadsStream => _threadsController.stream; final BehaviorSubject>> _threadsController = @@ -1772,10 +1786,10 @@ class ChannelClientState { _threadsController.add(v); } - /// Channel related typing users last value + /// Channel related typing users last value. Map get typingEvents => _typingEventsController.value; - /// Channel related typing users stream + /// Channel related typing users stream. Stream> get typingEventsStream => _typingEventsController.stream; @@ -1903,7 +1917,7 @@ class ChannelClientState { }); } - /// Call this method to dispose this object + /// Call this method to dispose this object. void dispose() { _debouncedUpdatePersistenceChannelState.cancel(); _unreadCountController.close(); From eae7cb10206264bfd1570dcf96f3d998910d41f6 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 09:59:08 +0200 Subject: [PATCH 26/99] feat: add image get, set and update to channel --- .../stream_chat/lib/src/client/channel.dart | 110 ++++++++++++++++-- .../test/src/api/channel_test.dart | 54 +++++++++ 2 files changed, 155 insertions(+), 9 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 4d4a3858..7ea1a50b 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -15,20 +15,49 @@ import 'package:stream_chat/src/core/util/utils.dart'; import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/stream_chat.dart'; -/// This a the class that manages a specific channel. +/// Class that manages a specific channel. +/// +/// {@template image} +/// If an optional [image] argument is provided in the constructor then it +/// will be set on [extraData] with a key of 'image'. +/// +/// ```dart +/// final channel = Channel(client, type, id, image: 'https://getstream.io/image.png'); +/// print(channel.image == channel.extraData['image']); // true +/// ``` +/// +/// Before the channel is initialized the image can be set directly: +/// ```dart +/// channel.image = 'https://getstream.io/new-image'; +/// ``` +/// +/// To update the image after the channel has been initialized call: +/// ```dart +/// channel.updateImage('https://getstream.io/new-image'); +/// ``` +/// +/// This will do a partial update to update the image. +/// {@endtemplate} class Channel { - /// Create a channel client instance. + /// Class that manages a specific channel. + /// + /// Optional [extraData] and [image] properties can be provided. The [image] + /// is exposed to easily set a key of 'image' on [extraData]. Channel( this._client, this._type, this._id, { Map? extraData, + String? image, }) : _cid = _id != null ? '$_type:$_id' : null, - _extraData = extraData ?? {} { - _client.logger.info('New Channel instance not initialized created'); + _extraData = { + ...?extraData, + if (image != null) 'image': image, + } { + _client.logger.info('New Channel instance created, not yet initialized'); } - /// Create a channel client instance from a [ChannelState] object + /// Create a channel client instance from a [ChannelState] object. Channel.fromState(this._client, ChannelState channelState) : assert( channelState.channel != null, @@ -40,7 +69,7 @@ class Channel { _extraData = channelState.channel!.extraData { state = ChannelClientState(this, channelState); _initializedCompleter.complete(true); - _client.logger.info('New Channel instance initialized created'); + _client.logger.info('New Channel instance initialized'); } /// This client state @@ -63,6 +92,19 @@ class Channel { _extraData.addAll(extraData); } + /// Shortcut to set channel image. + /// + /// {@macro image} + set image(String? image) { + if (_initializedCompleter.isCompleted) { + throw StateError( + 'Once the channel is initialized you should use channel.update ' + 'to update channel image', + ); + } + _extraData.addAll({'image': image}); + } + /// Returns true if the channel is muted. bool get isMuted => _client.state.currentUser?.channelMutes @@ -218,7 +260,26 @@ class Channel { ); } - /// The main Stream chat client + /// Shortcut to get channel image. + /// + /// {@macro image} + String? get image => extraData['image'] as String?; + + /// Channel [image] as a stream. + /// + /// The channel needs to be initialized. + /// + /// {@macro image} + Stream get imageStream { + _checkInitialized(); + return state!.channelStateStream.map( + (cs) => + (cs.channel?.extraData['image'] as String?) ?? + (_extraData['image'] as String?), + ); + } + + /// The main Stream chat client. StreamChatClient get client => _client; final StreamChatClient _client; @@ -799,7 +860,36 @@ class Channel { } } - /// Edit the channel custom data + /// Update the channel's [image]. + /// + /// This is equivelant to calling [updatePartial] and providing a map with an + /// 'image' key: + /// + /// ```dart + /// channel.updatePartial( + /// set: {'image': 'https://getstream.io/new-image'} + /// ); + /// ``` + /// + /// Instead do: + /// ```dart + /// channel.updateImage('https://getstream.io/new-image'); + /// ``` + Future updateImage( + String image, + ) { + _checkInitialized(); + + return _client.updateChannelPartial( + id!, + type, + set: { + 'image': image, + }, + ); + } + + /// Edit the channel custom data. Future update( Map channelData, [ Message? updateMessage, @@ -813,7 +903,9 @@ class Channel { ); } - /// Edit the channel custom data + /// Edit the channel custom data. + // TODO: This is the same description as [update]. Distinguish the two + // and provide a better description for set and unset. Future updatePartial({ Map? set, List? unset, diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 5be55491..381c208b 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -72,6 +72,23 @@ void main() { expect(channel.extraData.containsKey('name'), isTrue); expect(channel.extraData['name'], 'test-channel-name'); }); + + test('should be able to get and set `image`', () { + expect(channel.extraData.isEmpty, isTrue); + + const imageUrl = 'https://getstream.io/some-image'; + channel.image = imageUrl; + + expect(channel.image, imageUrl); + expect(channel.extraData['image'], imageUrl); + + const newImage = 'https://getstream.io/new-image'; + final newChannelInstance = + Channel(client, channelType, channelId, image: newImage); + + expect(newChannelInstance.image, newImage); + expect(newChannelInstance.extraData['image'], newImage); + }); }); // TODO : test all persistence related logic in this group @@ -192,6 +209,14 @@ void main() { } }); + test('should throw if trying to set `image`', () { + try { + channel.image = 'https://stream.io/some-image'; + } catch (e) { + expect(e, isA()); + } + }); + group('`.sendMessage`', () { test('should work fine', () async { final message = Message(id: 'test-message-id'); @@ -1192,6 +1217,35 @@ void main() { message: any(named: 'message'))).called(1); }); + test('`.updateImage`', () async { + const image = 'https://getstream.io/new-image'; + + final channelModel = ChannelModel( + cid: channelCid, + extraData: {'image': image}, + ); + + when(() => client.updateChannelPartial( + any(), + any(), + set: {'image': image}, + )).thenAnswer( + (_) async => PartialUpdateChannelResponse()..channel = channelModel, + ); + final res = await channel.updateImage(image); + + expect(res, isNotNull); + expect(res.channel.extraData['image'], image); + + verify( + () => client.updateChannelPartial( + any(), + any(), + set: {'image': image}, + ), + ).called(1); + }); + test('`.updatePartial`', () async { const set = { 'name': 'Stream Team', From ae8ebe2dba6e6a1c3a175bb506c18610bbf7c7ab Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 10:00:02 +0200 Subject: [PATCH 27/99] chore: prefer image and name property on image --- .../test/src/core/models/reaction_test.dart | 28 ++++++++++--------- .../test/src/channel_image_test.dart | 26 +++++------------ 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/packages/stream_chat/test/src/core/models/reaction_test.dart b/packages/stream_chat/test/src/core/models/reaction_test.dart index 0891b548..fbe493ef 100644 --- a/packages/stream_chat/test/src/core/models/reaction_test.dart +++ b/packages/stream_chat/test/src/core/models/reaction_test.dart @@ -13,10 +13,11 @@ void main() { expect(reaction.type, 'wow'); expect( reaction.user?.toJson(), - User(id: '2de0297c-f3f2-489d-b930-ef77342edccf', extraData: const { - 'image': 'https://randomuser.me/api/portraits/women/45.jpg', - 'name': 'Daisy Morgan' - }).toJson(), + User( + id: '2de0297c-f3f2-489d-b930-ef77342edccf', + image: 'https://randomuser.me/api/portraits/women/45.jpg', + name: 'Daisy Morgan', + ).toJson(), ); expect(reaction.score, 1); expect(reaction.userId, '2de0297c-f3f2-489d-b930-ef77342edccf'); @@ -28,11 +29,11 @@ void main() { messageId: '76cd8c82-b557-4e48-9d12-87995d3a0e04', createdAt: DateTime.parse('2020-01-28T22:17:31.108742Z'), type: 'wow', - user: - User(id: '2de0297c-f3f2-489d-b930-ef77342edccf', extraData: const { - 'image': 'https://randomuser.me/api/portraits/women/45.jpg', - 'name': 'Daisy Morgan' - }), + user: User( + id: '2de0297c-f3f2-489d-b930-ef77342edccf', + image: 'https://randomuser.me/api/portraits/women/45.jpg', + name: 'Daisy Morgan', + ), userId: '2de0297c-f3f2-489d-b930-ef77342edccf', extraData: {'bananas': 'yes'}, score: 1, @@ -58,10 +59,11 @@ void main() { expect(newReaction.type, 'wow'); expect( newReaction.user?.toJson(), - User(id: '2de0297c-f3f2-489d-b930-ef77342edccf', extraData: const { - 'image': 'https://randomuser.me/api/portraits/women/45.jpg', - 'name': 'Daisy Morgan', - }).toJson(), + User( + id: '2de0297c-f3f2-489d-b930-ef77342edccf', + image: 'https://randomuser.me/api/portraits/women/45.jpg', + name: 'Daisy Morgan', + ).toJson(), ); expect(newReaction.score, 1); expect(newReaction.userId, '2de0297c-f3f2-489d-b930-ef77342edccf'); diff --git a/packages/stream_chat_flutter/test/src/channel_image_test.dart b/packages/stream_chat_flutter/test/src/channel_image_test.dart index c9293e79..f6d110dd 100644 --- a/packages/stream_chat_flutter/test/src/channel_image_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_image_test.dart @@ -48,7 +48,7 @@ void main() { ); testWidgets( - 'it should show the the other member image', + 'it should show the other member image', (tester) async { final client = MockClient(); final clientState = MockClientState(); @@ -74,9 +74,7 @@ void main() { userId: 'user-id2', user: User( id: 'user-id2', - extraData: const { - 'image': 'testimage', - }, + image: 'testimage', ), ) ])); @@ -85,9 +83,7 @@ void main() { userId: 'user-id2', user: User( id: 'user-id2', - extraData: const { - 'image': 'testimage', - }, + image: 'testimage', ), ), Member( @@ -98,9 +94,7 @@ void main() { when(() => clientState.usersStream).thenAnswer((i) => Stream.value({ 'user-id2': User( id: 'user-id2', - extraData: const { - 'image': 'testimage', - }, + image: 'testimage', ), })); when(() => channel.extraData).thenReturn({ @@ -149,27 +143,21 @@ void main() { userId: 'user-id', user: User( id: 'user-id', - extraData: const { - 'image': 'testimage1', - }, + image: 'testimage1', ), ), Member( userId: 'user-id2', user: User( id: 'user-id2', - extraData: const { - 'image': 'testimage2', - }, + image: 'testimage2', ), ), Member( userId: 'user-id3', user: User( id: 'user-id3', - extraData: const { - 'image': 'testimage3', - }, + image: 'testimage3', ), ), ]; From 131019d77af5c5186a2005b1fbe13cbb92c6df0a Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 10:09:37 +0200 Subject: [PATCH 28/99] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index e3e31db6..513c1cdb 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -8,7 +8,7 @@ - `User` and `OwnUser` classes now have an `image` property. Setting an image will also set the 'image' key on `extraData`, so `user.image` and `user.extraData['image']` is the same. - `User` and `OwnUser` classes now have a `name` property. Setting a name will also set the 'name' key on `extraData`, so `user.name` and `user.extraData['name']` is the same. - +- `Channel` class now has extra `image` getter and setter. As well as an `updateImage` to do a partial update after a channel has been initialized. ## 2.1.1 🐞 Fixed From adfc0adea97362909f7ed91f3b1652cc5812f4ab Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 11:53:30 +0200 Subject: [PATCH 29/99] feat: add name get, set and update on Channel --- .../stream_chat/lib/src/client/channel.dart | 113 +++++++++++++++--- .../test/src/api/channel_test.dart | 59 +++++++++ .../example/lib/main.dart | 16 +-- 3 files changed, 160 insertions(+), 28 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 7ea1a50b..aeee3540 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -17,6 +17,32 @@ import 'package:stream_chat/stream_chat.dart'; /// Class that manages a specific channel. /// +/// #### Channel name +/// +/// {@template name} +/// If an optional [name] argument is provided in the constructor then it +/// will be set on [extraData] with a key of 'name'. +/// +/// ```dart +/// final channel = Channel(client, type, id, name: 'Channel name'); +/// print(channel.name == channel.extraData['name']); // true +/// ``` +/// +/// Before the channel is initialized the name can be set directly: +/// ```dart +/// channel.name = 'New channel name'; +/// ``` +/// +/// To update the name after the channel has been initialized, call: +/// ```dart +/// channel.updateName('Updated channel name'); +/// ``` +/// +/// This will do a partial update to update the name. +/// {@endtemplate} +/// +/// #### Channel image +/// /// {@template image} /// If an optional [image] argument is provided in the constructor then it /// will be set on [extraData] with a key of 'image'. @@ -31,7 +57,7 @@ import 'package:stream_chat/stream_chat.dart'; /// channel.image = 'https://getstream.io/new-image'; /// ``` /// -/// To update the image after the channel has been initialized call: +/// To update the image after the channel has been initialized, call: /// ```dart /// channel.updateImage('https://getstream.io/new-image'); /// ``` @@ -49,10 +75,12 @@ class Channel { this._id, { Map? extraData, String? image, + String? name, }) : _cid = _id != null ? '$_type:$_id' : null, _extraData = { ...?extraData, if (image != null) 'image': image, + if (name != null) 'name': name, } { _client.logger.info('New Channel instance created, not yet initialized'); } @@ -98,13 +126,26 @@ class Channel { set image(String? image) { if (_initializedCompleter.isCompleted) { throw StateError( - 'Once the channel is initialized you should use channel.update ' - 'to update channel image', + 'Once the channel is initialized you should use channel.updateImage ' + 'to update the channel image', ); } _extraData.addAll({'image': image}); } + /// Shortcut to set channel name. + /// + /// {@macro name} + set name(String? name) { + if (_initializedCompleter.isCompleted) { + throw StateError( + 'Once the channel is initialized you should use channel.updateName ' + 'to update the channel image', + ); + } + _extraData.addAll({'name': name}); + } + /// Returns true if the channel is muted. bool get isMuted => _client.state.currentUser?.channelMutes @@ -279,6 +320,39 @@ class Channel { ); } + /// Shortcut to get channel name. + /// + /// If no name is set this returns the channel cid, else null. + /// + /// {@macro name} + String? get name { + if (extraData.containsKey('name')) { + final name = extraData['name']! as String; + if (name.isNotEmpty) return name; + } + return cid; + } + + /// Channel [name] as a stream. + /// + /// If no name is set the stream returns the channel cid. + /// + /// The channel needs to be initialized. + /// + /// {@macro name} + Stream get nameStream { + _checkInitialized(); + return state!.channelStateStream.map( + (cs) { + if (cs.channel?.extraData.containsKey('name') ?? false) { + final name = cs.channel!.extraData['name']! as String; + if (name.isNotEmpty) return name; + } + return name!; + }, + ); + } + /// The main Stream chat client. StreamChatClient get client => _client; final StreamChatClient _client; @@ -862,7 +936,7 @@ class Channel { /// Update the channel's [image]. /// - /// This is equivelant to calling [updatePartial] and providing a map with an + /// This is the same as calling [updatePartial] and providing a map with an /// 'image' key: /// /// ```dart @@ -877,17 +951,28 @@ class Channel { /// ``` Future updateImage( String image, - ) { - _checkInitialized(); + ) => + updatePartial(set: {'image': image}); - return _client.updateChannelPartial( - id!, - type, - set: { - 'image': image, - }, - ); - } + /// Update the channel's [name]. + /// + /// This is the same as calling [updatePartial] and providing a map with a + /// 'name' key: + /// + /// ```dart + /// channel.updatePartial( + /// set: {'name': 'Updated channel name'} + /// ); + /// ``` + /// + /// Instead do: + /// ```dart + /// channel.updateName('Updated channel name'); + /// ``` + Future updateName( + String name, + ) => + updatePartial(set: {'name': name}); /// Edit the channel custom data. Future update( diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 381c208b..1166405a 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -89,6 +89,28 @@ void main() { expect(newChannelInstance.image, newImage); expect(newChannelInstance.extraData['image'], newImage); }); + + test('should be able to get and set `name`', () { + expect(channel.extraData.isEmpty, isTrue); + expect( + channel.name, + channelId, + reason: 'if name is not set then use channel id', + ); + + const name = 'Channel name'; + channel.name = name; + + expect(channel.name, name); + expect(channel.extraData['name'], name); + + const newName = 'New channel name'; + final newChannelInstance = + Channel(client, channelType, channelId, name: newName); + + expect(newChannelInstance.name, newName); + expect(newChannelInstance.extraData['name'], newName); + }); }); // TODO : test all persistence related logic in this group @@ -217,6 +239,14 @@ void main() { } }); + test('should throw if trying to set `name`', () { + try { + channel.name = 'New name'; + } catch (e) { + expect(e, isA()); + } + }); + group('`.sendMessage`', () { test('should work fine', () async { final message = Message(id: 'test-message-id'); @@ -1246,6 +1276,35 @@ void main() { ).called(1); }); + test('`.updateName`', () async { + const name = 'Name'; + + final channelModel = ChannelModel( + cid: channelCid, + extraData: {'name': name}, + ); + + when(() => client.updateChannelPartial( + any(), + any(), + set: {'name': name}, + )).thenAnswer( + (_) async => PartialUpdateChannelResponse()..channel = channelModel, + ); + final res = await channel.updateName(name); + + expect(res, isNotNull); + expect(res.channel.extraData['name'], name); + + verify( + () => client.updateChannelPartial( + any(), + any(), + set: {'name': name}, + ), + ).called(1); + }); + test('`.updatePartial`', () async { const set = { 'name': 'Stream Team', diff --git a/packages/stream_chat_flutter_core/example/lib/main.dart b/packages/stream_chat_flutter_core/example/lib/main.dart index 03e791de..31410e63 100644 --- a/packages/stream_chat_flutter_core/example/lib/main.dart +++ b/packages/stream_chat_flutter_core/example/lib/main.dart @@ -329,21 +329,9 @@ class _MessageScreenState extends State { } } -/// Extensions can be used to add functionality to the SDK. In the examples -/// below, we add two simple extensions to the [StreamChatClient] and [Channel]. +/// Extensions can be used to add functionality to the SDK. In the example +/// below, we add a simple extensions to the [StreamChatClient]. extension on StreamChatClient { /// Fetches the current user id. String get uid => state.currentUser!.id; } - -extension on Channel { - /// Fetches the name of the channel by accessing [extraData] or [cid]. - String? get name { - final _channelName = extraData['name']; - if (_channelName != null) { - return _channelName as String; - } else { - return cid; - } - } -} From 472b50397f4ae19266a50647217aa99fd56e69f9 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 11:54:31 +0200 Subject: [PATCH 30/99] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 513c1cdb..52496a96 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -9,6 +9,7 @@ - `User` and `OwnUser` classes now have an `image` property. Setting an image will also set the 'image' key on `extraData`, so `user.image` and `user.extraData['image']` is the same. - `User` and `OwnUser` classes now have a `name` property. Setting a name will also set the 'name' key on `extraData`, so `user.name` and `user.extraData['name']` is the same. - `Channel` class now has extra `image` getter and setter. As well as an `updateImage` to do a partial update after a channel has been initialized. +- `Channel` class now has extra `name` getter and setter. As well as an `updateName` to do a partial update after a channel has been initialized. ## 2.1.1 🐞 Fixed From 250162b7bdf3de0c4ad6364d36f97cd7019eea9d Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 11:56:32 +0200 Subject: [PATCH 31/99] use image getter --- packages/stream_chat/lib/src/client/channel.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index aeee3540..5181eaad 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -314,9 +314,7 @@ class Channel { Stream get imageStream { _checkInitialized(); return state!.channelStateStream.map( - (cs) => - (cs.channel?.extraData['image'] as String?) ?? - (_extraData['image'] as String?), + (cs) => (cs.channel?.extraData['image'] as String?) ?? image, ); } From 4dff4d4cbe66fed7140344f6b0fdb1ff26f229af Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 12:17:19 +0200 Subject: [PATCH 32/99] chore: additional descriptions for channel update --- .../stream_chat/lib/src/client/channel.dart | 23 +++++++++++++++---- .../stream_chat/lib/src/client/client.dart | 9 ++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 5181eaad..7bf91caf 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -972,7 +972,13 @@ class Channel { ) => updatePartial(set: {'name': name}); - /// Edit the channel custom data. + /// Update the channel custom data. This replaces all of the channel data + /// with the given [channelData]. + /// + /// If you instead want to do a partial update, use [updatePartial]. + /// + /// See, https://getstream.io/chat/docs/other-rest/channel_update/?language=dart + /// for more information. Future update( Map channelData, [ Message? updateMessage, @@ -986,9 +992,18 @@ class Channel { ); } - /// Edit the channel custom data. - // TODO: This is the same description as [update]. Distinguish the two - // and provide a better description for set and unset. + /// A partial update can be used to set and unset specific custom data fields + /// when it is necessary to retain additional custom data fields on the + /// object. + /// + /// - [set] will add, or update existing attributes. + /// - [unset] will remove the attributes with the provided list of + /// values (keys). + /// + /// If you want to do a full update/replacement, use [update] instead. + /// + /// See, https://getstream.io/chat/docs/other-rest/channel_update/?language=dart + /// for more information. Future updatePartial({ Map? set, List? unset, diff --git a/packages/stream_chat/lib/src/client/client.dart b/packages/stream_chat/lib/src/client/client.dart index 104b23fc..74abcb39 100644 --- a/packages/stream_chat/lib/src/client/client.dart +++ b/packages/stream_chat/lib/src/client/client.dart @@ -767,7 +767,9 @@ class StreamChatClient { cancelToken: cancelToken, ); - /// Replaces the [channelId] of type [ChannelType] data with [data] + /// Replaces the [channelId] of type [ChannelType] data with [data]. + /// + /// Use [updateChannelPartial] for a partial update. Future updateChannel( String channelId, String channelType, @@ -781,7 +783,10 @@ class StreamChatClient { message: message, ); - /// Updates the [channelId] of type [ChannelType] data with [data] + /// Partial update for the [channelId] of type [ChannelType]. Sets the + /// data provided in [set], and removes the attributes given in [unset]. + /// + /// Use [updateChannel] for a full update. Future updateChannelPartial( String channelId, String channelType, { From 5e2c6975e21642f871b9febd519882d4824a7cb7 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Tue, 10 Aug 2021 13:59:41 +0200 Subject: [PATCH 33/99] chore: update error description --- packages/stream_chat/lib/src/client/channel.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 7bf91caf..656d7f38 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -140,7 +140,7 @@ class Channel { if (_initializedCompleter.isCompleted) { throw StateError( 'Once the channel is initialized you should use channel.updateName ' - 'to update the channel image', + 'to update the channel name', ); } _extraData.addAll({'name': name}); From b3a1d42f92d49a15f8746859269a2ca1e4096798 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 11 Aug 2021 12:47:20 +0530 Subject: [PATCH 34/99] chore(llc): fix tests, minor changes Signed-off-by: xsahil03x --- .../stream_chat/lib/src/client/channel.dart | 112 +++++++++--------- .../test/src/api/channel_test.dart | 37 +++--- 2 files changed, 73 insertions(+), 76 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 656d7f38..5eee8060 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -73,14 +73,14 @@ class Channel { this._client, this._type, this._id, { - Map? extraData, - String? image, String? name, + String? image, + Map? extraData, }) : _cid = _id != null ? '$_type:$_id' : null, _extraData = { ...?extraData, - if (image != null) 'image': image, if (name != null) 'name': name, + if (image != null) 'image': image, } { _client.logger.info('New Channel instance created, not yet initialized'); } @@ -110,14 +110,17 @@ class Channel { String? _cid; final Map _extraData; - set extraData(Map extraData) { + /// Shortcut to set channel name. + /// + /// {@macro name} + set name(String? name) { if (_initializedCompleter.isCompleted) { throw StateError( - 'Once the channel is initialized you should use channel.update ' - 'to update channel data', + 'Once the channel is initialized you should use `channel.updateName` ' + 'to update the channel name', ); } - _extraData.addAll(extraData); + _extraData.addAll({'name': name}); } /// Shortcut to set channel image. @@ -126,24 +129,21 @@ class Channel { set image(String? image) { if (_initializedCompleter.isCompleted) { throw StateError( - 'Once the channel is initialized you should use channel.updateImage ' + 'Once the channel is initialized you should use `channel.updateImage` ' 'to update the channel image', ); } _extraData.addAll({'image': image}); } - /// Shortcut to set channel name. - /// - /// {@macro name} - set name(String? name) { + set extraData(Map extraData) { if (_initializedCompleter.isCompleted) { throw StateError( - 'Once the channel is initialized you should use channel.updateName ' - 'to update the channel name', + 'Once the channel is initialized you should use `channel.update` ' + 'to update channel data', ); } - _extraData.addAll({'name': name}); + _extraData.addAll(extraData); } /// Returns true if the channel is muted. @@ -301,23 +301,6 @@ class Channel { ); } - /// Shortcut to get channel image. - /// - /// {@macro image} - String? get image => extraData['image'] as String?; - - /// Channel [image] as a stream. - /// - /// The channel needs to be initialized. - /// - /// {@macro image} - Stream get imageStream { - _checkInitialized(); - return state!.channelStateStream.map( - (cs) => (cs.channel?.extraData['image'] as String?) ?? image, - ); - } - /// Shortcut to get channel name. /// /// If no name is set this returns the channel cid, else null. @@ -342,15 +325,34 @@ class Channel { _checkInitialized(); return state!.channelStateStream.map( (cs) { - if (cs.channel?.extraData.containsKey('name') ?? false) { - final name = cs.channel!.extraData['name']! as String; + final extraData = cs.channel?.extraData; + if (extraData != null && extraData.containsKey('name')) { + final name = extraData['name']! as String; if (name.isNotEmpty) return name; } + // this can never be null once the channel is initialized return name!; }, ); } + /// Shortcut to get channel image. + /// + /// {@macro image} + String? get image => extraData['image'] as String?; + + /// Channel [image] as a stream. + /// + /// The channel needs to be initialized. + /// + /// {@macro image} + Stream get imageStream { + _checkInitialized(); + return state!.channelStateStream.map( + (cs) => (cs.channel?.extraData['image'] as String?) ?? image, + ); + } + /// The main Stream chat client. StreamChatClient get client => _client; final StreamChatClient _client; @@ -932,26 +934,6 @@ class Channel { } } - /// Update the channel's [image]. - /// - /// This is the same as calling [updatePartial] and providing a map with an - /// 'image' key: - /// - /// ```dart - /// channel.updatePartial( - /// set: {'image': 'https://getstream.io/new-image'} - /// ); - /// ``` - /// - /// Instead do: - /// ```dart - /// channel.updateImage('https://getstream.io/new-image'); - /// ``` - Future updateImage( - String image, - ) => - updatePartial(set: {'image': image}); - /// Update the channel's [name]. /// /// This is the same as calling [updatePartial] and providing a map with a @@ -967,11 +949,27 @@ class Channel { /// ```dart /// channel.updateName('Updated channel name'); /// ``` - Future updateName( - String name, - ) => + Future updateName(String name) => updatePartial(set: {'name': name}); + /// Update the channel's [image]. + /// + /// This is the same as calling [updatePartial] and providing a map with an + /// 'image' key: + /// + /// ```dart + /// channel.updatePartial( + /// set: {'image': 'https://getstream.io/new-image'} + /// ); + /// ``` + /// + /// Instead do: + /// ```dart + /// channel.updateImage('https://getstream.io/new-image'); + /// ``` + Future updateImage(String image) => + updatePartial(set: {'image': image}); + /// Update the channel custom data. This replaces all of the channel data /// with the given [channelData]. /// diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 1166405a..6b3dfda2 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -39,6 +39,7 @@ void main() { late final client = MockStreamChatClient(); const channelId = 'test-channel-id'; const channelType = 'test-channel-type'; + const channelCid = '$channelType:$channelId'; late Channel channel; setUpAll(() { @@ -94,7 +95,7 @@ void main() { expect(channel.extraData.isEmpty, isTrue); expect( channel.name, - channelId, + channelCid, reason: 'if name is not set then use channel id', ); @@ -1256,24 +1257,23 @@ void main() { ); when(() => client.updateChannelPartial( - any(), - any(), + channelId, + channelType, set: {'image': image}, )).thenAnswer( (_) async => PartialUpdateChannelResponse()..channel = channelModel, ); + final res = await channel.updateImage(image); expect(res, isNotNull); expect(res.channel.extraData['image'], image); - verify( - () => client.updateChannelPartial( - any(), - any(), - set: {'image': image}, - ), - ).called(1); + verify(() => client.updateChannelPartial( + channelId, + channelType, + set: {'image': image}, + )).called(1); }); test('`.updateName`', () async { @@ -1285,24 +1285,23 @@ void main() { ); when(() => client.updateChannelPartial( - any(), - any(), + channelId, + channelType, set: {'name': name}, )).thenAnswer( (_) async => PartialUpdateChannelResponse()..channel = channelModel, ); + final res = await channel.updateName(name); expect(res, isNotNull); expect(res.channel.extraData['name'], name); - verify( - () => client.updateChannelPartial( - any(), - any(), - set: {'name': name}, - ), - ).called(1); + verify(() => client.updateChannelPartial( + channelId, + channelType, + set: {'name': name}, + )).called(1); }); test('`.updatePartial`', () async { From 702f7ee9379f20e6e9b5bb6069aac4ddec31b70d Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 11 Aug 2021 15:00:05 +0530 Subject: [PATCH 35/99] fix(llc): don't return `cid` in case `name` is null, minor improvements Signed-off-by: xsahil03x --- .../stream_chat/lib/src/client/channel.dart | 30 +++---------------- .../test/src/api/channel_test.dart | 6 ---- 2 files changed, 4 insertions(+), 32 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 5eee8060..b22a57cc 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -303,37 +303,17 @@ class Channel { /// Shortcut to get channel name. /// - /// If no name is set this returns the channel cid, else null. - /// /// {@macro name} - String? get name { - if (extraData.containsKey('name')) { - final name = extraData['name']! as String; - if (name.isNotEmpty) return name; - } - return cid; - } + String? get name => extraData['name'] as String?; /// Channel [name] as a stream. /// - /// If no name is set the stream returns the channel cid. - /// /// The channel needs to be initialized. /// /// {@macro name} - Stream get nameStream { + Stream get nameStream { _checkInitialized(); - return state!.channelStateStream.map( - (cs) { - final extraData = cs.channel?.extraData; - if (extraData != null && extraData.containsKey('name')) { - final name = extraData['name']! as String; - if (name.isNotEmpty) return name; - } - // this can never be null once the channel is initialized - return name!; - }, - ); + return extraDataStream.map((it) => it['name'] as String?); } /// Shortcut to get channel image. @@ -348,9 +328,7 @@ class Channel { /// {@macro image} Stream get imageStream { _checkInitialized(); - return state!.channelStateStream.map( - (cs) => (cs.channel?.extraData['image'] as String?) ?? image, - ); + return extraDataStream.map((it) => it['image'] as String?); } /// The main Stream chat client. diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 6b3dfda2..7c5386c6 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -39,7 +39,6 @@ void main() { late final client = MockStreamChatClient(); const channelId = 'test-channel-id'; const channelType = 'test-channel-type'; - const channelCid = '$channelType:$channelId'; late Channel channel; setUpAll(() { @@ -93,11 +92,6 @@ void main() { test('should be able to get and set `name`', () { expect(channel.extraData.isEmpty, isTrue); - expect( - channel.name, - channelCid, - reason: 'if name is not set then use channel id', - ); const name = 'Channel name'; channel.name = name; From f8797086c5b353d2d2b197e9a67303e8ef68df82 Mon Sep 17 00:00:00 2001 From: Gordon Date: Wed, 11 Aug 2021 15:42:52 +0200 Subject: [PATCH 36/99] docs: fix broken link --- docusaurus/docs/Flutter/guides/adding_localization.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx index 37f7299d..b031796f 100644 --- a/docusaurus/docs/Flutter/guides/adding_localization.mdx +++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx @@ -14,7 +14,7 @@ We have a dedicated package for adding localization to our UI widgets. It's call ## What is Localization? -If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/**internationalization**). +If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization). What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported. From a15ae16f987d8c80daa83575543e33a69ab83752 Mon Sep 17 00:00:00 2001 From: Gordon Date: Wed, 11 Aug 2021 15:49:46 +0200 Subject: [PATCH 37/99] docs: add i18n to title --- docusaurus/docs/Flutter/guides/adding_localization.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx index b031796f..3cad5696 100644 --- a/docusaurus/docs/Flutter/guides/adding_localization.mdx +++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx @@ -1,7 +1,7 @@ --- id: adding_localization sidebar_position: 2 -title: Adding Localization +title: Adding Localization (i18n) --- Adding Localization To UI Widgets From 977a6fdc7d9dea613760d8f62b25845442c7d8f6 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 12 Aug 2021 18:56:58 +0530 Subject: [PATCH 38/99] Update docusaurus/docs/Flutter/guides/understanding_filters.mdx Co-authored-by: Gordon Hayes --- docusaurus/docs/Flutter/guides/understanding_filters.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx index 8a6fc925..d4ecf94c 100644 --- a/docusaurus/docs/Flutter/guides/understanding_filters.mdx +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -85,7 +85,7 @@ Filter.notIn('members', [user.id]) #### Filter.query -Matches values by performing text search with the specified value. +The 'query' filter matches values by performing text search with the specified value. ```dart Filter.query('name', 'demo') From 1c846b4da7df6174171e44e157b129e00824817a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 12 Aug 2021 18:57:04 +0530 Subject: [PATCH 39/99] Update docusaurus/docs/Flutter/guides/understanding_filters.mdx Co-authored-by: Gordon Hayes --- docusaurus/docs/Flutter/guides/understanding_filters.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx index d4ecf94c..a88f371c 100644 --- a/docusaurus/docs/Flutter/guides/understanding_filters.mdx +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -93,7 +93,7 @@ Filter.query('name', 'demo') #### Filter.autoComplete -Matches values with the specified prefix. +The 'autoComplete' filter matches values with the specified prefix. ```dart Filter.autoComplete('name', 'demo') From c3444fe4915b6344cad4b6416a56f36d0e2787f1 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 12 Aug 2021 18:57:10 +0530 Subject: [PATCH 40/99] Update docusaurus/docs/Flutter/guides/understanding_filters.mdx Co-authored-by: Gordon Hayes --- docusaurus/docs/Flutter/guides/understanding_filters.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx index a88f371c..e7c288b4 100644 --- a/docusaurus/docs/Flutter/guides/understanding_filters.mdx +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -101,7 +101,7 @@ Filter.autoComplete('name', 'demo') #### Filter.exists -Matches values that exist/don't exist based on the specified boolean value. +The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value. ```dart Filter.exists('name', true) From a928bea12504168c935d899c503dfcdd29490d54 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 12 Aug 2021 19:00:54 +0530 Subject: [PATCH 41/99] added new guide --- docusaurus/docs/Flutter/guides/understanding_filters.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx index e7c288b4..9d169a80 100644 --- a/docusaurus/docs/Flutter/guides/understanding_filters.mdx +++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx @@ -109,7 +109,7 @@ Filter.exists('name', true) ### Group Queries -#### FilterOperator.and +#### Filter.and The 'and' operator combines multiple queries. @@ -120,7 +120,7 @@ final filter = Filter.and([ ]) ``` -#### FilterOperator.or +#### Filter.or Combines the provided filters and matches the values matched by at least one of the filters. @@ -131,7 +131,7 @@ final filter = Filter.or([ ]) ``` -#### FilterOperator.nor +#### Filter.nor Combines the provided filters and matches the values not matched by all the filters. From f097ef9913094e10d7ae44cea03c298a225b6bbd Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 13 Aug 2021 11:45:40 +0530 Subject: [PATCH 42/99] chore(ui): Apply review feedbacks. Signed-off-by: xsahil03x --- .../stream_chat_flutter/lib/src/extension.dart | 2 +- .../lib/src/message_input.dart | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/extension.dart b/packages/stream_chat_flutter/lib/src/extension.dart index 2780e1c8..19bf4523 100644 --- a/packages/stream_chat_flutter/lib/src/extension.dart +++ b/packages/stream_chat_flutter/lib/src/extension.dart @@ -48,7 +48,7 @@ extension PlatformFileX on PlatformFile { /// Extension on [InputDecoration] extension InputDecorationX on InputDecoration { - /// Merges this [AvatarThemeData] with the [other] + /// Merges this [InputDecoration] with the [other] InputDecoration merge(InputDecoration? other) { if (other == null) return this; return copyWith( diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index f5e4158a..f556024d 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -50,9 +50,10 @@ typedef MentionTileBuilder = Widget Function( Member member, ); -/// Widget builder for action button -/// [defaultActionButton] is the default [IconButton] configuration -/// Use [defaultActionButton.copyWith] to easily customize it +/// Widget builder for action button. +/// +/// [defaultActionButton] is the default [IconButton] configuration, +/// Use [defaultActionButton.copyWith] to easily customize it. typedef ActionButtonBuilder = Widget Function( BuildContext context, IconButton defaultActionButton, @@ -257,10 +258,16 @@ class MessageInput extends StatefulWidget { /// A callback for error reporting final ErrorListener? onError; - /// Builder for customizing attachment button. + /// Builder for customizing the attachment button. + /// + /// The builder contains the default [IconButton] that can be customized by + /// calling `.copyWith`. final ActionButtonBuilder? attachmentButtonBuilder; - /// Builder for customizing command button. + /// Builder for customizing the command button. + /// + /// The builder contains the default [IconButton] that can be customized by + /// calling `.copyWith`. final ActionButtonBuilder? commandButtonBuilder; @override From 7b7a65cd70c56888de3cb1506faa7a5027108f86 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 13 Aug 2021 11:50:07 +0530 Subject: [PATCH 43/99] fix(localization): Fix hindi translations. Signed-off-by: xsahil03x --- .../lib/src/stream_chat_localizations_hi.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart index 850e481b..7d7f54d2 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart @@ -197,7 +197,7 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { 'कार्रवाई पूरी नहीं की जा सकी.'; @override - String get replyLabel => 'रिप्लाई'; + String get replyLabel => 'जवाब दें'; @override String togglePinUnpinText({required bool pinned}) { @@ -224,7 +224,7 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { } @override - String get photosLabel => 'तस्वीरें'; + String get photosLabel => 'फ़ोटोज'; String _getDay(DateTime dateTime) { final now = DateTime.now(); @@ -250,10 +250,10 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { String get todayLabel => 'आज'; @override - String get yesterdayLabel => 'बिता हुआ कल'; + String get yesterdayLabel => 'कल'; @override - String get channelIsMutedText => 'चैनल मौन है'; + String get channelIsMutedText => 'चैनल म्यूट है'; @override String get noTitleText => 'कोई शीर्षक नहीं'; From 955b5f1c0b0829d949f9218921f229b814287976 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 13 Aug 2021 11:55:56 +0530 Subject: [PATCH 44/99] chore(localization): Update changelog. Signed-off-by: xsahil03x --- packages/stream_chat_localizations/CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_localizations/CHANGELOG.md b/packages/stream_chat_localizations/CHANGELOG.md index 865741c4..0845fa05 100644 --- a/packages/stream_chat_localizations/CHANGELOG.md +++ b/packages/stream_chat_localizations/CHANGELOG.md @@ -1,6 +1,18 @@ ## Upcoming -* Added support for [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) locale. +✅ Added + +* Added support + for [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) + locale. + +🔄 Changed + +* Some of the `Hindi` translations have been updated/changed for better understanding. + - 'रिप्लाई' -> 'जवाब दें' + - 'तस्वीरें' -> 'फ़ोटोज' + - 'बिता हुआ कल' -> 'कल' + - 'चैनल मौन है' -> 'चैनल म्यूट है' ## 1.0.2 From f18c326cf44340b2c1e57ddabcec0c806b4f6236 Mon Sep 17 00:00:00 2001 From: Gordon Date: Fri, 13 Aug 2021 08:46:50 +0200 Subject: [PATCH 45/99] docs: update title Co-authored-by: Deven Joshi --- docusaurus/docs/Flutter/guides/adding_localization.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx index 3cad5696..8ecc0cce 100644 --- a/docusaurus/docs/Flutter/guides/adding_localization.mdx +++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx @@ -1,7 +1,7 @@ --- id: adding_localization sidebar_position: 2 -title: Adding Localization (i18n) +title: Adding Localization (l10n) / Internationalization (i18n) --- Adding Localization To UI Widgets From 03e9f2e5d14a4425de00b19542ff6c287e4b0631 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 13 Aug 2021 14:49:53 +0530 Subject: [PATCH 46/99] Update packages/stream_chat_flutter/lib/src/message_input.dart Co-authored-by: Gordon --- packages/stream_chat_flutter/lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index f556024d..4765bcc5 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -53,7 +53,7 @@ typedef MentionTileBuilder = Widget Function( /// Widget builder for action button. /// /// [defaultActionButton] is the default [IconButton] configuration, -/// Use [defaultActionButton.copyWith] to easily customize it. +/// use [defaultActionButton.copyWith] to easily customize it. typedef ActionButtonBuilder = Widget Function( BuildContext context, IconButton defaultActionButton, From 6c71350d395518e1b98ff0cbe25f0dbc8abc5651 Mon Sep 17 00:00:00 2001 From: Jia-Han Wu <60439733+jiahan-wu@users.noreply.github.com> Date: Fri, 13 Aug 2021 15:42:45 +0800 Subject: [PATCH 47/99] fix(ui): Fix a `MessageInput` bug. --- .../lib/src/message_input.dart | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 9431cd22..a9d6c18b 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -1869,15 +1869,14 @@ class MessageInputState extends State { } else if (fileType == DefaultAttachmentTypes.video) { pickedFile = await _imagePicker.pickVideo(source: ImageSource.camera); } - if (pickedFile == null) { - return; + if (pickedFile != null) { + final bytes = await pickedFile.readAsBytes(); + file = AttachmentFile( + size: bytes.length, + path: pickedFile.path, + bytes: bytes, + ); } - final bytes = await pickedFile.readAsBytes(); - file = AttachmentFile( - size: bytes.length, - path: pickedFile.path, - bytes: bytes, - ); } else { late FileType type; if (fileType == DefaultAttachmentTypes.image) { From 4a9301317ad99e191df581ab00e48349cdbfa978 Mon Sep 17 00:00:00 2001 From: Jia-Han Wu Date: Fri, 13 Aug 2021 18:14:17 +0800 Subject: [PATCH 48/99] Update CHANGELOG.md --- packages/stream_chat_flutter/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 5289ec30..100853bb 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -28,6 +28,10 @@ Here's the full naming breakdown: * `MessageTheme` is now `MessageThemeData` * `UserListViewTheme` is now `UserListViewThemeData` +🐞 Fixed + +- Fixed `MessageInput` textField behaviour + ## 2.1.2 🐞 Fixed From 1a28a91be7a7ebbf58eef64264945b4aa47333a3 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 13 Aug 2021 16:19:14 +0530 Subject: [PATCH 49/99] Update packages/stream_chat_flutter/CHANGELOG.md --- packages/stream_chat_flutter/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 100853bb..218843f2 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -30,7 +30,7 @@ Here's the full naming breakdown: 🐞 Fixed -- Fixed `MessageInput` textField behaviour +- Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. ## 2.1.2 From d56a6df3de096bfeb2dd53af9b76b00ce0b31000 Mon Sep 17 00:00:00 2001 From: Gordon Date: Fri, 13 Aug 2021 14:34:51 +0200 Subject: [PATCH 50/99] docs: fix example folder link --- packages/stream_chat_flutter_core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter_core/README.md b/packages/stream_chat_flutter_core/README.md index 462498f6..e625aeeb 100644 --- a/packages/stream_chat_flutter_core/README.md +++ b/packages/stream_chat_flutter_core/README.md @@ -26,7 +26,7 @@ It teaches you how to use this SDK and also shows how to make frequently require ## Example App 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-core/tree/master/example) folder. +The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/main/packages/stream_chat_flutter_core/example) folder. ## Add dependency Add this to your package's pubspec.yaml file, use the latest version [![Pub](https://img.shields.io/pub/v/stream_chat_flutter_core.svg)](https://pub.dartlang.org/packages/stream_chat_flutter_core) From 33262200a3347aae43cd8de03b7fed709f45d6e5 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 16 Aug 2021 14:21:12 +0530 Subject: [PATCH 51/99] fix: tests --- .../test/src/core/models/channel_state_test.dart | 1 + .../test/src/core/models/channel_test.dart | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat/test/src/core/models/channel_state_test.dart b/packages/stream_chat/test/src/core/models/channel_state_test.dart index 8bd17d46..f151607a 100644 --- a/packages/stream_chat/test/src/core/models/channel_state_test.dart +++ b/packages/stream_chat/test/src/core/models/channel_state_test.dart @@ -29,6 +29,7 @@ void main() { DateTime.parse('2019-04-03T18:43:33.213374Z')); expect(channelState.channel?.createdBy, isA()); expect(channelState.channel?.frozen, true); + expect(channelState.channel?.cooldown, 0); expect(channelState.channel?.extraData['example'], 1); expect(channelState.channel?.extraData['name'], '#dev'); expect( diff --git a/packages/stream_chat/test/src/core/models/channel_test.dart b/packages/stream_chat/test/src/core/models/channel_test.dart index 31162bd6..e27f5970 100644 --- a/packages/stream_chat/test/src/core/models/channel_test.dart +++ b/packages/stream_chat/test/src/core/models/channel_test.dart @@ -25,7 +25,13 @@ void main() { expect( channel.toJson(), - {'id': 'id', 'type': 'type', 'frozen': false, 'name': 'cool'}, + { + 'id': 'id', + 'type': 'type', + 'frozen': false, + 'cooldown': 0, + 'name': 'cool', + }, ); }); @@ -39,7 +45,13 @@ void main() { expect( channel.toJson(), - {'id': 'id', 'type': 'type', 'name': 'cool', 'frozen': false}, + { + 'id': 'id', + 'type': 'type', + 'frozen': false, + 'cooldown': 0, + 'name': 'cool', + }, ); }); }); From fd13d1089f54396176a3e2d6539e8a65b0361564 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 16 Aug 2021 14:48:36 +0530 Subject: [PATCH 52/99] fix: tests --- packages/stream_chat/test/fixtures/channel_state_to_json.json | 1 + .../stream_chat/test/src/core/models/channel_state_test.dart | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/test/fixtures/channel_state_to_json.json b/packages/stream_chat/test/fixtures/channel_state_to_json.json index 4b8a0369..ebb74fb6 100644 --- a/packages/stream_chat/test/fixtures/channel_state_to_json.json +++ b/packages/stream_chat/test/fixtures/channel_state_to_json.json @@ -4,6 +4,7 @@ "id": "dev", "type": "team", "frozen": true, + "cooldown": 0, "name": "#dev", "image": "https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png", "example": 1 diff --git a/packages/stream_chat/test/src/core/models/channel_state_test.dart b/packages/stream_chat/test/src/core/models/channel_state_test.dart index f151607a..8bd17d46 100644 --- a/packages/stream_chat/test/src/core/models/channel_state_test.dart +++ b/packages/stream_chat/test/src/core/models/channel_state_test.dart @@ -29,7 +29,6 @@ void main() { DateTime.parse('2019-04-03T18:43:33.213374Z')); expect(channelState.channel?.createdBy, isA()); expect(channelState.channel?.frozen, true); - expect(channelState.channel?.cooldown, 0); expect(channelState.channel?.extraData['example'], 1); expect(channelState.channel?.extraData['name'], '#dev'); expect( From 3e4d39308f883f58733f1023aae254698c29a6bf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 16 Aug 2021 20:19:55 +0530 Subject: [PATCH 53/99] refactor(llc, ui): Make Streams non-nullable wherever possible. Signed-off-by: xsahil03x --- .../stream_chat/lib/src/client/channel.dart | 86 +++++++++---------- .../lib/src/channel_preview.dart | 2 +- .../lib/src/message_list_view.dart | 4 +- 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index b22a57cc..3285db75 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -153,9 +153,9 @@ class Channel { true; /// Returns true if the channel is muted, as a stream. - Stream? get isMutedStream => _client.state.currentUserStream + Stream get isMutedStream => _client.state.currentUserStream .map((event) => - event!.channelMutes.any((element) => element.channel.cid == cid) == + event?.channelMutes.any((element) => element.channel.cid == cid) == true) .distinct(); @@ -168,105 +168,97 @@ class Channel { /// Channel configuration. ChannelConfig? get config { _checkInitialized(); - return state?._channelState.channel?.config; + return state!._channelState.channel?.config; } /// Channel configuration as a stream. - Stream? get configStream { + Stream get configStream { _checkInitialized(); - return state?.channelStateStream.map((cs) => cs.channel?.config); + return state!.channelStateStream.map((cs) => cs.channel?.config); } /// Channel user creator. User? get createdBy { _checkInitialized(); - return state?._channelState.channel?.createdBy; + return state!._channelState.channel?.createdBy; } /// Channel user creator as a stream. - Stream? get createdByStream { + Stream get createdByStream { _checkInitialized(); - return state?.channelStateStream.map((cs) => cs.channel?.createdBy); + return state!.channelStateStream.map((cs) => cs.channel?.createdBy); } /// Channel frozen status. - bool? get frozen { + bool get frozen { _checkInitialized(); - return state?._channelState.channel?.frozen; + return state!._channelState.channel?.frozen == true; } /// Channel frozen status as a stream. - Stream? get frozenStream { + Stream get frozenStream { _checkInitialized(); - return state?.channelStateStream.map((cs) => cs.channel?.frozen); + return state!.channelStateStream.map((cs) => cs.channel?.frozen == true); } /// Channel creation date. DateTime? get createdAt { _checkInitialized(); - return state?._channelState.channel?.createdAt; + return state!._channelState.channel?.createdAt; } /// Channel creation date as a stream. - Stream? get createdAtStream { + Stream get createdAtStream { _checkInitialized(); - return state?.channelStateStream.map((cs) => cs.channel?.createdAt); + return state!.channelStateStream.map((cs) => cs.channel?.createdAt); } /// Channel last message date. DateTime? get lastMessageAt { _checkInitialized(); - - return state?._channelState.channel?.lastMessageAt; + return state!._channelState.channel?.lastMessageAt; } /// Channel last message date as a stream. - Stream? get lastMessageAtStream { + Stream get lastMessageAtStream { _checkInitialized(); - - return state?.channelStateStream.map((cs) => cs.channel?.lastMessageAt); + return state!.channelStateStream.map((cs) => cs.channel?.lastMessageAt); } /// Channel updated date. DateTime? get updatedAt { _checkInitialized(); - - return state?._channelState.channel?.updatedAt; + return state!._channelState.channel?.updatedAt; } /// Channel updated date as a stream. - Stream? get updatedAtStream { + Stream get updatedAtStream { _checkInitialized(); - - return state?.channelStateStream.map((cs) => cs.channel?.updatedAt); + return state!.channelStateStream.map((cs) => cs.channel?.updatedAt); } /// Channel deletion date. DateTime? get deletedAt { _checkInitialized(); - - return state?._channelState.channel?.deletedAt; + return state!._channelState.channel?.deletedAt; } /// Channel deletion date as a stream. - Stream? get deletedAtStream { + Stream get deletedAtStream { _checkInitialized(); - - return state?.channelStateStream.map((cs) => cs.channel?.deletedAt); + return state!.channelStateStream.map((cs) => cs.channel?.deletedAt); } /// Channel member count. int? get memberCount { _checkInitialized(); - - return state?._channelState.channel?.memberCount; + return state!._channelState.channel?.memberCount; } /// Channel member count as a stream. - Stream? get memberCountStream { + Stream get memberCountStream { _checkInitialized(); - - return state?.channelStateStream.map((cs) => cs.channel?.memberCount); + return state!.channelStateStream.map((cs) => cs.channel?.memberCount); } /// Channel id. @@ -281,7 +273,7 @@ class Channel { /// Channel team. String? get team { _checkInitialized(); - return state?._channelState.channel?.team; + return state!._channelState.channel?.team; } /// Channel extra data. @@ -294,7 +286,7 @@ class Channel { } /// Channel extra data as a stream. - Stream> get extraDataStream { + Stream> get extraDataStream { _checkInitialized(); return state!.channelStateStream.map( (cs) => cs.channel?.extraData ?? _extraData, @@ -1728,9 +1720,9 @@ class ChannelClientState { (event) { final readList = List.from(_channelState.read); final userReadIndex = - read?.indexWhere((r) => r.user.id == event.user!.id); + read.indexWhere((r) => r.user.id == event.user!.id); - if (userReadIndex != null && userReadIndex != -1) { + if (userReadIndex != -1) { final userRead = readList.removeAt(userReadIndex); if (userRead.user.id == _channel._client.state.currentUser!.id) { unreadCount = 0; @@ -1751,15 +1743,15 @@ class ChannelClientState { List get messages => _channelState.messages; /// Channel message list as a stream. - Stream?> get messagesStream => channelStateStream + Stream> get messagesStream => channelStateStream .map((cs) => cs.messages) .distinct(const ListEquality().equals); /// Channel pinned message list. - List? get pinnedMessages => _channelState.pinnedMessages.toList(); + List get pinnedMessages => _channelState.pinnedMessages.toList(); /// Channel pinned message list as a stream. - Stream?> get pinnedMessagesStream => + Stream> get pinnedMessagesStream => channelStateStream.map((cs) => cs.pinnedMessages.toList()); /// Get channel last message. @@ -1768,8 +1760,8 @@ class ChannelClientState { : null; /// Get channel last message. - Stream get lastMessageStream => messagesStream - .map((event) => event?.isNotEmpty == true ? event!.last : null); + Stream get lastMessageStream => + messagesStream.map((event) => event.isNotEmpty ? event.last : null); /// Channel members list. List get members => _channelState.members @@ -1806,10 +1798,10 @@ class ChannelClientState { ); /// Channel read list. - List? get read => _channelState.read; + List get read => _channelState.read; /// Channel read list as a stream. - Stream?> get readStream => channelStateStream.map((cs) => cs.read); + Stream> get readStream => channelStateStream.map((cs) => cs.read); final BehaviorSubject _unreadCountController = BehaviorSubject.seeded(0); @@ -2060,7 +2052,7 @@ class ChannelClientState { .toList(); updateChannelState(_channelState.copyWith( - pinnedMessages: pinnedMessages!.where(_pinIsValid()).toList(), + pinnedMessages: pinnedMessages.where(_pinIsValid()).toList(), messages: expiredMessages, )); } diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 333ee886..e01cd008 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -132,7 +132,7 @@ class ChannelPreview extends StatelessWidget { message: lastMessage!, size: channelPreviewTheme.indicatorIconSize, isMessageRead: channel.state!.read - ?.where((element) => + .where((element) => element.user.id != channel .client.state.currentUser!.id) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index a3830966..54634257 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -915,7 +915,7 @@ class _MessageListViewState extends State { } final channel = streamChannel!.channel; - final readList = channel.state?.read?.where((read) { + final readList = channel.state?.read.where((read) { if (read.user.id == userId) return false; return read.lastRead.isAfter(message.createdAt) || read.lastRead.isAtSameMomentAs(message.createdAt); @@ -1204,7 +1204,7 @@ class _MessageListViewState extends State { builder: (_) => BetterStreamBuilder( stream: streamChannel!.channel.state!.messagesStream.map( (messages) => - messages!.firstWhere((m) => m.id == message.id)), + messages.firstWhere((m) => m.id == message.id)), initialData: message, builder: (_, data) => StreamChannel( channel: streamChannel!.channel, From b4329786e8682a680c26980a6dc4cc173dadf73d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 10:00:59 +0200 Subject: [PATCH 54/99] fix(ui): date dividers in not reversed message list view --- .../lib/src/message_list_view.dart | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index a3830966..82697640 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -505,8 +505,14 @@ class _MessageListViewState extends State { if (i == 1 || i == itemCount - 4) return const Offstage(); - final message = messages[i - 1]; - final nextMessage = messages[i - 2]; + late final Message message, nextMessage; + if (widget.reverse) { + message = messages[i - 1]; + nextMessage = messages[i - 2]; + } else { + message = messages[i - 2]; + nextMessage = messages[i - 1]; + } if (!Jiffy(message.createdAt.toLocal()).isSame( nextMessage.createdAt.toLocal(), Units.DAY, @@ -636,8 +642,7 @@ class _MessageListViewState extends State { } Positioned _buildFloatingDateDivider(int itemCount) => Positioned( - top: widget.reverse ? 20 : null, - bottom: widget.reverse ? null : 20, + top: 20, left: 0, right: 0, child: BetterStreamBuilder>( @@ -647,16 +652,27 @@ class _MessageListViewState extends State { if (a == null || b == null) { return false; } - final aTop = _getTopElementIndex(a); - final bTop = _getTopElementIndex(b); - return aTop == bTop; + if (widget.reverse) { + final aTop = _getTopElementIndex(a); + final bTop = _getTopElementIndex(b); + return aTop == bTop; + } else { + final aBottom = _getBottomElementIndex(a); + final bBottom = _getBottomElementIndex(b); + return aBottom == bBottom; + } }, builder: (context, values) { if (values.isEmpty || messages.isEmpty) { return const Offstage(); } - final index = _getTopElementIndex(values); + late final int? index; + if (widget.reverse) { + index = _getTopElementIndex(values); + } else { + index = _getBottomElementIndex(values); + } if (index == null || index <= 2 || index >= itemCount - 3) { return const Offstage(); @@ -685,6 +701,15 @@ class _MessageListViewState extends State { .index; } + int? _getBottomElementIndex(Iterable values) { + final inView = values.where((position) => position.itemLeadingEdge < 1); + if (inView.isEmpty) return null; + return inView + .reduce((min, position) => + position.itemLeadingEdge < min.itemLeadingEdge ? position : min) + .index; + } + Widget _buildScrollToBottom() => StreamBuilder>( stream: Rx.combineLatest2( streamChannel!.channel.state!.isUpToDateStream.distinct(), From 79b2d91902b75a3235cde2507cf0c84f060a9999 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 10:01:50 +0200 Subject: [PATCH 55/99] chore(ui): update changelog --- packages/stream_chat_flutter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index add2c3cf..9138d952 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -45,6 +45,7 @@ breakdown: 🐞 Fixed - Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. +- Fixed date dividers in not reversed `MessageListView`. ## 2.1.2 From 607ad40443b818a61afd2acf0c5b1f496e1cc245 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 10:32:56 +0200 Subject: [PATCH 56/99] fix(core): `ChannelListView` pagination on refresh --- packages/stream_chat_flutter_core/lib/src/channels_bloc.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart index 46aaccee..6687eef5 100644 --- a/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart +++ b/packages/stream_chat_flutter_core/lib/src/channels_bloc.dart @@ -106,6 +106,9 @@ class ChannelsBlocState extends State final client = _streamChatCoreState!.client; final clear = paginationParams.offset == 0; + if (clear && _paginationEnded) { + _paginationEnded = false; + } if ((!clear && _paginationEnded) || _queryChannelsLoadingController.value == true) { From 6fb8c8731e2d6ba36f94d2856140f0b97828870a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 17 Aug 2021 14:46:44 +0530 Subject: [PATCH 57/99] fix(ui): fix test Signed-off-by: xsahil03x --- packages/stream_chat_flutter/test/src/channel_preview_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/stream_chat_flutter/test/src/channel_preview_test.dart b/packages/stream_chat_flutter/test/src/channel_preview_test.dart index 7d0c549e..d6f3a5ea 100644 --- a/packages/stream_chat_flutter/test/src/channel_preview_test.dart +++ b/packages/stream_chat_flutter/test/src/channel_preview_test.dart @@ -21,6 +21,8 @@ void main() { when(() => clientState.currentUser).thenReturn(user); when(() => clientState.currentUserStream) .thenAnswer((_) => Stream.value(user)); + when(() => channel.lastMessageAtStream) + .thenAnswer((_) => Stream.value(lastMessageAt)); when(() => channel.lastMessageAt).thenReturn(lastMessageAt); when(() => channel.state).thenReturn(channelState); when(() => channel.client).thenReturn(client); From d0f5f4af8322067d131ef5fc43dec76fdd882978 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 11:19:02 +0200 Subject: [PATCH 58/99] fix format --- packages/stream_chat_flutter/lib/src/message_list_view.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 54634257..d7a49051 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -1203,8 +1203,7 @@ class _MessageListViewState extends State { MaterialPageRoute( builder: (_) => BetterStreamBuilder( stream: streamChannel!.channel.state!.messagesStream.map( - (messages) => - messages.firstWhere((m) => m.id == message.id)), + (messages) => messages.firstWhere((m) => m.id == message.id)), initialData: message, builder: (_, data) => StreamChannel( channel: streamChannel!.channel, From ad4be0e9d639ed51f9f358a88ec0a97657facb84 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 11:26:16 +0200 Subject: [PATCH 59/99] update changelog --- packages/stream_chat_flutter_core/CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index ef24e401..65280674 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,3 +1,8 @@ +## Upcoming + +🐞 Fixed +- [#612](https://github.com/GetStream/stream-chat-flutter/issues/612) `ChannelListView` pagination doesn't work after refresh + ## 2.1.1 - Updated llc dependency From 7cdc2b98e51529e754cd287ddb00a123530403d2 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 11:59:45 +0200 Subject: [PATCH 60/99] Update packages/stream_chat_flutter/CHANGELOG.md Co-authored-by: Sahil Kumar --- packages/stream_chat_flutter/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 9138d952..b21acc7a 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -45,7 +45,7 @@ breakdown: 🐞 Fixed - Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. -- Fixed date dividers in not reversed `MessageListView`. +- Fixed date dividers position/alignment in non reversed `MessageListView`. ## 2.1.2 From 56bd3b5b50ec6e461ab8bc5221c9bd3db67a1afe Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 17 Aug 2021 12:34:38 +0200 Subject: [PATCH 61/99] fix(core): always show date divider --- .../lib/src/message_list_view.dart | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 82697640..8d83ab9d 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -667,7 +667,7 @@ class _MessageListViewState extends State { return const Offstage(); } - late final int? index; + int? index; if (widget.reverse) { index = _getTopElementIndex(values); } else { @@ -675,7 +675,14 @@ class _MessageListViewState extends State { } if (index == null || index <= 2 || index >= itemCount - 3) { - return const Offstage(); + if (index == null) { + return const Offstage(); + } + if (widget.reverse) { + index = itemCount - 4; + } else { + index = 2; + } } final message = messages[index - 2]; From b2eb51317f3abc2b18bd4655359ac788a385c85b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Tue, 17 Aug 2021 16:17:19 +0530 Subject: [PATCH 62/99] refactor(ui): early return `Offstage` in case index is null. Signed-off-by: xsahil03x --- .../stream_chat_flutter/lib/src/message_list_view.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 8d83ab9d..cd9c4b45 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -674,10 +674,9 @@ class _MessageListViewState extends State { index = _getBottomElementIndex(values); } - if (index == null || index <= 2 || index >= itemCount - 3) { - if (index == null) { - return const Offstage(); - } + if (index == null) return const Offstage(); + + if (index <= 2 || index >= itemCount - 3) { if (widget.reverse) { index = itemCount - 4; } else { From 49fcaf40f5fa0d229aa38f6a4a92a20fb3a6a0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Braun?= Date: Tue, 17 Aug 2021 20:15:52 +0200 Subject: [PATCH 63/99] Fix sample app link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6758b189..62358d57 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This repository contains code for our [Dart](https://dart.dev/) and [Flutter](ht Stream allows developers to rapidly deploy scalable feeds and chat messaging with an industry leading 99.999% uptime SLA guarantee. ## Sample apps and demos -Our team maintains a dedicated repository for fully-fledged sample applications and demos. Consider checking out [GetStream/flutter-samples](https://github.com/GetStream/flutter-samples) to learn more or get started by looking at our latest [Stream Chat demo](https://github.com/GetStream/flutter-samples/tree/main/stream_chat_v1). +Our team maintains a dedicated repository for fully-fledged sample applications and demos. Consider checking out [GetStream/flutter-samples](https://github.com/GetStream/flutter-samples) to learn more or get started by looking at our latest [Stream Chat demo](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1). ## Free for Makers From f28b6b61a0dbbead99d3218838cdd7fa9802caa2 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 15:45:46 +0530 Subject: [PATCH 64/99] fix: cooldown and teams, added correct textfield hint --- packages/stream_chat/lib/src/core/models/event.dart | 4 ++++ packages/stream_chat/lib/src/core/models/event.g.dart | 2 ++ .../lib/src/localization/translations.dart | 6 ++++++ packages/stream_chat_flutter/lib/src/message_input.dart | 4 ++++ .../lib/src/stream_chat_localizations_en.dart | 3 +++ .../lib/src/stream_chat_localizations_es.dart | 3 +++ .../lib/src/stream_chat_localizations_fr.dart | 3 +++ .../lib/src/stream_chat_localizations_hi.dart | 3 +++ .../lib/src/stream_chat_localizations_it.dart | 3 +++ 9 files changed, 31 insertions(+) diff --git a/packages/stream_chat/lib/src/core/models/event.dart b/packages/stream_chat/lib/src/core/models/event.dart index 26831555..9250176d 100644 --- a/packages/stream_chat/lib/src/core/models/event.dart +++ b/packages/stream_chat/lib/src/core/models/event.dart @@ -184,6 +184,8 @@ class EventChannel extends ChannelModel { DateTime? deletedAt, required int memberCount, Map? extraData, + required int cooldown, + String? team, }) : super( id: id, type: type, @@ -197,6 +199,8 @@ class EventChannel extends ChannelModel { deletedAt: deletedAt, memberCount: memberCount, extraData: extraData ?? {}, + cooldown: cooldown, + team: team, ); /// Create a new instance from a json diff --git a/packages/stream_chat/lib/src/core/models/event.g.dart b/packages/stream_chat/lib/src/core/models/event.g.dart index 5247af17..93d2e75b 100644 --- a/packages/stream_chat/lib/src/core/models/event.g.dart +++ b/packages/stream_chat/lib/src/core/models/event.g.dart @@ -87,5 +87,7 @@ EventChannel _$EventChannelFromJson(Map json) { : DateTime.parse(json['deleted_at'] as String), memberCount: json['member_count'] as int? ?? 0, extraData: json['extra_data'] as Map? ?? {}, + cooldown: json['cooldown'] as int? ?? 0, + team: json['team'] as String?, ); } diff --git a/packages/stream_chat_flutter/lib/src/localization/translations.dart b/packages/stream_chat_flutter/lib/src/localization/translations.dart index d6e5add0..4c86e6e2 100644 --- a/packages/stream_chat_flutter/lib/src/localization/translations.dart +++ b/packages/stream_chat_flutter/lib/src/localization/translations.dart @@ -100,6 +100,9 @@ abstract class Translations { /// The label for write a message in [MessageInput] String get writeAMessageLabel; + /// The label for slow mode enabled in [MessageInput] + String get slowModeOnLabel; + /// The label for instant commands in [MessageInput] String get instantCommandsLabel; @@ -664,4 +667,7 @@ class DefaultTranslations implements Translations { @override String get replyToMessageLabel => 'Reply to Message'; + + @override + String get slowModeOnLabel => 'Slow mode ON'; } diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index afff3d52..23e64642 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -835,6 +835,10 @@ class MessageInputState extends State { if (_attachments.isNotEmpty) { return context.translations.addACommentOrSendLabel; } + if(_timeOut != 0 && _timeOut != null) { + return context.translations.slowModeOnLabel; + } + return context.translations.writeAMessageLabel; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart index 5041d398..56f2ccfe 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_en.dart @@ -357,4 +357,7 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'Reply to Message'; + + @override + String get slowModeOnLabel => 'Slow mode ON'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart index b43e4ba8..5602a4a5 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart @@ -362,4 +362,7 @@ class StreamChatLocalizationsEs extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'Responder al Mensaje'; + + @override + String get slowModeOnLabel => 'Modo lento activado'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart index 9d8586d5..f3ab6070 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart @@ -361,4 +361,7 @@ class StreamChatLocalizationsFr extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'Répondre au Message'; + + @override + String get slowModeOnLabel => 'Mode lent activé'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart index 850e481b..386651cb 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart @@ -356,4 +356,7 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'संदेश का जवाब'; + + @override + String get slowModeOnLabel => 'स्लो मोड चालू'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart index 8b2e1692..cb82a690 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart @@ -358,4 +358,7 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.'''; @override String get replyToMessageLabel => 'Rispondi al messaggio'; + + @override + String get slowModeOnLabel => 'Modalità lenta attiva'; } From 84fccf2c63fb9b4ba364dc7254a6938099fe41fd Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 18 Aug 2021 12:07:27 +0200 Subject: [PATCH 65/99] fix(ui): revert wrapping ChannelPreview in a DecoratedBox because of Slidable --- .../lib/src/channel_list_view.dart | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index eadbed59..d6cd454b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -584,11 +584,16 @@ class _ChannelListViewState extends State { ), ], child: widget.channelPreviewBuilder?.call(context, channel) ?? - ChannelPreview( - onLongPress: widget.onChannelLongPress, - channel: channel, - onImageTap: () => widget.onImageTap?.call(channel), - onTap: (channel) => onTap(channel, widget.channelWidget), + DecoratedBox( + decoration: BoxDecoration( + color: chatThemeData.channelListViewTheme.backgroundColor, + ), + child: ChannelPreview( + onLongPress: widget.onChannelLongPress, + channel: channel, + onImageTap: () => widget.onImageTap?.call(channel), + onTap: (channel) => onTap(channel, widget.channelWidget), + ), ), ), ); From 00ea765959e7aea360f0d8e637714533e10e7288 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 16:00:17 +0530 Subject: [PATCH 66/99] fix: it translations --- .../lib/src/stream_chat_localizations_it.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart index cb82a690..b3740f23 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart @@ -360,5 +360,5 @@ Il file è troppo grande per essere caricato. Il limite è di $limitInMB MB.'''; String get replyToMessageLabel => 'Rispondi al messaggio'; @override - String get slowModeOnLabel => 'Modalità lenta attiva'; + String get slowModeOnLabel => 'Slowmode attiva'; } From c2177fa7a55a52055473a84f3a48034025dcfd6f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 16:01:07 +0530 Subject: [PATCH 67/99] fmt --- packages/stream_chat_flutter/lib/src/message_input.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 23e64642..90a4b8fa 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -835,7 +835,7 @@ class MessageInputState extends State { if (_attachments.isNotEmpty) { return context.translations.addACommentOrSendLabel; } - if(_timeOut != 0 && _timeOut != null) { + if (_timeOut != 0 && _timeOut != null) { return context.translations.slowModeOnLabel; } From 2a30ff2e73140977aa6ca3808328cb06e592bae8 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 16:08:20 +0530 Subject: [PATCH 68/99] fixes --- packages/stream_chat_flutter_core/test/channels_bloc_test.dart | 1 + .../stream_chat_localizations/example/lib/add_new_lang.dart | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/stream_chat_flutter_core/test/channels_bloc_test.dart b/packages/stream_chat_flutter_core/test/channels_bloc_test.dart index a237a23c..2aee9eba 100644 --- a/packages/stream_chat_flutter_core/test/channels_bloc_test.dart +++ b/packages/stream_chat_flutter_core/test/channels_bloc_test.dart @@ -558,6 +558,7 @@ void main() { config: ChannelConfig(), createdAt: DateTime.now(), memberCount: 1, + cooldown: 0, ), ); diff --git a/packages/stream_chat_localizations/example/lib/add_new_lang.dart b/packages/stream_chat_localizations/example/lib/add_new_lang.dart index 8a1d196e..f7eb280e 100644 --- a/packages/stream_chat_localizations/example/lib/add_new_lang.dart +++ b/packages/stream_chat_localizations/example/lib/add_new_lang.dart @@ -381,6 +381,9 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'Reply to Message'; + + @override + String get slowModeOnLabel => 'Slow mode ON'; } void main() async { From a029adae249bae2b44abd7ae008eeef8f7ea27a4 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 17:30:15 +0530 Subject: [PATCH 69/99] fixes --- packages/stream_chat_flutter/lib/src/message_input.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 90a4b8fa..7b6d2936 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -363,7 +363,6 @@ class MessageInputState extends State { if (_timeOut == 0) { timer.cancel(); } else { - print('Time left until cooldown is over: $_timeOut'); setState(() => _timeOut = _timeOut! - 1); } }); From 170f18093ed296002de1b32b3d4b85bfe357df62 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Wed, 18 Aug 2021 17:31:44 +0530 Subject: [PATCH 70/99] Update packages/stream_chat/lib/src/client/channel.dart --- packages/stream_chat/lib/src/client/channel.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 5dfcb4f9..3190dc1b 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -213,7 +213,7 @@ class Channel { return state?.channelStateStream.map((cs) => cs.channel?.cooldown); } - /// + /// Stores time at which cooldown was started DateTime? cooldownStartedAt; /// Channel creation date. From d44eceb29093a5098580076e7bd85fdeff712612 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 18 Aug 2021 18:06:44 +0530 Subject: [PATCH 71/99] ci(repo): add verify-semantic-changelog-update action workflow Signed-off-by: xsahil03x --- .github/workflows/pr_title.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index eddb2ac1..d3c6122c 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -1,4 +1,4 @@ -name: 'PR Title is Conventional' +name: 'PR Title is Conventional and Semantic' on: pull_request_target: types: @@ -9,7 +9,7 @@ on: - develop jobs: - main: + conventional_pr_title: runs-on: ubuntu-latest steps: - uses: amannn/action-semantic-pull-request@v3.4.0 @@ -25,3 +25,20 @@ jobs: requireScope: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + semantic_changelog_update: + needs: conventional_pr_title # Trigger after the [conventional_pr_title] completes + runs-on: ubuntu-latest + steps: + - uses: GetStream/verify-semantic-changelog-update@main + with: + scopes: | + { + "llc": "packages/stream_chat", + "ui": "packages/stream_chat_flutter", + "core": "packages/stream_chat_flutter_core", + "localization": "packages/stream_chat_flutter_localizations", + "persistence": "packages/stream_chat_persistence" + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 4aaef416bf349306079a78f5366bf3cf8f373209 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Wed, 18 Aug 2021 18:57:48 +0530 Subject: [PATCH 72/99] Update .github/workflows/pr_title.yml --- .github/workflows/pr_title.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml index d3c6122c..4e7c3b5f 100644 --- a/.github/workflows/pr_title.yml +++ b/.github/workflows/pr_title.yml @@ -1,4 +1,4 @@ -name: 'PR Title is Conventional and Semantic' +name: 'PR is Conventional and Semantic' on: pull_request_target: types: From b3542ffb78004a6e34be2b95fae6ccf9805b57b7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 11:34:22 +0200 Subject: [PATCH 73/99] fix(ui): open `MessageListView` at a specific message --- .../lib/src/message_list_view.dart | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 75d45707..0feecf83 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -5,6 +5,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; import 'package:jiffy/jiffy.dart'; import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; @@ -454,7 +455,11 @@ class _MessageListViewState extends State { _inBetweenList = true; }, child: ScrollablePositionedList.separated( - key: ValueKey(initialIndex! + initialAlignment!), + key: (_upToDate || + initialIndex == null || + initialAlignment == null) + ? null + : ValueKey(initialIndex! + initialAlignment!), itemPositionsListener: _itemPositionListener, initialScrollIndex: initialIndex ?? 0, initialAlignment: initialAlignment ?? 0, @@ -1194,6 +1199,15 @@ class _MessageListViewState extends State { initialIndex = _initialIndex; initialAlignment = _initialAlignment; + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + if (initialIndex != null) { + _scrollController?.jumpTo( + index: initialIndex!, + alignment: initialAlignment ?? 0, + ); + } + }); + _messageNewListener = streamChannel!.channel.on(EventType.messageNew).listen((event) { if (_upToDate) { From d53f309a26ffd4b803e2eb0a4235a87f7208fca3 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 11:35:26 +0200 Subject: [PATCH 74/99] remove unused import --- packages/stream_chat_flutter/lib/src/message_list_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 0feecf83..ab333260 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -5,7 +5,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; import 'package:jiffy/jiffy.dart'; import 'package:rxdart/rxdart.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; From 44e4cb5d37656a7760c2c1ce6a2da28caf678ae7 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 11:39:12 +0200 Subject: [PATCH 75/99] update changelog --- packages/stream_chat_flutter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index b21acc7a..6d060d52 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -46,6 +46,7 @@ breakdown: - Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. - Fixed date dividers position/alignment in non reversed `MessageListView`. +- Fixed `MessageListView` not opening to the right initialMessage if `StreamChannel.initialMessageId` is set. ## 2.1.2 From 819abd091e418117b3f052ea77c345bdbc25dc10 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 11:43:25 +0200 Subject: [PATCH 76/99] fix format --- .../lib/src/stream_chat_localizations_hi.dart | 4 ++-- .../lib/src/stream_chat_localizations_ja.dart | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart index 11d7d486..247b90f8 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_hi.dart @@ -340,10 +340,10 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { String get sendLabel => 'भेजें'; @override - String get withText => 'विद';//TODO: break? + String get withText => 'विद'; //TODO: break? @override - String get inText => 'इन';//TODO: break? + String get inText => 'इन'; //TODO: break? @override String get youText => 'आप'; diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index e8d9759e..5510a2d8 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -85,8 +85,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { String get emptyChatMessagesText => 'チャットがありませんが。。。'; @override - String threadSeparatorText(int replyCount)=> '$replyCount件の返信'; - + String threadSeparatorText(int replyCount) => '$replyCount件の返信'; @override String get connectedLabel => '接続しています'; From a93b585d61e75b5b7675fbb6a9c1a9dbbf86af91 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 11:44:23 +0200 Subject: [PATCH 77/99] fix analysis --- .../lib/src/stream_chat_localizations_ja.dart | 3 ++- .../lib/src/stream_chat_localizations_ko.dart | 15 +++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index 5510a2d8..f61fcc4f 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -331,7 +331,8 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String get youText => 'あなた'; - // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude + // This is the word for 'customer' or 'user' because saying 'you' directly + //is too informal and rude @override String galleryPaginationText({ diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index dbd9609d..5cc278f7 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -85,9 +85,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get emptyChatMessagesText => '아직 채팅이 없습니다...'; @override - String threadSeparatorText(int replyCount) { - return '$replyCount개의 답장'; - } + String threadSeparatorText(int replyCount) => '$replyCount개의 답장'; @override String get connectedLabel => '연결중'; @@ -283,14 +281,10 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get tryAgainLabel => '다시 시도합니다'; @override - String membersCountText(int count) { - return '$count명'; - } + String membersCountText(int count) => '$count명'; @override - String watchersCountText(int count) { - return '$count명이 온라인'; - } + String watchersCountText(int count) => '$count명이 온라인'; @override String get viewInfoLabel => '정보를 보기'; @@ -336,7 +330,8 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { @override String get youText => '당신'; - // This is the word for 'customer' or 'user' because saying 'you' directly is too informal and rude + // This is the word for 'customer' or 'user' because saying 'you' directly + // is too informal and rude @override String galleryPaginationText( From 894802502a82d03a46c579c046eaffb97725e901 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 12:16:55 +0200 Subject: [PATCH 78/99] update readme and example --- packages/stream_chat_localizations/README.md | 6 ++++++ .../stream_chat_localizations/example/lib/add_new_lang.dart | 3 +++ packages/stream_chat_localizations/example/lib/main.dart | 3 +++ .../example/lib/override_lang.dart | 3 +++ 4 files changed, 15 insertions(+) diff --git a/packages/stream_chat_localizations/README.md b/packages/stream_chat_localizations/README.md index c2ea8a72..131d6b13 100644 --- a/packages/stream_chat_localizations/README.md +++ b/packages/stream_chat_localizations/README.md @@ -35,6 +35,8 @@ At the moment we support the following languages: - [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart) - [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart) - [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) +- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) +- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages. @@ -70,6 +72,8 @@ class MyApp extends StatelessWidget { Locale('fr'), Locale('it'), Locale('es'), + Locale('ja'), + Locale('ko'), ], // Add GlobalStreamChatLocalizations.delegates localizationsDelegates: GlobalStreamChatLocalizations.delegates, @@ -113,6 +117,8 @@ Example: fr it es + ja + ko ``` diff --git a/packages/stream_chat_localizations/example/lib/add_new_lang.dart b/packages/stream_chat_localizations/example/lib/add_new_lang.dart index 2f373691..a64717d3 100644 --- a/packages/stream_chat_localizations/example/lib/add_new_lang.dart +++ b/packages/stream_chat_localizations/example/lib/add_new_lang.dart @@ -456,6 +456,9 @@ class MyApp extends StatelessWidget { Locale('hi'), Locale('fr'), Locale('it'), + Locale('es'), + Locale('ja'), + Locale('ko'), // Add support for additional 'nn' locale Locale('nn'), ], diff --git a/packages/stream_chat_localizations/example/lib/main.dart b/packages/stream_chat_localizations/example/lib/main.dart index 818086df..76194992 100644 --- a/packages/stream_chat_localizations/example/lib/main.dart +++ b/packages/stream_chat_localizations/example/lib/main.dart @@ -73,6 +73,9 @@ class MyApp extends StatelessWidget { Locale('hi'), Locale('fr'), Locale('it'), + Locale('es'), + Locale('ja'), + Locale('ko'), ], // Add GlobalStreamChatLocalizations.delegates localizationsDelegates: GlobalStreamChatLocalizations.delegates, diff --git a/packages/stream_chat_localizations/example/lib/override_lang.dart b/packages/stream_chat_localizations/example/lib/override_lang.dart index 0e45019a..8eafd257 100644 --- a/packages/stream_chat_localizations/example/lib/override_lang.dart +++ b/packages/stream_chat_localizations/example/lib/override_lang.dart @@ -98,6 +98,9 @@ class MyApp extends StatelessWidget { Locale('hi'), Locale('fr'), Locale('it'), + Locale('es'), + Locale('ja'), + Locale('ko'), ], // Add overridden "CustomStreamChatLocalizationsEn.delegate" along with // "GlobalStreamChatLocalizations.delegates" From 5bda5db70599e8ef4d402264cf04e518c83a8f33 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Thu, 19 Aug 2021 12:17:56 +0200 Subject: [PATCH 79/99] update changelog --- packages/stream_chat_localizations/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/stream_chat_localizations/CHANGELOG.md b/packages/stream_chat_localizations/CHANGELOG.md index 865741c4..a1ae75b0 100644 --- a/packages/stream_chat_localizations/CHANGELOG.md +++ b/packages/stream_chat_localizations/CHANGELOG.md @@ -1,6 +1,8 @@ ## Upcoming * Added support for [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) locale. +* Added support for [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) locale. +* Added support for [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) locale. ## 1.0.2 From b920919e0f872ea9d808cfe15156cc5d1ba0bb7a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Aug 2021 17:20:59 +0530 Subject: [PATCH 80/99] added tests --- .../test/src/api/channel_test.dart | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 7c5386c6..6afa60c2 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -1859,6 +1859,52 @@ void main() { ).called(1); }); + test('`.enableSlowMode`', () async { + final channelModel = ChannelModel( + cid: channelCid, + cooldown: 10, + ); + + when(() => client.enableSlowdown( + channelCid, + channelType, + 10, + )).thenAnswer((_) async => PartialUpdateChannelResponse() + ..channel = channelModel); + + final res = await channel.enableSlowMode(cooldownInterval: 10); + + expect(res, isNotNull); + + verify(() => client.enableSlowdown( + channelCid, + channelType, + any(), + )).called(1); + }); + + test('`.disableSlowMode`', () async { + final channelModel = ChannelModel( + cid: channelCid, + cooldown: 0, + ); + + when(() => client.disableSlowdown( + channelCid, + channelType, + )).thenAnswer((_) async => PartialUpdateChannelResponse() + ..channel = channelModel); + + final res = await channel.disableSlowMode(); + + expect(res, isNotNull); + + verify(() => client.disableSlowdown( + channelCid, + channelType, + )).called(1); + }); + test('`.banUser`', () async { const userId = 'test-user-id'; const options = {'key': 'value'}; From ddf33a19897641d874dd716e500565887e5b235a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Aug 2021 17:50:37 +0530 Subject: [PATCH 81/99] added tests --- .../test/src/api/channel_test.dart | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 6afa60c2..08ebd091 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -1860,15 +1860,17 @@ void main() { }); test('`.enableSlowMode`', () async { + const cooldown = 10; + final channelModel = ChannelModel( cid: channelCid, - cooldown: 10, + cooldown: cooldown, ); when(() => client.enableSlowdown( - channelCid, + channelId, channelType, - 10, + cooldown, )).thenAnswer((_) async => PartialUpdateChannelResponse() ..channel = channelModel); @@ -1877,32 +1879,28 @@ void main() { expect(res, isNotNull); verify(() => client.enableSlowdown( - channelCid, + channelId, channelType, - any(), + cooldown, )).called(1); }); test('`.disableSlowMode`', () async { final channelModel = ChannelModel( cid: channelCid, - cooldown: 0, ); when(() => client.disableSlowdown( - channelCid, - channelType, - )).thenAnswer((_) async => PartialUpdateChannelResponse() + channelId, + channelType, + )).thenAnswer((_) async => PartialUpdateChannelResponse() ..channel = channelModel); final res = await channel.disableSlowMode(); expect(res, isNotNull); - verify(() => client.disableSlowdown( - channelCid, - channelType, - )).called(1); + verify(() => client.disableSlowdown(channelId, channelType)).called(1); }); test('`.banUser`', () async { From 5cd59f2277431cf2c8842a0e82702531bee485b3 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Aug 2021 18:03:34 +0530 Subject: [PATCH 82/99] fix: timer dispose, added widget test --- .../lib/src/message_input.dart | 5 +- .../test/src/message_input_test.dart | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 7b6d2936..e97e1364 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -318,6 +318,8 @@ class MessageInputState extends State { late DateTime? _cooldownStartedAt; int? _timeOut; + Timer? slowModeTimer; + @override void initState() { super.initState(); @@ -359,7 +361,7 @@ class MessageInputState extends State { StreamChannel.of(context).channel.cooldown!) { _timeOut = StreamChannel.of(context).channel.cooldown! - DateTime.now().difference(_cooldownStartedAt!).inSeconds; - Timer.periodic(const Duration(seconds: 1), (timer) { + slowModeTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_timeOut == 0) { timer.cancel(); } else { @@ -2265,6 +2267,7 @@ class MessageInputState extends State { _emojiOverlay?.remove(); _mentionsOverlay?.remove(); _keyboardListener?.cancel(); + slowModeTimer?.cancel(); super.dispose(); } diff --git a/packages/stream_chat_flutter/test/src/message_input_test.dart b/packages/stream_chat_flutter/test/src/message_input_test.dart index 679fb7f3..62fe0107 100644 --- a/packages/stream_chat_flutter/test/src/message_input_test.dart +++ b/packages/stream_chat_flutter/test/src/message_input_test.dart @@ -69,4 +69,69 @@ void main() { expect(find.byKey(const Key('messageInputText')), findsOneWidget); }, ); + + testWidgets( + 'checks message input slow mode', + (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); + final channel = MockChannel(); + final channelState = MockChannelState(); + final lastMessageAt = DateTime.parse('2020-06-22 12:00:00'); + + when(() => client.state).thenReturn(clientState); + when(() => clientState.currentUser).thenReturn(OwnUser(id: 'user-id')); + when(() => channel.lastMessageAt).thenReturn(lastMessageAt); + when(() => channel.state).thenReturn(channelState); + when(() => channel.cooldown).thenReturn(10); + when(() => channel.cooldownStartedAt).thenReturn(DateTime.now()); + when(() => channel.client).thenReturn(client); + when(() => channel.isMuted).thenReturn(false); + when(() => channel.isMutedStream).thenAnswer((i) => Stream.value(false)); + when(() => channel.extraDataStream).thenAnswer((i) => Stream.value({ + 'name': 'test', + })); + when(() => channel.extraData).thenReturn({ + 'name': 'test', + }); + when(() => channelState.membersStream).thenAnswer((i) => Stream.value([ + Member( + userId: 'user-id', + user: User(id: 'user-id'), + ) + ])); + when(() => channelState.members).thenReturn([ + Member( + userId: 'user-id', + user: User(id: 'user-id'), + ), + ]); + when(() => channelState.messages).thenReturn([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ]); + when(() => channelState.messagesStream).thenAnswer((i) => Stream.value([ + Message( + text: 'hello', + user: User(id: 'other-user'), + ) + ])); + + await tester.pumpWidget(MaterialApp( + home: StreamChat( + client: client, + child: StreamChannel( + channel: channel, + child: const Scaffold( + body: MessageInput(), + ), + ), + ), + )); + + expect(find.text('Slow mode ON'), findsOneWidget); + }, + ); } From 4cec36a7231bf39fc30523855d43f976a9e8349a Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Thu, 19 Aug 2021 18:13:18 +0530 Subject: [PATCH 83/99] fix: analysis --- packages/stream_chat_flutter/lib/src/message_input.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index e97e1364..de7c2788 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -318,7 +318,7 @@ class MessageInputState extends State { late DateTime? _cooldownStartedAt; int? _timeOut; - Timer? slowModeTimer; + Timer? _slowModeTimer; @override void initState() { @@ -361,7 +361,7 @@ class MessageInputState extends State { StreamChannel.of(context).channel.cooldown!) { _timeOut = StreamChannel.of(context).channel.cooldown! - DateTime.now().difference(_cooldownStartedAt!).inSeconds; - slowModeTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + _slowModeTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_timeOut == 0) { timer.cancel(); } else { @@ -2267,7 +2267,7 @@ class MessageInputState extends State { _emojiOverlay?.remove(); _mentionsOverlay?.remove(); _keyboardListener?.cancel(); - slowModeTimer?.cancel(); + _slowModeTimer?.cancel(); super.dispose(); } From 5ecbfa4ac8248fb10595eee4a86c7c071c1310ab Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Aug 2021 10:21:13 +0200 Subject: [PATCH 84/99] move comments --- .../lib/src/stream_chat_localizations_ja.dart | 4 ++-- .../lib/src/stream_chat_localizations_ko.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index f61fcc4f..e6946125 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -329,10 +329,10 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String get inText => 'に'; - @override - String get youText => 'あなた'; // This is the word for 'customer' or 'user' because saying 'you' directly //is too informal and rude + @override + String get youText => 'あなた'; @override String galleryPaginationText({ diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index 5cc278f7..2642b991 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -328,10 +328,10 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { @override String get inText => '에'; - @override - String get youText => '당신'; // This is the word for 'customer' or 'user' because saying 'you' directly // is too informal and rude + @override + String get youText => '당신'; @override String galleryPaginationText( From 26407a0f15567f9b1c2699b242181397b8d08bf4 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Aug 2021 11:03:04 +0200 Subject: [PATCH 85/99] rename test folder --- packages/stream_chat/test/src/{api => client}/channel_test.dart | 0 packages/stream_chat/test/src/{api => client}/client_test.dart | 0 .../stream_chat/test/src/{api => client}/retry_queue_test.dart | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename packages/stream_chat/test/src/{api => client}/channel_test.dart (100%) rename packages/stream_chat/test/src/{api => client}/client_test.dart (100%) rename packages/stream_chat/test/src/{api => client}/retry_queue_test.dart (100%) diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/client/channel_test.dart similarity index 100% rename from packages/stream_chat/test/src/api/channel_test.dart rename to packages/stream_chat/test/src/client/channel_test.dart diff --git a/packages/stream_chat/test/src/api/client_test.dart b/packages/stream_chat/test/src/client/client_test.dart similarity index 100% rename from packages/stream_chat/test/src/api/client_test.dart rename to packages/stream_chat/test/src/client/client_test.dart diff --git a/packages/stream_chat/test/src/api/retry_queue_test.dart b/packages/stream_chat/test/src/client/retry_queue_test.dart similarity index 100% rename from packages/stream_chat/test/src/api/retry_queue_test.dart rename to packages/stream_chat/test/src/client/retry_queue_test.dart From 6cf63fe3ca899bf8606830e26b9c549f2141ef61 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Aug 2021 16:10:01 +0530 Subject: [PATCH 86/99] added tests --- .../test/src/core/api/channel_api_test.dart | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/packages/stream_chat/test/src/core/api/channel_api_test.dart b/packages/stream_chat/test/src/core/api/channel_api_test.dart index 8ffd778d..8dd6a3f4 100644 --- a/packages/stream_chat/test/src/core/api/channel_api_test.dart +++ b/packages/stream_chat/test/src/core/api/channel_api_test.dart @@ -605,4 +605,69 @@ void main() { verify(() => client.post(path, data: {})).called(1); verifyNoMoreInteractions(client); }); + + test('enableSlowdown', () async { + const channelId = 'test-channel-id'; + const channelType = 'test-channel-type'; + const cooldown = 10; + const set = { + 'ccooldown': 10, + }; + + final path = _getChannelUrl(channelId, channelType); + + final channelModel = ChannelModel( + id: channelId, + type: channelType, + extraData: set, + ); + + when(() => client.patch(path, data: { + 'set': { + 'cooldown': cooldown, + }, + })).thenAnswer((_) async => successResponse(path, data: { + 'channel': channelModel.toJson(), + })); + + final res = + await channelApi.enableSlowdown(channelId, channelType, cooldown); + + expect(res, isNotNull); + + verify(() => client.patch(path, data: { + 'set': { + 'cooldown': cooldown, + }, + })).called(1); + verifyNoMoreInteractions(client); + }); + + test('disableSlowdown', () async { + const channelId = 'test-channel-id'; + const channelType = 'test-channel-type'; + const unset = ['cooldown']; + + final path = _getChannelUrl(channelId, channelType); + + final channelModel = ChannelModel( + id: channelId, + type: channelType, + ); + + when(() => client.patch(path, data: { + 'unset': unset, + })).thenAnswer((_) async => successResponse(path, data: { + 'channel': channelModel.toJson(), + })); + + final res = await channelApi.disableSlowdown(channelId, channelType); + + expect(res, isNotNull); + + verify(() => client.patch(path, data: { + 'unset': unset, + })).called(1); + verifyNoMoreInteractions(client); + }); } From feac07057a45e5d70851c1b5f7ec423ec2ce4c67 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Aug 2021 16:10:48 +0530 Subject: [PATCH 87/99] removed comments --- .../lib/src/message_input.dart | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index de7c2788..7c67c4d3 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -536,36 +536,10 @@ class MessageInputState extends State { : _buildSendButton(context); } - /*if (_timeOut == null || _timeOut == 0) { - sendButton = widget.activeSendButton != null - ? InkWell( - onTap: sendMessage, - child: widget.activeSendButton, - ) - : _buildSendButton(context); - } else { - sendButton = _CountdownButton( - count: _timeOut!, - ); - } - - if (!_messageIsPresent && _attachments.isEmpty) { - sendButton = widget.idleSendButton ?? _buildIdleSendButton(context); - }*/ - return AnimatedSwitcher( duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!, child: sendButton, ); - /*return AnimatedCrossFade( - crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: sendButton, - secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), - duration: _messageInputTheme.sendAnimationDuration!, - alignment: Alignment.center, - );*/ } Widget _buildExpandActionsButton(BuildContext context) { From f90dc4127d43a2562a9d353328a494fa2bbd0192 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 20 Aug 2021 16:13:27 +0530 Subject: [PATCH 88/99] refactor!(core): Refactor BetterStreamBuilder. 1. BREAKING: Renamed `BetterStreamBuilder.loadingBuilder` to `.noDataBuilder`. 2. BREAKING: Added non-null constraint on `BetterStreamBuilder`. 3. `BetterStreamBuilder.initialData` is now nullable/not-required. Signed-off-by: xsahil03x --- .../stream_chat_flutter_core/CHANGELOG.md | 6 +++ .../lib/src/better_stream_builder.dart | 39 +++++++++++-------- .../lib/src/channel_list_core.dart | 16 +++----- .../lib/src/message_list_core.dart | 6 +-- .../lib/src/message_search_list_core.dart | 14 +++---- .../lib/src/user_list_core.dart | 13 ++----- 6 files changed, 46 insertions(+), 48 deletions(-) diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index 65280674..ad331bc2 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -1,5 +1,11 @@ ## Upcoming +🛑️ Breaking Changes from `2.1.1` +- Renamed `BetterStreamBuilder.loadingBuilder` to `.noDataBuilder` + +🔄 Changed +- `BetterStreamBuilder.initialData` is now nullable/not-required. + 🐞 Fixed - [#612](https://github.com/GetStream/stream-chat-flutter/issues/612) `ChannelListView` pagination doesn't work after refresh diff --git a/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart b/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart index 871a8a1d..3c456246 100644 --- a/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart +++ b/packages/stream_chat_flutter_core/lib/src/better_stream_builder.dart @@ -6,23 +6,23 @@ import 'package:flutter/widgets.dart'; /// It requires [initialData] and will rebuild /// only when the new data is different than the current data /// The [comparator] is used to check if the new data is different -class BetterStreamBuilder extends StatefulWidget { +class BetterStreamBuilder extends StatefulWidget { /// Creates a new BetterStreamBuilder const BetterStreamBuilder({ required this.stream, - required this.initialData, required this.builder, - this.loadingBuilder, + this.initialData, + this.noDataBuilder, this.errorBuilder, this.comparator, Key? key, }) : super(key: key); /// The stream to listen to - final Stream? stream; + final Stream? stream; /// The initial data available - final T initialData; + final T? initialData; /// Comparator used to check if the new data is different than the last one final bool Function(T?, T?)? comparator; @@ -31,7 +31,7 @@ class BetterStreamBuilder extends StatefulWidget { final Widget Function(BuildContext context, T data) builder; /// Builder that builds when the data is null - final Widget Function(BuildContext context)? loadingBuilder; + final Widget Function(BuildContext context)? noDataBuilder; /// Builder used when there is an error final Widget Function(BuildContext context, Object error)? errorBuilder; @@ -40,21 +40,26 @@ class BetterStreamBuilder extends StatefulWidget { _BetterStreamBuilderState createState() => _BetterStreamBuilderState(); } -class _BetterStreamBuilderState extends State> { +class _BetterStreamBuilderState + extends State> { T? _lastEvent; - StreamSubscription? _subscription; + StreamSubscription? _subscription; Object? _lastError; @override Widget build(BuildContext context) { - if (_lastError != null) { - return widget.errorBuilder!(context, _lastError!); + final error = _lastError; + if (error != null) { + final errorBuilder = widget.errorBuilder; + if (errorBuilder != null) { + return errorBuilder(context, error); + } } - - if (_lastEvent == null) { - return widget.loadingBuilder?.call(context) ?? const Offstage(); + final event = _lastEvent; + if (event == null) { + return widget.noDataBuilder?.call(context) ?? const Offstage(); } - return widget.builder(context, _lastEvent ?? widget.initialData); + return widget.builder(context, event); } @override @@ -87,22 +92,22 @@ class _BetterStreamBuilderState extends State> { void _onError(error) { if (widget.errorBuilder != null && error != _lastError) { + _lastError = error; if (mounted) { setState(() {}); } - _lastError = error; } } - void _onEvent(T event) { + void _onEvent(T? event) { _lastError = null; final isEqual = widget.comparator?.call(_lastEvent, event) ?? event == _lastEvent; if (!isEqual) { + _lastEvent = event; if (mounted) { setState(() {}); } - _lastEvent = event; } } } diff --git a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart index c59b2030..c5d3f69a 100644 --- a/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/channel_list_core.dart @@ -4,6 +4,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/better_stream_builder.dart'; import 'package:stream_chat_flutter_core/src/channels_bloc.dart'; import 'package:stream_chat_flutter_core/src/stream_chat_core.dart'; import 'package:stream_chat_flutter_core/src/typedef.dart'; @@ -137,19 +138,14 @@ class ChannelListCoreState extends State { @override Widget build(BuildContext context) => _buildListView(_channelsBloc); - StreamBuilder> _buildListView( + BetterStreamBuilder> _buildListView( ChannelsBlocState channelsBlocState, ) => - StreamBuilder>( + BetterStreamBuilder>( stream: channelsBlocState.channelsStream, - builder: (context, snapshot) { - if (snapshot.hasError) { - return widget.errorBuilder(context, snapshot.error!); - } - if (!snapshot.hasData) { - return widget.loadingBuilder(context); - } - final channels = snapshot.data!; + errorBuilder: widget.errorBuilder, + noDataBuilder: widget.loadingBuilder, + builder: (context, channels) { if (channels.isEmpty) { return widget.emptyBuilder(context); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index d3d69dfb..b9b423ce 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -138,7 +138,7 @@ class MessageListCoreState extends State { return true; } - return BetterStreamBuilder?>( + return BetterStreamBuilder>( initialData: initialData, comparator: const ListEquality().equals, stream: messagesStream!.map( @@ -148,9 +148,9 @@ class MessageListCoreState extends State { ), ), errorBuilder: widget.errorBuilder, - loadingBuilder: widget.loadingBuilder, + noDataBuilder: widget.loadingBuilder, builder: (context, data) { - final messageList = data?.reversed.toList(growable: false) ?? []; + final messageList = data.reversed.toList(growable: false); if (messageList.isEmpty && !_isThreadConversation) { if (_upToDate) { return widget.emptyBuilder(context); diff --git a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart index 4901c332..234b5c9a 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_search_list_core.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_flutter_core/src/better_stream_builder.dart'; import 'package:stream_chat_flutter_core/src/message_search_bloc.dart'; import 'package:stream_chat_flutter_core/src/typedef.dart'; @@ -132,16 +133,11 @@ class MessageSearchListCoreState extends State { Widget build(BuildContext context) => _buildListView(_messageSearchBloc!); Widget _buildListView(MessageSearchBlocState messageSearchBloc) => - StreamBuilder>( + BetterStreamBuilder>( stream: messageSearchBloc.messagesStream, - builder: (context, snapshot) { - if (snapshot.hasError) { - return widget.errorBuilder(context, snapshot.error!); - } - if (!snapshot.hasData) { - return widget.loadingBuilder(context); - } - final items = snapshot.data!; + errorBuilder: widget.errorBuilder, + noDataBuilder: widget.loadingBuilder, + builder: (context, items) { if (items.isEmpty) { return widget.emptyBuilder(context); } diff --git a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart index a45aa904..57d61fe6 100644 --- a/packages/stream_chat_flutter_core/lib/src/user_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/user_list_core.dart @@ -176,16 +176,11 @@ class UserListCoreState extends State }, ); - StreamBuilder> _buildListView() => StreamBuilder( + BetterStreamBuilder> _buildListView() => BetterStreamBuilder( stream: _buildUserStream(), - builder: (context, snapshot) { - if (snapshot.hasError) { - return widget.errorBuilder(context, snapshot.error!); - } - if (!snapshot.hasData) { - return widget.loadingBuilder(context); - } - final items = snapshot.data!; + errorBuilder: widget.errorBuilder, + noDataBuilder: widget.loadingBuilder, + builder: (context, items) { if (items.isEmpty) { return widget.emptyBuilder(context); } From b7ba8b5e854ce9d6ccbb6a77670d865200ef091f Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Aug 2021 16:13:46 +0530 Subject: [PATCH 89/99] fixed test --- .../test/src/core/api/channel_api_test.dart | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/stream_chat/test/src/core/api/channel_api_test.dart b/packages/stream_chat/test/src/core/api/channel_api_test.dart index 8dd6a3f4..9110845d 100644 --- a/packages/stream_chat/test/src/core/api/channel_api_test.dart +++ b/packages/stream_chat/test/src/core/api/channel_api_test.dart @@ -611,7 +611,7 @@ void main() { const channelType = 'test-channel-type'; const cooldown = 10; const set = { - 'ccooldown': 10, + 'cooldown': 10, }; final path = _getChannelUrl(channelId, channelType); @@ -623,9 +623,7 @@ void main() { ); when(() => client.patch(path, data: { - 'set': { - 'cooldown': cooldown, - }, + 'set': set, })).thenAnswer((_) async => successResponse(path, data: { 'channel': channelModel.toJson(), })); @@ -636,9 +634,7 @@ void main() { expect(res, isNotNull); verify(() => client.patch(path, data: { - 'set': { - 'cooldown': cooldown, - }, + 'set': set, })).called(1); verifyNoMoreInteractions(client); }); From 08c2a2a8863fb1e90ce80dfa34db3678fe839559 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 20 Aug 2021 16:14:07 +0530 Subject: [PATCH 90/99] refactor(ui): update core dependency Signed-off-by: xsahil03x --- packages/stream_chat_flutter/CHANGELOG.md | 5 ++++- .../lib/src/channel_preview.dart | 17 +++++++---------- .../lib/src/connection_status_builder.dart | 2 +- .../lib/src/unread_indicator.dart | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index b21acc7a..acc93337 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -42,9 +42,12 @@ breakdown: * `MessageTheme` is now `MessageThemeData` * `UserListViewTheme` is now `UserListViewThemeData` +- Updated core dependency. + 🐞 Fixed -- Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. +- Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the + camera is null. - Fixed date dividers position/alignment in non reversed `MessageListView`. ## 2.1.2 diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index e01cd008..f3984ab9 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -94,13 +94,13 @@ class ChannelPreview extends StatelessWidget { textStyle: channelPreviewTheme.titleStyle, ), ), - BetterStreamBuilder?>( + BetterStreamBuilder>( stream: channel.state?.membersStream, initialData: channel.state?.members, comparator: const ListEquality().equals, builder: (context, members) { - if (members?.isEmpty == true || - members?.any((Member e) => + if (members.isEmpty || + members.any((Member e) => e.user!.id == channel.client.state.currentUser?.id) != true) { @@ -153,13 +153,10 @@ class ChannelPreview extends StatelessWidget { )); } - Widget _buildDate(BuildContext context) => BetterStreamBuilder( + Widget _buildDate(BuildContext context) => BetterStreamBuilder( stream: channel.lastMessageAtStream, initialData: channel.lastMessageAt, builder: (context, data) { - if (data == null) { - return const Offstage(); - } final lastMessageAt = data.toLocal(); String stringDate; @@ -213,12 +210,12 @@ class ChannelPreview extends StatelessWidget { Widget _buildLastMessage(BuildContext context) => Align( alignment: Alignment.centerLeft, - child: BetterStreamBuilder?>( + child: BetterStreamBuilder>( stream: channel.state!.messagesStream, initialData: channel.state!.messages, builder: (context, data) { - final lastMessage = data - ?.lastWhereOrNull((m) => m.shadowed != true && !m.isDeleted); + final lastMessage = + data.lastWhereOrNull((m) => !m.shadowed && !m.isDeleted); if (lastMessage == null) { return const SizedBox(); } diff --git a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart index fbe7ffae..2cba8eb4 100644 --- a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart +++ b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart @@ -38,7 +38,7 @@ class ConnectionStatusBuilder extends StatelessWidget { return BetterStreamBuilder( initialData: client.wsConnectionStatus, stream: stream, - loadingBuilder: loadingBuilder, + noDataBuilder: loadingBuilder, errorBuilder: (context, error) { if (errorBuilder != null) { return errorBuilder!(context, error); diff --git a/packages/stream_chat_flutter/lib/src/unread_indicator.dart b/packages/stream_chat_flutter/lib/src/unread_indicator.dart index 381bad39..e5f3027b 100644 --- a/packages/stream_chat_flutter/lib/src/unread_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/unread_indicator.dart @@ -17,7 +17,7 @@ class UnreadIndicator extends StatelessWidget { Widget build(BuildContext context) { final client = StreamChat.of(context).client; return IgnorePointer( - child: BetterStreamBuilder( + child: BetterStreamBuilder( stream: cid != null ? client.state.channels[cid]?.state?.unreadCountStream : client.state.totalUnreadCountStream, @@ -25,7 +25,7 @@ class UnreadIndicator extends StatelessWidget { ? client.state.channels[cid]?.state?.unreadCount : client.state.totalUnreadCount, builder: (context, data) { - if (data == null || data == 0) { + if (data == 0) { return const Offstage(); } return Material( From fea90d4afdbc25151678ab2dd71266a53b067c5d Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Fri, 20 Aug 2021 16:20:56 +0530 Subject: [PATCH 91/99] added japanese and korean localizations --- .../lib/src/stream_chat_localizations_ja.dart | 3 +++ .../lib/src/stream_chat_localizations_ko.dart | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart index e6946125..21fc48fa 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart @@ -346,4 +346,7 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => 'メッセージに返信'; + + @override + String get slowModeOnLabel => 'スローモードオン'; } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index 2642b991..a933ddb0 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -344,4 +344,7 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { @override String get replyToMessageLabel => '메시지에 회신합니다.'; + + @override + String get slowModeOnLabel => '느린 모드 켜짐'; } From 071b337194dedaea4999d4d2e9f9bb9de29b6d5d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Aug 2021 14:40:41 +0200 Subject: [PATCH 92/99] call streamchannel.of just once --- packages/stream_chat_flutter/lib/src/message_input.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 7c67c4d3..388df21b 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -355,11 +355,12 @@ class MessageInputState extends State { } void _startSlowMode() { - if (StreamChannel.of(context).channel.cooldownStartedAt != null) { - _cooldownStartedAt = StreamChannel.of(context).channel.cooldownStartedAt; + final channel = StreamChannel.of(context).channel; + if (channel.cooldownStartedAt != null) { + _cooldownStartedAt = channel.cooldownStartedAt; if (DateTime.now().difference(_cooldownStartedAt!).inSeconds < - StreamChannel.of(context).channel.cooldown!) { - _timeOut = StreamChannel.of(context).channel.cooldown! - + channel.cooldown!) { + _timeOut = channel.cooldown! - DateTime.now().difference(_cooldownStartedAt!).inSeconds; _slowModeTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_timeOut == 0) { From ed6c87ef494e164e0808f659a802f342e039b7cd Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 20 Aug 2021 19:16:23 +0530 Subject: [PATCH 93/99] refactor(ui): make initialIndex, initialAlignment non nullable Signed-off-by: xsahil03x --- .../lib/src/message_list_view.dart | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index ab333260..a8296231 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -298,8 +298,9 @@ class _MessageListViewState extends State { StreamChannelState? streamChannel; late StreamChatThemeData _streamTheme; - int? get _initialIndex { - if (widget.initialScrollIndex != null) return widget.initialScrollIndex; + int get _initialIndex { + final initialScrollIndex = widget.initialScrollIndex; + if (initialScrollIndex != null) return initialScrollIndex; if (streamChannel!.initialMessageId != null) { final messages = streamChannel!.channel.state!.messages; final totalMessages = messages.length; @@ -312,8 +313,9 @@ class _MessageListViewState extends State { return 0; } - double? get _initialAlignment { - if (widget.initialAlignment != null) return widget.initialAlignment; + double get _initialAlignment { + final initialAlignment = widget.initialAlignment; + if (initialAlignment != null) return initialAlignment; return 0; } @@ -326,8 +328,8 @@ class _MessageListViewState extends State { bool _topPaginationActive = false; bool _bottomPaginationActive = false; - int? initialIndex; - double? initialAlignment; + int initialIndex = 0; + double initialAlignment = 0; List messages = []; @@ -454,14 +456,12 @@ class _MessageListViewState extends State { _inBetweenList = true; }, child: ScrollablePositionedList.separated( - key: (_upToDate || - initialIndex == null || - initialAlignment == null) + key: _upToDate ? null - : ValueKey(initialIndex! + initialAlignment!), + : ValueKey(initialIndex + initialAlignment), itemPositionsListener: _itemPositionListener, - initialScrollIndex: initialIndex ?? 0, - initialAlignment: initialAlignment ?? 0, + initialScrollIndex: initialIndex, + initialAlignment: initialAlignment, physics: widget.scrollPhysics, itemScrollController: _scrollController, reverse: widget.reverse, @@ -1199,12 +1199,10 @@ class _MessageListViewState extends State { initialAlignment = _initialAlignment; WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { - if (initialIndex != null) { - _scrollController?.jumpTo( - index: initialIndex!, - alignment: initialAlignment ?? 0, - ); - } + _scrollController?.jumpTo( + index: initialIndex, + alignment: initialAlignment, + ); }); _messageNewListener = From 162a144d976c23b38228d00f61e0140b9738c043 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Aug 2021 15:56:18 +0200 Subject: [PATCH 94/99] fix(docs): update `Adding custom attachment guide` with updated code --- .../guides/adding_custom_attachments.mdx | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx b/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx index fb1f7bbe..9fe7f6aa 100644 --- a/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx +++ b/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx @@ -146,21 +146,25 @@ Next, we build the Static Maps URL (Add your API key before using the code snipp } ``` -And then modify the MessageListView and tell it how to build a location attachment: +And then modify the `MessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property: ```dart MessageListView( - customAttachmentBuilders: { - 'location': (context, message, attachments) { - var attachmentWidget = Image.network( - _buildMapAttachment( - attachments[0].extraData['latitude'], - attachments[0].extraData['longitude'], - ), - ); + messageBuilder: (context, details, messages, defaultMessage) { + return defaultMessage.copyWith( + customAttachmentBuilders: { + 'location': (context, message, attachments) { + final attachmentWidget = Image.network( + _buildMapAttachment( + attachments[0].extraData['latitude'], + attachments[0].extraData['longitude'], + ), + ); - return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); - } + return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0)); + } + }, + ); }, ), ``` From 80aaef037a8180c619ae75010397d784511f7029 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 20 Aug 2021 17:12:26 +0200 Subject: [PATCH 95/99] Update packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart --- .../lib/src/stream_chat_localizations_ko.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart index a933ddb0..49015674 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart @@ -346,5 +346,5 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { String get replyToMessageLabel => '메시지에 회신합니다.'; @override - String get slowModeOnLabel => '느린 모드 켜짐'; + String get slowModeOnLabel => '슬로모드 켜짐'; } From c0b80b84c602699d35f5a2b4d9cb03c8cfe12fcc Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Fri, 20 Aug 2021 17:31:08 +0200 Subject: [PATCH 96/99] fix: add null checks on message text --- packages/stream_chat_flutter/lib/src/message_list_view.dart | 2 +- packages/stream_chat_flutter/lib/src/message_widget.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 75d45707..9400a984 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -984,7 +984,7 @@ class _MessageListViewState extends State { final showInChannelIndicator = !_isThreadConversation && isThreadMessage; final showThreadReplyIndicator = !_isThreadConversation && hasReplies; - final isOnlyEmoji = message.text!.isOnlyEmoji; + final isOnlyEmoji = message.text?.isOnlyEmoji ?? false; final hasUrlAttachment = message.attachments.any((it) => it.ogScrapeUrl != null) == true; diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 19af5b2a..5bfa2b63 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -1258,7 +1258,7 @@ class _MessageWidgetState extends State ); Widget _buildTextBubble() { - if (widget.message.text!.trim().isEmpty) return const Offstage(); + if (widget.message.text?.trim().isEmpty ?? false) return const Offstage(); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ From eb468edf826f69567c9cd7c5649e1c54bc4c03f9 Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Fri, 20 Aug 2021 17:48:16 +0200 Subject: [PATCH 97/99] fix: add null checks to message text --- packages/stream_chat_flutter/lib/src/message_list_view.dart | 2 +- packages/stream_chat_flutter/lib/src/message_widget.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 9400a984..d5fc3671 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -845,7 +845,7 @@ class _MessageListViewState extends State { ) { final isMyMessage = message.user!.id == StreamChat.of(context).currentUser!.id; - final isOnlyEmoji = message.text!.isOnlyEmoji; + final isOnlyEmoji = message.text?.isOnlyEmoji ?? false; final currentUser = StreamChat.of(context).currentUser; final members = StreamChannel.of(context).channel.state?.members ?? []; final currentUserMember = diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 5bfa2b63..ca1aa0bf 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -1048,7 +1048,7 @@ class _MessageWidgetState extends State messageWidget: widget.copyWith( key: const Key('MessageWidget'), message: widget.message.copyWith( - text: widget.message.text!.length > 200 + text: (widget.message.text?.length ?? 0) > 200 ? '${widget.message.text!.substring(0, 200)}...' : widget.message.text, ), @@ -1111,7 +1111,7 @@ class _MessageWidgetState extends State messageWidget: widget.copyWith( key: const Key('MessageWidget'), message: widget.message.copyWith( - text: widget.message.text!.length > 200 + text: (widget.message.text?.length ?? 0) > 200 ? '${widget.message.text!.substring(0, 200)}...' : widget.message.text, ), From 0f8418dd29a660fe92fa91207371b3db75eda796 Mon Sep 17 00:00:00 2001 From: Deven Joshi Date: Mon, 23 Aug 2021 13:07:23 +0530 Subject: [PATCH 98/99] added changelog --- packages/stream_chat/CHANGELOG.md | 1 + packages/stream_chat_flutter/CHANGELOG.md | 2 ++ packages/stream_chat_localizations/CHANGELOG.md | 1 + 3 files changed, 4 insertions(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 52496a96..85bc73ef 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -10,6 +10,7 @@ - `User` and `OwnUser` classes now have a `name` property. Setting a name will also set the 'name' key on `extraData`, so `user.name` and `user.extraData['name']` is the same. - `Channel` class now has extra `image` getter and setter. As well as an `updateImage` to do a partial update after a channel has been initialized. - `Channel` class now has extra `name` getter and setter. As well as an `updateName` to do a partial update after a channel has been initialized. +- Added slow mode which allows a cooldown period after a user sends a message. ## 2.1.1 🐞 Fixed diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index b21acc7a..e9dfe04b 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -25,6 +25,8 @@ typedef ActionButtonBuilder = Widget Function( > **_NOTE:_** The last parameter is the default `ActionButton` You can call `.copyWith` to customize just a subset of properties. +- Added slow mode which allows a cooldown period after a user sends a message. + 🔄 Changed Theming has been upgraded! Most theme classes now have `InheritedTheme` classes associated with diff --git a/packages/stream_chat_localizations/CHANGELOG.md b/packages/stream_chat_localizations/CHANGELOG.md index d718ce12..8e13d154 100644 --- a/packages/stream_chat_localizations/CHANGELOG.md +++ b/packages/stream_chat_localizations/CHANGELOG.md @@ -5,6 +5,7 @@ * Added support for [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart) locale. * Added support for [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart) locale. * Added support for [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart) locale. +* Added strings for cooldown mode. 🔄 Changed From 93ce9201a998c22315e306bd412f878ce955447b Mon Sep 17 00:00:00 2001 From: Gordon Hayes Date: Mon, 23 Aug 2021 09:54:19 +0200 Subject: [PATCH 99/99] docs: update CHANGELOG.md --- packages/stream_chat_flutter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index acc93337..b2515712 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -49,6 +49,7 @@ breakdown: - Fixed `MessageInput` textField case where `input` is not enabled if the file picked from the camera is null. - Fixed date dividers position/alignment in non reversed `MessageListView`. +- Fixed null check errors when accessing `message.text` in `MessageWidget` and `MessageListView`; this occurred when sending a message with no text. ## 2.1.2