diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVAudioPlayback.swift b/Signal/src/ViewControllers/ConversationView/CV/CVAudioPlayback.swift index 65840cb1ed..68209863e8 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVAudioPlayback.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVAudioPlayback.swift @@ -143,6 +143,7 @@ public class CVAudioPlayer: NSObject { DispatchQueue.main.async { // Make sure the user didn't start another attachment while the tone was playing. guard self?.autoplayAttachmentId == attachmentStream.uniqueId else { return } + guard self?.audioPlayback?.attachmentId == attachmentStream.uniqueId else { return } guard audioPlayback.audioPlaybackState != .playing else { return } if audioAttachment.markOwningMessageAsViewed() { @@ -197,6 +198,7 @@ extension CVAudioPlayer: CVAudioPlaybackDelegate { switch audioPlayback.audioPlaybackState { case .playing: + if audioPlayback != self.audioPlayback { audioPlayback.togglePlayState() } progressCache[audioPlayback.attachmentId] = audioPlayback.progress case .stopped: progressCache[audioPlayback.attachmentId] = 0 diff --git a/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentAudioAttachment.swift b/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentAudioAttachment.swift index 646bff1065..8827aa2a72 100644 --- a/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentAudioAttachment.swift +++ b/Signal/src/ViewControllers/ConversationView/CV/CVComponents/CVComponentAudioAttachment.swift @@ -51,9 +51,9 @@ public class CVComponentAudioAttachment: CVComponentBase, CVComponent { cellMeasurement: cellMeasurement, componentDelegate: componentDelegate) let footerRootView = footerView.rootView - stackView.addSubview(footerRootView) + let footerSize = cellMeasurement.size(key: Self.measurementKey_footerSize) ?? .zero - stackView.addLayoutBlock { view in + stackView.addSubview(footerRootView) { view in var footerFrame = view.bounds footerFrame.height = min(view.bounds.height, footerSize.height) footerFrame.y = view.bounds.height - footerSize.height diff --git a/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift b/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift index 98abaf7a1a..6c6fa16804 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift +++ b/Signal/src/ViewControllers/ConversationView/Cells/AudioMessageView.swift @@ -31,13 +31,13 @@ class AudioMessageView: ManualStackView { private weak var componentDelegate: CVComponentDelegate! private let playedDotAnimation = AnimationView(name: "audio-played-dot") - private let playedDotContainer = OWSLayerView() + private let playedDotContainer = ManualLayoutView(name: "playedDotContainer") private let playPauseAnimation = AnimationView(name: "playPauseButton") - private let playPauseContainer = OWSLayerView() + private let playPauseContainer = ManualLayoutView.circleView(name: "playPauseContainer") private let playbackTimeLabel = CVLabel() private let progressSlider = UISlider() private let waveformProgress = AudioWaveformProgressView() - private let waveformContainer = OWSLayerView() + private let waveformContainer = ManualLayoutView(name: "waveformContainer") private var audioPlaybackState: AudioPlaybackState { cvAudioPlayer.audioPlaybackState(forAttachmentId: attachment.uniqueId) @@ -82,19 +82,14 @@ class AudioMessageView: ManualStackView { waveformProgress.playedColor = playedColor waveformProgress.unplayedColor = unplayedColor waveformProgress.thumbColor = thumbColor - waveformContainer.addSubview(waveformProgress) + waveformContainer.addSubviewToFillSuperviewEdges(waveformProgress) progressSlider.setThumbImage(UIImage(named: "audio_message_thumb")?.asTintedImage(color: thumbColor), for: .normal) progressSlider.setMinimumTrackImage(trackImage(color: playedColor), for: .normal) progressSlider.setMaximumTrackImage(trackImage(color: unplayedColor), for: .normal) - waveformContainer.addSubview(progressSlider) progressSlider.isEnabled = isDownloaded - let waveformProgress = self.waveformProgress - let progressSlider = self.progressSlider - waveformContainer.layoutCallback = { view in - waveformProgress.frame = view.bounds - + waveformContainer.addSubview(progressSlider) { [progressSlider] view in var sliderFrame = view.bounds sliderFrame.height = 12 sliderFrame.y = (view.bounds.height - sliderFrame.height) * 0.5 @@ -137,24 +132,9 @@ class AudioMessageView: ManualStackView { playPauseContainer.backgroundColor = isIncoming ? (Theme.isDarkThemeEnabled ? .ows_gray60 : .ows_whiteAlpha80) : .ows_whiteAlpha20 - playPauseContainer.addSubview(playPauseAnimation) - playPauseContainer.layoutCallback = { view in - view.layer.cornerRadius = view.height / 2 - playPauseAnimation.frame.size = CGSize(square: 24) - playPauseAnimation.frame.origin = CGPoint( - x: (view.width / 2) - (playPauseAnimation.width / 2), - y: (view.height / 2) - (playPauseAnimation.height / 2) - ) - } + playPauseContainer.addSubviewToCenterOnSuperview(playPauseAnimation, size: CGSize(square: 24)) - playedDotContainer.addSubview(playedDotAnimation) - playedDotContainer.layoutCallback = { view in - playedDotAnimation.frame.size = CGSize(square: 16) - playedDotAnimation.frame.origin = CGPoint( - x: (view.width / 2) - (playedDotAnimation.width / 2), - y: (view.height / 2) - (playedDotAnimation.height / 2) - ) - } + playedDotContainer.addSubviewToCenterOnSuperview(playedDotAnimation, size: CGSize(square: 16)) leftView = playPauseContainer } else if let attachmentPointer = audioAttachment.attachmentPointer { @@ -523,12 +503,16 @@ extension AudioMessageView: CVAudioPlayerListener { func audioPlayerStateDidChange(attachmentId: String) { AssertIsOnMainThread() + guard attachmentId == attachment.uniqueId else { return } + updateContents(animated: true) } func audioPlayerDidFinish(attachmentId: String) { AssertIsOnMainThread() + guard attachmentId == attachment.uniqueId else { return } + updateContents(animated: true) } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController+CVC.swift b/Signal/src/ViewControllers/ConversationView/ConversationViewController+CVC.swift index b740ef4039..91d8383029 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController+CVC.swift +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController+CVC.swift @@ -67,7 +67,7 @@ extension ConversationViewController { @objc public var areCellsAnimating: Bool { - !viewState.activeCellAnimations.isEmpty + viewState.activeCellAnimations.count > 0 } } diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 2a8857a254..690a577be3 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -4530,6 +4530,11 @@ typedef enum : NSUInteger { { OWSAssertIsOnMainThread(); + if (maximumDuration > 0.5) { + OWSFailDebug(@"Animation is too long, skipping."); + return ^{}; + } + NSUUID *identifier = [NSUUID new]; [self.viewState beginCellAnimationWithIdentifier:identifier]; diff --git a/SignalServiceKit/src/Messages/OWSReceiptManager.m b/SignalServiceKit/src/Messages/OWSReceiptManager.m index 29e2eccfca..edce9b17e8 100644 --- a/SignalServiceKit/src/Messages/OWSReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReceiptManager.m @@ -502,9 +502,9 @@ NSString *const OWSReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsEnabl OWSFailDebug(@"thread was unexpectedly nil"); continue; } - NSTimeInterval secondsSinceRead = [NSDate new].timeIntervalSince1970 - viewedTimestamp / 1000; + NSTimeInterval secondsSinceViewed = [NSDate new].timeIntervalSince1970 - viewedTimestamp / 1000; OWSAssertDebug([message isKindOfClass:[TSMessage class]]); - OWSLogDebug(@"viewed on linked device %f seconds ago", secondsSinceRead); + OWSLogDebug(@"viewed on linked device %f seconds ago", secondsSinceViewed); [self markAsViewedOnLinkedDevice:message thread:thread viewedTimestamp:viewedTimestamp