Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/stream_chat/lib/src/client/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3340,6 +3340,7 @@ class ChannelClientState {
read: newReads,
draft: updatedState.draft,
pinnedMessages: updatedState.pinnedMessages,
pendingMessages: updatedState.pendingMessages,
pushPreferences: updatedState.pushPreferences,
);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/stream_chat/lib/src/core/models/channel_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class ChannelConfig {
this.urlEnrichment = false,
this.skipLastMsgUpdateForSystemMsgs = false,
this.userMessageReminders = false,
this.markMessagesPending = false,
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();

Expand Down Expand Up @@ -91,6 +92,9 @@ class ChannelConfig {
/// True if the user can set reminders for messages in this channel.
final bool userMessageReminders;

/// Whether pending messages are enabled for this channel.
final bool markMessagesPending;

/// Serialize to json
Map<String, dynamic> toJson() => _$ChannelConfigToJson(this);
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions packages/stream_chat/lib/src/core/models/channel_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class ChannelState implements ComparableFieldProvider {
this.read,
this.membership,
this.draft,
this.pendingMessages,
this.pushPreferences,
});

Expand Down Expand Up @@ -60,6 +61,28 @@ class ChannelState implements ComparableFieldProvider {
/// The draft message for this channel if it exists.
final Draft? draft;

static Object? _pendingMessagesReadValue(
Map<Object?, Object?> json,
String key,
) {
final pendingMessageResponse = json[key];
if (pendingMessageResponse is! List<Object?>) return null;

final value = pendingMessageResponse.map((it) {
if (it is! Map<String, Object?>) return null;
return it['message'];
}).nonNulls;

if (value.isEmpty) return null;
return value.toList(growable: false);
}

/// List of messages pending for moderation on this channel.
///
/// These messages are only visible to the author until they are approved.
@JsonKey(readValue: _pendingMessagesReadValue)
final List<Message>? pendingMessages;

/// The push preferences for this channel if it exists.
final ChannelPushPreference? pushPreferences;

Expand All @@ -81,6 +104,7 @@ class ChannelState implements ComparableFieldProvider {
List<Read>? read,
Member? membership,
Object? draft = _nullConst,
List<Message>? pendingMessages,
ChannelPushPreference? pushPreferences,
}) =>
ChannelState(
Expand All @@ -93,6 +117,7 @@ class ChannelState implements ComparableFieldProvider {
read: read ?? this.read,
membership: membership ?? this.membership,
draft: draft == _nullConst ? this.draft : draft as Draft?,
pendingMessages: pendingMessages ?? this.pendingMessages,
pushPreferences: pushPreferences ?? this.pushPreferences,
);

Expand Down
7 changes: 7 additions & 0 deletions packages/stream_chat/lib/src/core/models/channel_state.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1478,19 +1478,31 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
if (_upToDate && lastFullyVisibleMessageChanged) {
_lastFullyVisibleMessage = newLastFullyVisibleMessage;

if (streamChannel?.channel case final channel?) {
final hasUnread = (channel.state?.unreadCount ?? 0) > 0;
final allowMarkRead = channel.config?.readEvents == true;
final canMarkReadAtBottom = widget.markReadWhenAtTheBottom;

// Mark messages as read if it's allowed.
if (hasUnread && allowMarkRead && canMarkReadAtBottom) {
return _markMessagesAsRead().ignore();
}
}
// Mark messages as read if needed.
_maybeMarkMessagesAsRead().ignore();
}
}

Future<void> _maybeMarkMessagesAsRead() async {
final channel = streamChannel?.channel;
if (channel == null) return;

final hasUnread = (channel.state?.unreadCount ?? 0) > 0;
if (!hasUnread) return;

final allowMarkRead = channel.config?.readEvents == true;
if (!allowMarkRead) return;

final markPendingDisabled = channel.config?.markMessagesPending == false;
if (!markPendingDisabled) return;

final canMarkReadAtBottom = widget.markReadWhenAtTheBottom;
if (!canMarkReadAtBottom) return;

// Mark messages as read if it's allowed.
return _markMessagesAsRead();
}

void _getOnThreadTap() {
if (widget.onThreadTap != null) {
_onThreadTap = (Message message) {
Expand Down
Loading