Merge pull request #1212 from GetStream/feature/newMessageLabel
feat(ui,localization): add unread messages label
This commit is contained in:
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
- [[#1011]](https://github.com/GetStream/stream-chat-flutter/issues/1011) Animate the background
|
- [[#1011]](https://github.com/GetStream/stream-chat-flutter/issues/1011) Animate the background
|
||||||
color of pinned messages.
|
color of pinned messages.
|
||||||
|
- Added unread messages divider in `StreamMessageListView`.
|
||||||
|
- Added `StreamMessageListView.unreadMessagesSeparatorBuilder`.
|
||||||
|
|
||||||
## 4.2.0
|
## 4.2.0
|
||||||
|
|
||||||
|
|||||||
@@ -59,5 +59,7 @@
|
|||||||
|
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Explain why your app uses the mic</string>
|
<string>Explain why your app uses the mic</string>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ abstract class Translations {
|
|||||||
/// contains a parent message
|
/// contains a parent message
|
||||||
String threadSeparatorText(int replyCount);
|
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]
|
/// The label for "connected" in [StreamConnectionStatusBuilder]
|
||||||
String get connectedLabel;
|
String get connectedLabel;
|
||||||
|
|
||||||
@@ -711,4 +715,12 @@ Attachment limit exceeded: it's not possible to add more than $limit attachments
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'Links are disabled';
|
String get linkDisabledError => 'Links are disabled';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '1 unread message';
|
||||||
|
}
|
||||||
|
return '$unreadCount unread messages';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
this.onSystemMessageTap,
|
this.onSystemMessageTap,
|
||||||
this.showFloatingDateDivider = true,
|
this.showFloatingDateDivider = true,
|
||||||
this.threadSeparatorBuilder,
|
this.threadSeparatorBuilder,
|
||||||
|
this.unreadMessagesSeparatorBuilder,
|
||||||
this.messageListController,
|
this.messageListController,
|
||||||
this.reverse = true,
|
this.reverse = true,
|
||||||
this.paginationLimit = 20,
|
this.paginationLimit = 20,
|
||||||
@@ -337,6 +338,10 @@ class StreamMessageListView extends StatefulWidget {
|
|||||||
/// Builder used to build the thread separator in case it's a thread view
|
/// Builder used to build the thread separator in case it's a thread view
|
||||||
final WidgetBuilder? threadSeparatorBuilder;
|
final WidgetBuilder? threadSeparatorBuilder;
|
||||||
|
|
||||||
|
/// Builder used to build the unread message separator
|
||||||
|
final Widget Function(BuildContext context, int unreadCount)?
|
||||||
|
unreadMessagesSeparatorBuilder;
|
||||||
|
|
||||||
/// A [MessageListController] allows pagination.
|
/// A [MessageListController] allows pagination.
|
||||||
/// Use [ChannelListController.paginateData] pagination.
|
/// Use [ChannelListController.paginateData] pagination.
|
||||||
final MessageListController? messageListController;
|
final MessageListController? messageListController;
|
||||||
@@ -363,6 +368,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
StreamChannelState? streamChannel;
|
StreamChannelState? streamChannel;
|
||||||
late StreamChatThemeData _streamTheme;
|
late StreamChatThemeData _streamTheme;
|
||||||
late List<String> _userPermissions;
|
late List<String> _userPermissions;
|
||||||
|
late int unreadCount;
|
||||||
|
|
||||||
int get _initialIndex {
|
int get _initialIndex {
|
||||||
final initialScrollIndex = widget.initialScrollIndex;
|
final initialScrollIndex = widget.initialScrollIndex;
|
||||||
@@ -596,9 +602,12 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
return const SizedBox(height: 8);
|
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 final Message message, nextMessage;
|
||||||
|
late Widget separator;
|
||||||
if (widget.reverse) {
|
if (widget.reverse) {
|
||||||
message = messages[i - 1];
|
message = messages[i - 1];
|
||||||
nextMessage = messages[i - 2];
|
nextMessage = messages[i - 2];
|
||||||
@@ -611,7 +620,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
nextMessage.createdAt.toLocal(),
|
nextMessage.createdAt.toLocal(),
|
||||||
Units.DAY,
|
Units.DAY,
|
||||||
)) {
|
)) {
|
||||||
return _buildDateDivider(nextMessage);
|
separator = _buildDateDivider(nextMessage);
|
||||||
}
|
}
|
||||||
final timeDiff =
|
final timeDiff =
|
||||||
Jiffy(nextMessage.createdAt.toLocal()).diff(
|
Jiffy(nextMessage.createdAt.toLocal()).diff(
|
||||||
@@ -644,13 +653,52 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (spacingRules.isNotEmpty) {
|
if (spacingRules.isNotEmpty) {
|
||||||
return widget.spacingWidgetBuilder
|
separator = widget.spacingWidgetBuilder
|
||||||
?.call(context, spacingRules) ??
|
?.call(context, spacingRules) ??
|
||||||
const SizedBox(height: 8);
|
const SizedBox(height: 8);
|
||||||
}
|
}
|
||||||
return widget.spacingWidgetBuilder
|
separator = widget.spacingWidgetBuilder
|
||||||
?.call(context, [SpacingType.defaultSpacing]) ??
|
?.call(context, [SpacingType.defaultSpacing]) ??
|
||||||
const SizedBox(height: 2);
|
const SizedBox(height: 2);
|
||||||
|
|
||||||
|
if (!isThread && unreadCount > 0 && unreadCount == i - 1) {
|
||||||
|
final unreadMessagesSeparator = widget
|
||||||
|
.unreadMessagesSeparatorBuilder
|
||||||
|
?.call(context, unreadCount);
|
||||||
|
|
||||||
|
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) {
|
itemBuilder: (context, i) {
|
||||||
if (i == itemCount - 1) {
|
if (i == itemCount - 1) {
|
||||||
@@ -880,6 +928,7 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> scrollToBottomDefaultTapAction(int unreadCount) async {
|
Future<void> scrollToBottomDefaultTapAction(int unreadCount) async {
|
||||||
|
this.unreadCount = unreadCount;
|
||||||
if (unreadCount > 0) {
|
if (unreadCount > 0) {
|
||||||
streamChannel!.channel.markRead();
|
streamChannel!.channel.markRead();
|
||||||
}
|
}
|
||||||
@@ -890,11 +939,11 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
await streamChannel!.reloadChannel();
|
await streamChannel!.reloadChannel();
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollController!.jumpTo(index: 0);
|
_scrollController!.jumpTo(index: unreadCount);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_scrollController!.scrollTo(
|
_scrollController!.scrollTo(
|
||||||
index: 0,
|
index: unreadCount,
|
||||||
duration: const Duration(seconds: 1),
|
duration: const Duration(seconds: 1),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
@@ -1335,18 +1384,28 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
|
|||||||
if (event.message?.parentId == widget.parentMessage?.id &&
|
if (event.message?.parentId == widget.parentMessage?.id &&
|
||||||
event.message!.user!.id ==
|
event.message!.user!.id ==
|
||||||
streamChannel!.channel.client.state.currentUser!.id) {
|
streamChannel!.channel.client.state.currentUser!.id) {
|
||||||
|
setState(() {
|
||||||
|
unreadCount = 0;
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_scrollController?.scrollTo(
|
_scrollController?.scrollTo(
|
||||||
index: 0,
|
index: 0,
|
||||||
duration: const Duration(seconds: 1),
|
duration: const Duration(seconds: 1),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else if (streamChannel?.channel.state?.unreadCount != 0) {
|
||||||
|
setState(() {
|
||||||
|
unreadCount = unreadCount + 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (_isThreadConversation) {
|
if (_isThreadConversation) {
|
||||||
streamChannel!.getReplies(widget.parentMessage!.id);
|
streamChannel!.getReplies(widget.parentMessage!.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unreadCount = streamChannel?.channel.state?.unreadCount ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
## Upcoming
|
||||||
|
|
||||||
|
✅ Added
|
||||||
|
|
||||||
|
* Added support for `unreadMessagesSeparatorText` translation.
|
||||||
|
|
||||||
## 3.1.0
|
## 3.1.0
|
||||||
|
|
||||||
* Added support for [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) locale.
|
* Added support for [German](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_de.dart) locale.
|
||||||
|
|||||||
@@ -405,6 +405,14 @@ class NnStreamChatLocalizations extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get viewLibrary => 'View library';
|
String get viewLibrary => 'View library';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '1 unread message';
|
||||||
|
}
|
||||||
|
return '$unreadCount unread messages';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
|
|||||||
@@ -381,4 +381,12 @@ class StreamChatLocalizationsDe extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get viewLibrary => 'Bibliothek öffnen';
|
String get viewLibrary => 'Bibliothek öffnen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '1 ungelesene Nachricht';
|
||||||
|
}
|
||||||
|
return '$unreadCount ungelesene Nachrichten';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -381,4 +381,12 @@ class StreamChatLocalizationsEn extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get viewLibrary => 'View library';
|
String get viewLibrary => 'View library';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '1 unread message';
|
||||||
|
}
|
||||||
|
return '$unreadCount unread messages';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,4 +387,12 @@ No es posible añadir más de $limit archivos adjuntos
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'Los enlaces están deshabilitados';
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -386,4 +386,12 @@ Limite de pièces jointes dépassée : il n'est pas possible d'ajouter plus de $
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'Les liens sont désactivés';
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,4 +380,12 @@ class StreamChatLocalizationsHi extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'लिंक भेजना प्रतिबंधित';
|
String get linkDisabledError => 'लिंक भेजना प्रतिबंधित';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '1 अपठित संदेश';
|
||||||
|
}
|
||||||
|
return '$unreadCount अपठित संदेश';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,12 @@ class StreamChatLocalizationsIt extends GlobalStreamChatLocalizations {
|
|||||||
String get onlyVisibleToYouText => 'Visible solo a te';
|
String get onlyVisibleToYouText => 'Visible solo a te';
|
||||||
|
|
||||||
@override
|
@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
|
@override
|
||||||
String attachmentsUploadProgressText({
|
String attachmentsUploadProgressText({
|
||||||
@@ -383,4 +388,12 @@ Attenzione: il limite massimo di $limit file è stato superato.
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'I links sono disattivati';
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,4 +365,12 @@ class StreamChatLocalizationsJa extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => 'リンクが無効になっています';
|
String get linkDisabledError => 'リンクが無効になっています';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '未読メッセージ1通';
|
||||||
|
}
|
||||||
|
return '$unreadCountつの未読メッセージ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,4 +366,12 @@ class StreamChatLocalizationsKo extends GlobalStreamChatLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get linkDisabledError => '링크가 비활성화되었습니다.';
|
String get linkDisabledError => '링크가 비활성화되었습니다.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String unreadMessagesSeparatorText(int unreadCount) {
|
||||||
|
if (unreadCount == 1) {
|
||||||
|
return '읽지 않은 메시지 1개';
|
||||||
|
}
|
||||||
|
return '읽지 않은 메시지 $unreadCount개';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -384,4 +384,12 @@ Não é possível adicionar mais de $limit arquivos de uma vez
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get viewLibrary => 'Ver biblioteca';
|
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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user