diff --git a/Signal/ConversationView/CVAudioPlayback.swift b/Signal/ConversationView/CVAudioPlayback.swift index 6cd6b985742..4fa8088d11c 100644 --- a/Signal/ConversationView/CVAudioPlayback.swift +++ b/Signal/ConversationView/CVAudioPlayback.swift @@ -9,7 +9,9 @@ public import SignalUI protocol CVAudioPlayerListener { func audioPlayerStateDidChange(attachmentId: Attachment.IDType) - func audioPlayerDidFinish(attachmentId: Attachment.IDType) + // Attachments are deduplicated by content across conversations, so + // attachmentId alone is not enough to identify which message finished. + func audioPlayerDidFinish(attachmentId: Attachment.IDType, forInteractionId interactionId: String?) func audioPlayerDidMarkViewed(attachmentId: Attachment.IDType) } @@ -294,7 +296,10 @@ extension CVAudioPlayer: CVAudioPlaybackDelegate { progressCache[audioPlayback.attachmentId] = 0 for listener in listeners.elements { - listener.audioPlayerDidFinish(attachmentId: audioPlayback.attachmentId) + listener.audioPlayerDidFinish( + attachmentId: audioPlayback.attachmentId, + forInteractionId: audioPlayback.owningInteractionId, + ) } } } @@ -316,6 +321,7 @@ private class CVAudioPlayback: NSObject, AudioPlayerDelegate { fileprivate weak var delegate: CVAudioPlaybackDelegate? fileprivate let uniqueThreadId: String? + fileprivate let owningInteractionId: String? fileprivate let attachmentId: Attachment.IDType private let audioPlayer: AudioPlayer @@ -391,6 +397,7 @@ private class CVAudioPlayback: NSObject, AudioPlayerDelegate { audioPlayer = AudioPlayer(attachment: attachmentStream.attachmentStream, audioBehavior: .audioMessagePlayback) uniqueThreadId = attachment.owningMessage?.uniqueThreadId + owningInteractionId = attachment.owningMessage?.uniqueId super.init() diff --git a/Signal/ConversationView/CellViews/AudioMessageView.swift b/Signal/ConversationView/CellViews/AudioMessageView.swift index 14a26be9bcb..bf4ebbdfd65 100644 --- a/Signal/ConversationView/CellViews/AudioMessageView.swift +++ b/Signal/ConversationView/CellViews/AudioMessageView.swift @@ -492,7 +492,7 @@ class AudioMessageView: ManualStackView, CVAudioPlayerListener { updateContents(animated: true) } - func audioPlayerDidFinish(attachmentId: Attachment.IDType) { + func audioPlayerDidFinish(attachmentId: Attachment.IDType, forInteractionId interactionId: String?) { AssertIsOnMainThread() guard attachmentId == attachment.id else { return } diff --git a/Signal/ConversationView/Components/CVComponentAudioAttachment.swift b/Signal/ConversationView/Components/CVComponentAudioAttachment.swift index a88fb8023a2..588f16605b1 100644 --- a/Signal/ConversationView/Components/CVComponentAudioAttachment.swift +++ b/Signal/ConversationView/Components/CVComponentAudioAttachment.swift @@ -357,8 +357,12 @@ public class CVComponentAudioAttachment: CVComponentBase, CVComponent { extension CVComponentAudioAttachment: CVAudioPlayerListener { func audioPlayerStateDidChange(attachmentId: Attachment.IDType) {} - func audioPlayerDidFinish(attachmentId: Attachment.IDType) { + func audioPlayerDidFinish(attachmentId: Attachment.IDType, forInteractionId interactionId: String?) { guard attachmentId == audioAttachment.attachment.id else { return } + // Prevent a stale listener in a different conversation (sharing the + // same deduplicated attachment) from incorrectly triggering autoplay + // of its own, unrelated "next" message. + guard interactionId == self.interaction.uniqueId else { return } AppEnvironment.shared.cvAudioPlayerRef.autoplayNextAudioAttachmentIfNeeded(nextAudioAttachment) }