Skip to content

Commit 1ec6423

Browse files
authored
feat(ui, core, localization): add draft message preview and controller (#2230)
1 parent 7d8c556 commit 1ec6423

File tree

52 files changed

+2626
-376
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2626
-376
lines changed

packages/stream_chat/lib/src/client/channel.dart

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2608,15 +2608,7 @@ class ChannelClientState {
26082608
final draft = event.draft;
26092609
if (draft == null) return;
26102610

2611-
if (draft.parentId case final parentId?) {
2612-
for (final message in messages) {
2613-
if (message.id == parentId) {
2614-
return updateMessage(message.copyWith(draft: draft));
2615-
}
2616-
}
2617-
}
2618-
2619-
updateChannelState(channelState.copyWith(draft: draft));
2611+
return updateDraft(draft);
26202612
}),
26212613
);
26222614
}
@@ -2627,19 +2619,7 @@ class ChannelClientState {
26272619
final draft = event.draft;
26282620
if (draft == null) return;
26292621

2630-
if (draft.parentId case final parentId?) {
2631-
for (final message in messages) {
2632-
if (message.id == parentId) {
2633-
return updateMessage(
2634-
message.copyWith(draft: null),
2635-
);
2636-
}
2637-
}
2638-
}
2639-
2640-
updateChannelState(
2641-
channelState.copyWith(draft: null),
2642-
);
2622+
return deleteDraft(draft);
26432623
}),
26442624
);
26452625
}
@@ -2781,6 +2761,48 @@ class ChannelClientState {
27812761
);
27822762
}
27832763

2764+
/// Updates the [draft] in the channel state or the message if it exists.
2765+
void updateDraft(Draft draft) {
2766+
if (draft.parentId case final parentId?) {
2767+
for (final message in messages) {
2768+
if (message.id == parentId) {
2769+
return updateMessage(message.copyWith(draft: draft));
2770+
}
2771+
}
2772+
}
2773+
2774+
updateChannelState(
2775+
channelState.copyWith(
2776+
draft: draft,
2777+
),
2778+
);
2779+
}
2780+
2781+
/// Deletes the [draft] from the state if it exists.
2782+
void deleteDraft(Draft draft) async {
2783+
// Delete the draft from the persistence client.
2784+
await _channel._client.chatPersistenceClient?.deleteDraftMessageByCid(
2785+
draft.channelCid,
2786+
parentId: draft.parentId,
2787+
);
2788+
2789+
if (draft.parentId case final parentId?) {
2790+
for (final message in messages) {
2791+
if (message.id == parentId) {
2792+
return updateMessage(
2793+
message.copyWith(draft: null),
2794+
);
2795+
}
2796+
}
2797+
}
2798+
2799+
updateChannelState(
2800+
channelState.copyWith(
2801+
draft: null,
2802+
),
2803+
);
2804+
}
2805+
27842806
/// Updates the [message] in the state if it exists. Adds it otherwise.
27852807
void updateMessage(Message message) {
27862808
// Determine if the message should be displayed in the channel view.

packages/stream_chat/lib/src/db/chat_persistence_client.dart

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,9 @@ abstract class ChatPersistenceClient {
7979
PaginationParams? messagePagination,
8080
});
8181

82-
/// Get stored [Draft] message by providing channel [cid].
83-
Future<Draft?> getDraftMessageByCid(String cid);
84-
85-
/// Get stored [Draft] message by providing parent message [id].
86-
Future<Draft?> getDraftMessageByParentId(String parentId);
82+
/// Get stored [Draft] message by providing channel [cid] and a optional
83+
/// [parentId] for thread messages.
84+
Future<Draft?> getDraftMessageByCid(String cid, {String? parentId});
8785

8886
/// Get [ChannelState] data by providing channel [cid]
8987
Future<ChannelState> getChannelStateByCid(
@@ -166,8 +164,9 @@ abstract class ChatPersistenceClient {
166164
/// Remove a channel by [channelId]
167165
Future<void> deleteChannels(List<String> cids);
168166

169-
/// Removes all the draft messages by draft [messageIds]
170-
Future<void> deleteDraftMessagesByIds(List<String> messageIds);
167+
/// Removes the draft message by matching [DraftMessages.channelCid] and
168+
/// [DraftMessages.parentId].
169+
Future<void> deleteDraftMessageByCid(String cid, {String? parentId});
171170

172171
/// Updates the message data of a particular channel [cid] with
173172
/// the new [messages] data
@@ -278,6 +277,7 @@ abstract class ChatPersistenceClient {
278277
final channelWithPinnedMessages = <String, List<Message>?>{};
279278
final channelWithReads = <String, List<Read>?>{};
280279
final channelWithMembers = <String, List<Member>?>{};
280+
final drafts = <Draft>[];
281281

282282
final users = <User>[];
283283
final reactions = <Reaction>[];
@@ -287,9 +287,6 @@ abstract class ChatPersistenceClient {
287287
final pollVotes = <PollVote>[];
288288
final pollVotesToDelete = <String>[];
289289

290-
final drafts = <Draft>[];
291-
final draftsToDelete = <String>[];
292-
293290
for (final state in channelStates) {
294291
final channel = state.channel;
295292
// Continue if channel is not available.
@@ -339,8 +336,6 @@ abstract class ChatPersistenceClient {
339336
...?pinnedMessages?.map((it) => it.draft),
340337
].nonNulls);
341338

342-
draftsToDelete.addAll(drafts.map((it) => it.message.id));
343-
344339
users.addAll([
345340
channel.createdBy,
346341
...?messages?.map((it) => it.user),
@@ -361,7 +356,6 @@ abstract class ChatPersistenceClient {
361356
deleteReactionsByMessageId(reactionsToDelete),
362357
deletePinnedMessageReactionsByMessageId(pinnedReactionsToDelete),
363358
deletePollVotesByPollIds(pollVotesToDelete),
364-
deleteDraftMessagesByIds(draftsToDelete),
365359
]);
366360

367361
// Updating first as does not depend on any other table.

packages/stream_chat/test/src/db/chat_persistence_client_test.dart

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class TestPersistenceClient extends ChatPersistenceClient {
5858
Future<void> deletePollVotesByPollIds(List<String> pollIds) => Future.value();
5959

6060
@override
61-
Future<void> deleteDraftMessagesByIds(List<String> messageIds) =>
61+
Future<void> deleteDraftMessageByCid(String cid, {String? parentId}) =>
6262
Future.value();
6363

6464
@override
@@ -105,17 +105,14 @@ class TestPersistenceClient extends ChatPersistenceClient {
105105
Future<List<Read>> getReadsByCid(String cid) async => [];
106106

107107
@override
108-
Future<Draft?> getDraftMessageByCid(String cid) async => Draft(
108+
Future<Draft?> getDraftMessageByCid(
109+
String cid, {
110+
String? parentId,
111+
}) async =>
112+
Draft(
109113
channelCid: cid,
110-
createdAt: DateTime.now(),
111-
message: DraftMessage(id: 'message-id', text: 'message-text'),
112-
);
113-
114-
@override
115-
Future<Draft?> getDraftMessageByParentId(String parentId) async => Draft(
116-
channelCid: 'test:cid',
117-
createdAt: DateTime.now(),
118114
parentId: parentId,
115+
createdAt: DateTime.now(),
119116
message: DraftMessage(id: 'message-id', text: 'message-text'),
120117
);
121118

@@ -218,9 +215,10 @@ void main() {
218215
persistenceClient.updatePolls([poll]);
219216
});
220217

221-
test('deleteDraftMessagesByIds', () {
222-
const messageIds = ['message-id'];
223-
persistenceClient.deleteDraftMessagesByIds(messageIds);
218+
test('deleteDraftMessageByCid', () {
219+
const cid = 'test:cid';
220+
const parentId = 'parent-id';
221+
persistenceClient.deleteDraftMessageByCid(cid, parentId: parentId);
224222
});
225223

226224
test('updateDraftMessages', () async {

packages/stream_chat_flutter/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## Upcoming
2+
3+
✅ Added
4+
5+
- Added support for Draft messages preview.
6+
- Added a new `StreamDraftListView` for displaying draft messages.
7+
18
## 9.8.0
29

310
🐞 Fixed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
3+
4+
/// A widget that renders a preview of the draft message text.
5+
class StreamDraftMessagePreviewText extends StatelessWidget {
6+
/// Creates a new instance of [StreamDraftMessagePreviewText].
7+
const StreamDraftMessagePreviewText({
8+
super.key,
9+
required this.draftMessage,
10+
this.textStyle,
11+
});
12+
13+
/// The draft message to display.
14+
final DraftMessage draftMessage;
15+
16+
/// The style to use for the text.
17+
final TextStyle? textStyle;
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
final theme = StreamChatTheme.of(context);
22+
final colorTheme = theme.colorTheme;
23+
24+
final previewTextSpan = TextSpan(
25+
text: '${context.translations.draftLabel}: ',
26+
style: textStyle?.copyWith(
27+
fontWeight: FontWeight.bold,
28+
color: colorTheme.accentPrimary,
29+
),
30+
children: [
31+
TextSpan(text: draftMessage.text, style: textStyle),
32+
],
33+
);
34+
35+
return Text.rich(
36+
maxLines: 1,
37+
previewTextSpan,
38+
overflow: TextOverflow.ellipsis,
39+
textAlign: TextAlign.start,
40+
);
41+
}
42+
}

packages/stream_chat_flutter/lib/src/localization/translations.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ abstract class Translations {
535535

536536
/// The text for poll when someone created
537537
String pollSomeoneCreatedText(String username);
538+
539+
/// The label for draft message
540+
String get draftLabel;
538541
}
539542

540543
/// Default implementation of Translation strings for the stream chat widgets
@@ -1198,4 +1201,7 @@ Attachment limit exceeded: it's not possible to add more than $limit attachments
11981201

11991202
@override
12001203
String pollSomeoneCreatedText(String username) => '$username created';
1204+
1205+
@override
1206+
String get draftLabel => 'Draft';
12011207
}

0 commit comments

Comments
 (0)