From f3ab200137aa6fe991ce657a1860513a588da11a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Fri, 17 Jun 2022 11:41:25 +0200 Subject: [PATCH] feat(ui, localizations): add unread messages label --- .../example/ios/Runner/Info.plist | 2 + .../lib/src/localization/translations.dart | 12 ++++ .../lib/src/message_list_view.dart | 69 +++++++++++++++++-- .../example/lib/add_new_lang.dart | 8 +++ .../lib/src/stream_chat_localizations_de.dart | 8 +++ .../lib/src/stream_chat_localizations_en.dart | 8 +++ .../lib/src/stream_chat_localizations_es.dart | 8 +++ .../lib/src/stream_chat_localizations_fr.dart | 8 +++ .../lib/src/stream_chat_localizations_hi.dart | 8 +++ .../lib/src/stream_chat_localizations_it.dart | 15 +++- .../lib/src/stream_chat_localizations_ja.dart | 8 +++ .../lib/src/stream_chat_localizations_ko.dart | 8 +++ .../lib/src/stream_chat_localizations_pt.dart | 8 +++ 13 files changed, 163 insertions(+), 7 deletions(-) diff --git a/packages/stream_chat_flutter/example/ios/Runner/Info.plist b/packages/stream_chat_flutter/example/ios/Runner/Info.plist index a74aeed0..299ebd4c 100644 --- a/packages/stream_chat_flutter/example/ios/Runner/Info.plist +++ b/packages/stream_chat_flutter/example/ios/Runner/Info.plist @@ -59,5 +59,7 @@ NSMicrophoneUsageDescription Explain why your app uses the mic + CADisableMinimumFrameDurationOnPhone + diff --git a/packages/stream_chat_flutter/lib/src/localization/translations.dart b/packages/stream_chat_flutter/lib/src/localization/translations.dart index 3f29704f..27094c80 100644 --- a/packages/stream_chat_flutter/lib/src/localization/translations.dart +++ b/packages/stream_chat_flutter/lib/src/localization/translations.dart @@ -77,6 +77,10 @@ abstract class Translations { /// contains a parent message String threadSeparatorText(int replyCount); + /// The text for showing the unread messages count + /// in the [StreamMessageListView] + String unreadMessagesSeparatorText(int unreadCount); + /// The label for "connected" in [StreamConnectionStatusBuilder] String get connectedLabel; @@ -711,4 +715,12 @@ Attachment limit exceeded: it's not possible to add more than $limit attachments @override String get linkDisabledError => 'Links are disabled'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 unread message'; + } + return '$unreadCount unread messages'; + } } 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 b2256190..2978df32 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -200,6 +200,7 @@ class StreamMessageListView extends StatefulWidget { this.onSystemMessageTap, this.showFloatingDateDivider = true, this.threadSeparatorBuilder, + this.unreadMessagesSeparatorBuilder, this.messageListController, this.reverse = true, this.paginationLimit = 20, @@ -337,6 +338,9 @@ class StreamMessageListView extends StatefulWidget { /// Builder used to build the thread separator in case it's a thread view final WidgetBuilder? threadSeparatorBuilder; + /// Builder used to build the unread message separator + final WidgetBuilder? unreadMessagesSeparatorBuilder; + /// A [MessageListController] allows pagination. /// Use [ChannelListController.paginateData] pagination. final MessageListController? messageListController; @@ -363,6 +367,7 @@ class _StreamMessageListViewState extends State { StreamChannelState? streamChannel; late StreamChatThemeData _streamTheme; late List _userPermissions; + late int unreadCount; int get _initialIndex { final initialScrollIndex = widget.initialScrollIndex; @@ -596,9 +601,12 @@ class _StreamMessageListViewState extends State { return const SizedBox(height: 8); } - if (i == 1 || i == itemCount - 4) return const Offstage(); + if (i == 1 || i == itemCount - 4) { + return const Offstage(); + } late final Message message, nextMessage; + late Widget separator; if (widget.reverse) { message = messages[i - 1]; nextMessage = messages[i - 2]; @@ -611,7 +619,7 @@ class _StreamMessageListViewState extends State { nextMessage.createdAt.toLocal(), Units.DAY, )) { - return _buildDateDivider(nextMessage); + separator = _buildDateDivider(nextMessage); } final timeDiff = Jiffy(nextMessage.createdAt.toLocal()).diff( @@ -644,13 +652,51 @@ class _StreamMessageListViewState extends State { } if (spacingRules.isNotEmpty) { - return widget.spacingWidgetBuilder + separator = widget.spacingWidgetBuilder ?.call(context, spacingRules) ?? const SizedBox(height: 8); } - return widget.spacingWidgetBuilder + separator = widget.spacingWidgetBuilder ?.call(context, [SpacingType.defaultSpacing]) ?? const SizedBox(height: 2); + + if (!isThread && unreadCount > 0 && unreadCount == i - 1) { + final unreadMessagesSeparator = + widget.unreadMessagesSeparatorBuilder?.call(context); + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + separator, + unreadMessagesSeparator ?? + Padding( + padding: + const EdgeInsets.symmetric(vertical: 8), + child: DecoratedBox( + decoration: BoxDecoration( + gradient: + _streamTheme.colorTheme.bgGradient, + ), + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + context.translations + .unreadMessagesSeparatorText( + unreadCount, + ), + textAlign: TextAlign.center, + style: + StreamChannelHeaderTheme.of(context) + .subtitleStyle, + ), + ), + ), + ), + ], + ); + } + + return separator; }, itemBuilder: (context, i) { if (i == itemCount - 1) { @@ -880,6 +926,7 @@ class _StreamMessageListViewState extends State { } Future scrollToBottomDefaultTapAction(int unreadCount) async { + this.unreadCount = unreadCount; if (unreadCount > 0) { streamChannel!.channel.markRead(); } @@ -890,11 +937,11 @@ class _StreamMessageListViewState extends State { await streamChannel!.reloadChannel(); WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollController!.jumpTo(index: 0); + _scrollController!.jumpTo(index: unreadCount); }); } else { _scrollController!.scrollTo( - index: 0, + index: unreadCount, duration: const Duration(seconds: 1), curve: Curves.easeInOut, ); @@ -1335,18 +1382,28 @@ class _StreamMessageListViewState extends State { if (event.message?.parentId == widget.parentMessage?.id && event.message!.user!.id == streamChannel!.channel.client.state.currentUser!.id) { + setState(() { + unreadCount = 0; + }); + WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController?.scrollTo( index: 0, duration: const Duration(seconds: 1), ); }); + } else if (streamChannel?.channel.state?.unreadCount != 0) { + setState(() { + unreadCount = unreadCount + 1; + }); } }); if (_isThreadConversation) { streamChannel!.getReplies(widget.parentMessage!.id); } + + unreadCount = streamChannel?.channel.state?.unreadCount ?? 0; } super.didChangeDependencies(); 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 9becad2d..6ca047f1 100644 --- a/packages/stream_chat_localizations/example/lib/add_new_lang.dart +++ b/packages/stream_chat_localizations/example/lib/add_new_lang.dart @@ -405,6 +405,14 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations { @override String get viewLibrary => 'View library'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 unread message'; + } + return '$unreadCount unread messages'; + } } void main() async { diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart index 71af15fa..0ad26f34 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart @@ -381,4 +381,12 @@ class StreamChatLocalizationsDe extends GlobalStreamChatLocalizations { @override String get viewLibrary => 'Bibliothek öffnen'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 ungelesene Nachricht'; + } + return '$unreadCount ungelesene Nachrichten'; + } } 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 ead459fa..cf00e816 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 @@ -381,4 +381,12 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations { @override String get viewLibrary => 'View library'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 unread message'; + } + return '$unreadCount unread messages'; + } } 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 d26e033a..3e85123d 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 @@ -387,4 +387,12 @@ No es posible añadir más de $limit archivos adjuntos @override String get linkDisabledError => 'Los enlaces están deshabilitados'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 mensaje no leído'; + } + return '$unreadCount mensajes no leídos'; + } } 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 5521ef57..c41547c3 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 @@ -386,4 +386,12 @@ Limite de pièces jointes dépassée : il n'est pas possible d'ajouter plus de $ @override String get linkDisabledError => 'Les liens sont désactivés'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 message non lu'; + } + return '$unreadCount messages non lus'; + } } 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 20ae9db2..be1153e9 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 @@ -380,4 +380,12 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations { @override String get linkDisabledError => 'लिंक भेजना प्रतिबंधित'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 अपठित संदेश'; + } + return '$unreadCount अपठित संदेश'; + } } 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 f8b21ed4..eb62d655 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 @@ -40,7 +40,12 @@ class StreamChatLocalizationsIt extends GlobalStreamChatLocalizations { String get onlyVisibleToYouText => 'Visible solo a te'; @override - String threadReplyCountText(int count) => '$count risposte al thread'; + String threadReplyCountText(int count) { + if (count == 1) { + return '1 risposta al thread'; + } + return '$count risposte al thread'; + } @override String attachmentsUploadProgressText({ @@ -383,4 +388,12 @@ Attenzione: il limite massimo di $limit file è stato superato. @override String get linkDisabledError => 'I links sono disattivati'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 messaggio non letto'; + } + return '$unreadCount messaggi non letti'; + } } 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 2faae6c4..3e5d5b37 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 @@ -365,4 +365,12 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations { @override String get linkDisabledError => 'リンクが無効になっています'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '未読メッセージ1通'; + } + return '$unreadCountつの未読メッセージ'; + } } 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 e541e529..519cd3cf 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 @@ -366,4 +366,12 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations { @override String get linkDisabledError => '링크가 비활성화되었습니다.'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '읽지 않은 메시지 1개'; + } + return '읽지 않은 메시지 $unreadCount개'; + } } diff --git a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart index 74e9a1f4..d761a45b 100644 --- a/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart +++ b/packages/stream_chat_localizations/lib/src/stream_chat_localizations_pt.dart @@ -384,4 +384,12 @@ Não é possível adicionar mais de $limit arquivos de uma vez @override String get viewLibrary => 'Ver biblioteca'; + + @override + String unreadMessagesSeparatorText(int unreadCount) { + if (unreadCount == 1) { + return '1 mensagem não lida'; + } + return '$unreadCount mensagens não lidas'; + } }