Skip to content

Commit 1d7d440

Browse files
authored
Sort messages by CreatedAt after appending new items - this fixes the message ordering when using the LoadOlderMessagesAsync() (#120)
1 parent 7a49bf1 commit 1d7d440

2 files changed

Lines changed: 37 additions & 26 deletions

File tree

Assets/Plugins/StreamChat/Core/StatefulModels/IStreamChannel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public interface IStreamChannel : IStreamStatefulModel
232232
IStreamChannelMember Membership { get; }
233233

234234
/// <summary>
235-
/// List of channel messages. By default only latest messages are loaded. If you wish to load older messages user the <see cref="LoadOlderMessagesAsync"/>
235+
/// List of channel messages. By default only latest messages are loaded. If you wish to load older messages use the <see cref="LoadOlderMessagesAsync"/>
236236
/// </summary>
237237
IReadOnlyList<IStreamMessage> Messages { get; }
238238

@@ -283,6 +283,10 @@ public interface IStreamChannel : IStreamStatefulModel
283283
/// </summary>
284284
Task<IStreamMessage> SendNewMessageAsync(StreamSendMessageRequest sendMessageRequest);
285285

286+
/// <summary>
287+
/// Load next portion of older messages. Older messages will be prepended to the <see cref="Messages"/> list.
288+
/// Note that loading older messages does NOT trigger the <see cref="MessageReceived"/> event
289+
/// </summary>
286290
Task LoadOlderMessagesAsync();
287291

288292
/// <summary>

Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ namespace StreamChat.Core.StatefulModels
2828
public delegate void StreamChannelUserChangeHandler(IStreamChannel channel, IStreamUser user);
2929

3030
public delegate void StreamChannelMemberChangeHandler(IStreamChannel channel, IStreamChannelMember member);
31-
public delegate void StreamChannelMemberAnyChangeHandler(IStreamChannel channel, IStreamChannelMember member, OperationType operationType);
31+
32+
public delegate void StreamChannelMemberAnyChangeHandler(IStreamChannel channel, IStreamChannelMember member,
33+
OperationType operationType);
3234

3335
public delegate void StreamMessageReactionHandler(IStreamChannel channel, IStreamMessage message,
3436
StreamReaction reaction);
@@ -57,7 +59,7 @@ internal sealed class StreamChannel : StreamStatefulModelBase<StreamChannel>,
5759
public event StreamChannelMemberChangeHandler MemberRemoved;
5860

5961
public event StreamChannelMemberChangeHandler MemberUpdated;
60-
62+
6163
public event StreamChannelMemberAnyChangeHandler MembersChanged;
6264

6365
public event StreamChannelVisibilityHandler VisibilityChanged;
@@ -177,8 +179,7 @@ internal set
177179

178180
#endregion
179181

180-
public bool IsDirectMessage =>
181-
Members.Count == 2 && Members.Any(m => m.User == Client.LocalUserData.User);
182+
public bool IsDirectMessage => Members.Count == 2 && Members.Any(m => m.User == Client.LocalUserData.User);
182183

183184
public Task<IStreamMessage> SendNewMessageAsync(string message)
184185
=> SendNewMessageAsync(new StreamSendMessageRequest
@@ -286,12 +287,12 @@ public async Task<StreamImageUploadResponse> UploadImageAsync(byte[] imageConten
286287

287288
//StreamTodo: IMPLEMENT, this should probably work like LoadNextMembers, LoadPreviousMembers? what about sorting - in config?
288289
//Perhaps we should have both, maybe user wants to search members and not only paginate joined
289-
public async Task<IEnumerable<IStreamChannelMember>> QueryMembersAsync(IDictionary<string, object> filters = null,
290-
int limit = 30, int offset = 0)
290+
public async Task<IEnumerable<IStreamChannelMember>> QueryMembersAsync(
291+
IDictionary<string, object> filters = null, int limit = 30, int offset = 0)
291292
{
292293
// filter_conditions is required by API but empty object is accepted
293294
filters ??= new Dictionary<string, object>();
294-
295+
295296
var response = await LowLevelClient.InternalChannelApi.QueryMembersAsync(new QueryMembersRequestInternalDTO
296297
{
297298
CreatedAtAfter = null,
@@ -389,8 +390,7 @@ public Task AddMembersAsync(IEnumerable<IStreamUser> users)
389390
return AddMembersAsync(users.Select(u => u.Id));
390391
}
391392

392-
public Task AddMembersAsync(params IStreamUser[] users)
393-
=> AddMembersAsync(users as IEnumerable<IStreamUser>);
393+
public Task AddMembersAsync(params IStreamUser[] users) => AddMembersAsync(users as IEnumerable<IStreamUser>);
394394

395395
public async Task AddMembersAsync(IEnumerable<string> userIds)
396396
{
@@ -412,9 +412,8 @@ public async Task AddMembersAsync(IEnumerable<string> userIds)
412412
});
413413
Cache.TryCreateOrUpdate(response);
414414
}
415-
416-
public Task AddMembersAsync(params string[] users)
417-
=> AddMembersAsync(users as IEnumerable<string>);
415+
416+
public Task AddMembersAsync(params string[] users) => AddMembersAsync(users as IEnumerable<string>);
418417

419418
public Task RemoveMembersAsync(IEnumerable<IStreamChannelMember> members)
420419
{
@@ -424,16 +423,16 @@ public Task RemoveMembersAsync(IEnumerable<IStreamChannelMember> members)
424423

425424
public Task RemoveMembersAsync(params IStreamChannelMember[] members)
426425
=> RemoveMembersAsync(members as IEnumerable<IStreamChannelMember>);
427-
426+
428427
public Task RemoveMembersAsync(IEnumerable<IStreamUser> members)
429428
{
430429
StreamAsserts.AssertNotNull(members, nameof(members));
431430
return RemoveMembersAsync(members.Select(_ => _.Id));
432431
}
433-
432+
434433
public Task RemoveMembersAsync(params IStreamUser[] members)
435434
=> RemoveMembersAsync(members as IEnumerable<IStreamUser>);
436-
435+
437436
public async Task RemoveMembersAsync(IEnumerable<string> userIds)
438437
{
439438
StreamAsserts.AssertNotNull(userIds, nameof(userIds));
@@ -445,10 +444,9 @@ public async Task RemoveMembersAsync(IEnumerable<string> userIds)
445444
});
446445
Cache.TryCreateOrUpdate(response);
447446
}
448-
449-
public Task RemoveMembersAsync(params string[] userIds)
450-
=> RemoveMembersAsync(userIds as IEnumerable<string>);
451-
447+
448+
public Task RemoveMembersAsync(params string[] userIds) => RemoveMembersAsync(userIds as IEnumerable<string>);
449+
452450
public Task JoinAsMemberAsync() => AddMembersAsync(Client.LocalUserData.User);
453451

454452
public Task LeaveAsMemberChannelAsync() => RemoveMembersAsync(Client.LocalUserData.User);
@@ -499,19 +497,19 @@ public async Task TruncateAsync(DateTimeOffset? truncatedAt = default, string sy
499497
}
500498

501499
//StreamTodo: write test and check Client.WatchedChannels
502-
public Task StopWatchingAsync() =>
503-
LowLevelClient.InternalChannelApi.StopWatchingChannelAsync(Type, Id,
500+
public Task StopWatchingAsync()
501+
=> LowLevelClient.InternalChannelApi.StopWatchingChannelAsync(Type, Id,
504502
new ChannelStopWatchingRequestInternalDTO());
505503

506504
public Task DeleteAsync()
507505
=> LowLevelClient.InternalChannelApi.DeleteChannelAsync(Type, Id, isHardDelete: false);
508506

509507
//StreamTodo: auto send TypingStopped after timeout + timeout received typing users in case they've lost connection and never sent the stop event
510-
public Task SendTypingStartedEventAsync() =>
511-
LowLevelClient.InternalChannelApi.SendTypingStartEventAsync(Type, Id);
508+
public Task SendTypingStartedEventAsync()
509+
=> LowLevelClient.InternalChannelApi.SendTypingStartEventAsync(Type, Id);
512510

513-
public Task SendTypingStoppedEventAsync() =>
514-
LowLevelClient.InternalChannelApi.SendTypingStopEventAsync(Type, Id);
511+
public Task SendTypingStoppedEventAsync()
512+
=> LowLevelClient.InternalChannelApi.SendTypingStopEventAsync(Type, Id);
515513

516514
public override string ToString() => $"Channel - Id: {Id}, Name: {Name}";
517515

@@ -543,6 +541,8 @@ void IUpdateableFrom<ChannelStateResponseInternalDTO, StreamChannel>.UpdateFromD
543541

544542
#endregion
545543

544+
SortMessagesByCreatedAt();
545+
546546
//StreamTodo should every UpdateFromDto trigger Updated event?
547547
}
548548

@@ -564,6 +564,8 @@ void IUpdateableFrom<ChannelStateResponseFieldsInternalDTO, StreamChannel>.Updat
564564
WatcherCount = GetOrDefault(dto.WatcherCount, WatcherCount);
565565
_watchers.TryAppendUniqueTrackedObjects(dto.Watchers, cache.Users);
566566

567+
SortMessagesByCreatedAt();
568+
567569
#endregion
568570
}
569571

@@ -932,5 +934,10 @@ private Task InternalBanUserAsync(IStreamUser user, bool isShadowBan = false, st
932934
//AdditionalProperties = null
933935
});
934936
}
937+
938+
private void SortMessagesByCreatedAt()
939+
{
940+
_messages.Sort((msg1, msg2) => msg1.CreatedAt.CompareTo(msg2.CreatedAt));
941+
}
935942
}
936943
}

0 commit comments

Comments
 (0)