Skip to content

Commit 29a4249

Browse files
committed
message: Handle UpdateMessageEvent for moving/editing.
When a channel (a.k.a stream) or a topic gets updated on a message, we get a UpdateMessageEvent from the server. The same happens when the message's content is updated. This updates the edit state to show the "edited" or "moved" marker properly on the messages affected, and leave other move related states (like streamId) untouched until we get to #150. Signed-off-by: Zixuan James Li <[email protected]>
1 parent c0802b3 commit 29a4249

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

lib/model/message.dart

+22-1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class MessageStoreImpl with MessageStore {
124124
if (message == null) return;
125125

126126
message.flags = event.flags;
127+
message.editState = MessageEditState.edited;
127128
if (event.renderedContent != null) {
128129
assert(message.contentType == 'text/html',
129130
"Message contentType was ${message.contentType}; expected text/html.");
@@ -142,7 +143,10 @@ class MessageStoreImpl with MessageStore {
142143
// The interaction between the fields of these events are a bit tricky.
143144
// For reference, see: https://zulip.com/api/get-events#update_message
144145

145-
if (event.origTopic == null) {
146+
final bool isChannelMoved = event.newStreamId != null;
147+
bool isTopicMoved = event.origTopic != null;
148+
149+
if (!isTopicMoved && !isChannelMoved) {
146150
// There was no move.
147151
assert(() {
148152
if (event.newStreamId != null && event.origStreamId != null
@@ -167,10 +171,27 @@ class MessageStoreImpl with MessageStore {
167171
return;
168172
}
169173

174+
if (isTopicMoved) {
175+
// Eliminate the case when the topic is updated but resolved/unresolved.
176+
isTopicMoved = MessageEditState.areSameTopic(event.origTopic!, event.newTopic!);
177+
}
178+
179+
// When nothing has been moved,
180+
// return early as the messages' editStates need no update.
181+
if (!isTopicMoved && !isChannelMoved) return;
182+
170183
// final newStreamId = event.newStreamId; // null if topic-only move
171184
// final newTopic = event.newTopic!;
172185
// TODO(#150): Handle message moves. The views' recipient headers
173186
// may need updating, and consequently showSender too.
187+
// Currently only editState gets updated.
188+
for (final messageId in event.messageIds) {
189+
final message = messages[messageId];
190+
if (message == null) continue;
191+
// Do not override the edited marker if the message has also been moved.
192+
if (message.editState == MessageEditState.edited) continue;
193+
message.editState = MessageEditState.moved;
194+
}
174195
}
175196

176197
void handleDeleteMessageEvent(DeleteMessageEvent event) {

test/example_data.dart

+29
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,35 @@ UpdateMessageEvent updateMessageEditEvent(
420420
);
421421
}
422422

423+
UpdateMessageEvent updateMessageMoveEvent(
424+
Message origMessage, {
425+
int? messageId,
426+
int? newStreamId,
427+
String? origTopic,
428+
String? newTopic,
429+
}) {
430+
messageId ??= origMessage.id;
431+
return UpdateMessageEvent(
432+
id: 0,
433+
userId: selfUser.userId,
434+
renderingOnly: false,
435+
messageId: messageId,
436+
messageIds: [messageId],
437+
flags: origMessage.flags,
438+
editTimestamp: 1234567890, // TODO generate timestamp
439+
origStreamId: origMessage is StreamMessage ? origMessage.streamId : null,
440+
newStreamId: newStreamId,
441+
propagateMode: null,
442+
origTopic: origTopic,
443+
newTopic: newTopic,
444+
origContent: 'some probably-mismatched old Markdown',
445+
origRenderedContent: origMessage.content,
446+
content: 'some probably-mismatched new Markdown',
447+
renderedContent: origMessage.content,
448+
isMeMessage: false,
449+
);
450+
}
451+
423452
UpdateMessageFlagsRemoveEvent updateMessageFlagsRemoveEvent(
424453
MessageFlag flag,
425454
Iterable<Message> messages, {

test/model/message_test.dart

+46-2
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ void main() {
207207
..content.not((it) => it.equals(updateEvent.renderedContent!))
208208
..lastEditTimestamp.isNull()
209209
..flags.not((it) => it.deepEquals(updateEvent.flags))
210-
..isMeMessage.not((it) => it.equals(updateEvent.isMeMessage!));
210+
..isMeMessage.not((it) => it.equals(updateEvent.isMeMessage!))
211+
..editState.equals(MessageEditState.none);
211212

212213
await store.handleEvent(updateEvent);
213214
checkNotifiedOnce();
@@ -216,7 +217,8 @@ void main() {
216217
..content.equals(updateEvent.renderedContent!)
217218
..lastEditTimestamp.equals(updateEvent.editTimestamp)
218219
..flags.equals(updateEvent.flags)
219-
..isMeMessage.equals(updateEvent.isMeMessage!);
220+
..isMeMessage.equals(updateEvent.isMeMessage!)
221+
..editState.equals(MessageEditState.edited);
220222
});
221223

222224
test('ignore when message unknown', () async {
@@ -269,6 +271,48 @@ void main() {
269271
test('rendering-only update does not change timestamp (for old server versions)', () async {
270272
await checkRenderingOnly(legacy: true);
271273
});
274+
275+
group('Handle message edit state update', () {
276+
final message = eg.streamMessage();
277+
278+
Future<void> sendEvent(Message message, UpdateMessageEvent event) async {
279+
await prepare();
280+
await prepareMessages([message]);
281+
282+
await store.handleEvent(event);
283+
checkNotifiedOnce();
284+
}
285+
286+
test('message not moved update', () async {
287+
await sendEvent(message, eg.updateMessageMoveEvent(message));
288+
check(store).messages.values.single.editState.equals(MessageEditState.none);
289+
});
290+
291+
test('message topic moved update', () async {
292+
await sendEvent(message, eg.updateMessageMoveEvent(message,
293+
origTopic: 'old topic',
294+
newTopic: 'new topic',
295+
));
296+
check(store).messages.values.single.editState.equals(MessageEditState.moved);
297+
});
298+
299+
test('message topic resolved update', () async {
300+
await sendEvent(message, eg.updateMessageMoveEvent(message,
301+
origTopic: 'new topic',
302+
newTopic: '✔ new topic',
303+
));
304+
check(store).messages.values.single.editState.equals(MessageEditState.none);
305+
});
306+
307+
test('message stream moved update', () async {
308+
await sendEvent(message, eg.updateMessageMoveEvent(message,
309+
origTopic: 'topic',
310+
newTopic: 'topic',
311+
newStreamId: 20,
312+
));
313+
check(store).messages.values.single.editState.equals(MessageEditState.moved);
314+
});
315+
});
272316
});
273317

274318
group('handleUpdateMessageFlagsEvent', () {

0 commit comments

Comments
 (0)