Skip to content

Commit d3ca74e

Browse files
Improved animation when sending messages
1 parent 0552de4 commit d3ca74e

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

Sources/StreamChatSwiftUI/ChatChannel/ChatChannelViewModel.swift

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,12 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
173173
array.append(message)
174174
self.messages = LazyCachedMapCollection(source: array, map: { $0 })
175175
} else {
176-
if shouldAnimate(changes: changes) {
176+
let animationState = shouldAnimate(changes: changes)
177+
if animationState == .animated {
177178
withAnimation {
178179
self.messages = messages
179180
}
180-
} else {
181+
} else if animationState == .notAnimated {
181182
self.messages = messages
182183
}
183184
}
@@ -364,22 +365,32 @@ open class ChatChannelViewModel: ObservableObject, MessagesDataSource {
364365
}
365366
}
366367

367-
private func shouldAnimate(changes: [ListChange<ChatMessage>]) -> Bool {
368+
private func shouldAnimate(changes: [ListChange<ChatMessage>]) -> AnimationChange {
368369
if !utils.messageListConfig.messageDisplayOptions.animateChanges {
369-
return false
370+
return .notAnimated
370371
}
371372

373+
var skipChanges = true
372374
for change in changes {
373375
switch change {
374376
case .insert(_, index: _),
375377
.remove(_, index: _):
376-
return true
378+
return .animated
379+
case let .update(message, index: index):
380+
if index.row < messages.count,
381+
message.messageId != messages[index.row].messageId {
382+
skipChanges = false
383+
}
377384
default:
378-
log.debug("detected non-animatable change")
385+
skipChanges = false
379386
}
380387
}
381388

382-
return false
389+
if skipChanges {
390+
return .skip
391+
}
392+
393+
return .notAnimated
383394
}
384395

385396
private func enableDateIndicator() {
@@ -468,3 +479,9 @@ public enum ChannelHeaderType {
468479
/// The header shown when someone is typing.
469480
case typingIndicator
470481
}
482+
483+
enum AnimationChange {
484+
case animated
485+
case notAnimated
486+
case skip
487+
}

StreamChatSwiftUITests/Tests/ChatChannel/ChatChannelViewModel_Tests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,67 @@ class ChatChannelViewModel_Tests: StreamChatTestCase {
233233
XCTAssert(headerType == .typingIndicator)
234234
}
235235

236+
func test_chatChannelVM_skipChanges() {
237+
// Given
238+
let channelController = makeChannelController()
239+
let viewModel = ChatChannelViewModel(channelController: channelController)
240+
let messageId = String.unique
241+
let message = ChatMessage.mock(
242+
id: messageId,
243+
cid: .unique,
244+
text: "Some text",
245+
author: .mock(id: .unique)
246+
)
247+
248+
// When
249+
channelController.simulate(
250+
messages: [message],
251+
changes: [.update(message, index: .init(row: 0, section: 0))]
252+
)
253+
let initial = viewModel.messages
254+
channelController.simulate(
255+
messages: [message],
256+
changes: [.update(message, index: .init(row: 0, section: 0))]
257+
)
258+
let after = viewModel.messages
259+
260+
// Then
261+
XCTAssert(initial[0].messageId == after[0].messageId)
262+
}
263+
264+
func test_chatChannelVM_animatedChanges() {
265+
// Given
266+
let channelController = makeChannelController()
267+
let viewModel = ChatChannelViewModel(channelController: channelController)
268+
let message = ChatMessage.mock(
269+
id: .unique,
270+
cid: .unique,
271+
text: "Some text",
272+
author: .mock(id: .unique)
273+
)
274+
let newMessage = ChatMessage.mock(
275+
id: .unique,
276+
cid: .unique,
277+
text: "New message",
278+
author: .mock(id: .unique)
279+
)
280+
281+
// When
282+
channelController.simulate(
283+
messages: [message],
284+
changes: [.update(message, index: .init(row: 0, section: 0))]
285+
)
286+
let initial = viewModel.messages
287+
channelController.simulate(
288+
messages: [message, newMessage],
289+
changes: [.insert(newMessage, index: .init(row: 1, section: 0))]
290+
)
291+
let after = viewModel.messages
292+
293+
// Then
294+
XCTAssert(initial.count < after.count)
295+
}
296+
236297
// MARK: - private
237298

238299
private func makeChannelController(

0 commit comments

Comments
 (0)