From 9c0f5978ce1d266cf2dac4f673f1156fa45c8a6d Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 1 Oct 2020 18:15:48 +1000 Subject: [PATCH] Add duration label & debug --- .../Loki/Components/VoiceMessageView2.swift | 45 +++++++++++++------ .../src/Loki/Utilities/AudioUtilities.swift | 2 +- .../Cells/OWSMessageBubbleView.m | 1 + 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Signal/src/Loki/Components/VoiceMessageView2.swift b/Signal/src/Loki/Components/VoiceMessageView2.swift index 4b614dac0..86eaeab99 100644 --- a/Signal/src/Loki/Components/VoiceMessageView2.swift +++ b/Signal/src/Loki/Components/VoiceMessageView2.swift @@ -6,6 +6,7 @@ final class VoiceMessageView2 : UIView { private var isAnimating = false private var volumeSamples: [Float] = [] { didSet { updateShapeLayers() } } private var progress: CGFloat = 0 + @objc var duration: Int = 0 { didSet { updateDurationLabel() } } // MARK: Components private lazy var loader: UIView = { @@ -14,6 +15,13 @@ final class VoiceMessageView2 : UIView { return result }() + private lazy var durationLabel: UILabel = { + let result = UILabel() + result.textColor = Colors.text + result.font = .systemFont(ofSize: Values.mediumFontSize) + return result + }() + private lazy var backgroundShapeLayer: CAShapeLayer = { let result = CAShapeLayer() result.fillColor = Colors.text.cgColor @@ -27,10 +35,10 @@ final class VoiceMessageView2 : UIView { }() // MARK: Settings - private let margin: CGFloat = 4 + private let vMargin: CGFloat = 0 private let sampleSpacing: CGFloat = 1 - @objc public static let contentHeight: CGFloat = 40 + @objc public static let contentHeight: CGFloat = 32 // MARK: Initialization @objc(initWithVoiceMessage:) @@ -55,23 +63,26 @@ final class VoiceMessageView2 : UIView { guard let url = (voiceMessage as? TSAttachmentStream)?.originalMediaURL else { return print("[Loki] Couldn't get URL for voice message.") } - if let cachedVolumeSamples = Storage.getVolumeSamples(for: voiceMessage.uniqueId!) { + let targetSampleCount = 48 + if let cachedVolumeSamples = Storage.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount { self.volumeSamples = cachedVolumeSamples self.stopAnimating() } else { let voiceMessageID = voiceMessage.uniqueId! - AudioUtilities.getVolumeSamples(for: url).done(on: DispatchQueue.main) { [weak self] volumeSamples in + AudioUtilities.getVolumeSamples(for: url, targetSampleCount: targetSampleCount).done(on: DispatchQueue.main) { [weak self] volumeSamples in guard let self = self else { return } self.volumeSamples = volumeSamples Storage.write { transaction in Storage.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction) } + self.durationLabel.alpha = 1 self.stopAnimating() }.catch(on: DispatchQueue.main) { error in print("[Loki] Couldn't sample audio file due to error: \(error).") } } } else { + durationLabel.alpha = 0 showLoader() } } @@ -83,6 +94,9 @@ final class VoiceMessageView2 : UIView { loader.pin(to: self) layer.insertSublayer(backgroundShapeLayer, at: 0) layer.insertSublayer(foregroundShapeLayer, at: 1) + addSubview(durationLabel) + durationLabel.center(.vertical, in: self) + durationLabel.pin(.trailing, to: .trailing, of: self) } // MARK: UI & Updating @@ -120,18 +134,18 @@ final class VoiceMessageView2 : UIView { private func updateShapeLayers() { guard !volumeSamples.isEmpty else { return } - let max = CGFloat(volumeSamples.max()!) - let min = CGFloat(volumeSamples.min()!) - let w = width() - 2 * margin - let h = height() - 2 * margin - let sW = (w - sampleSpacing * CGFloat(volumeSamples.count)) / CGFloat(volumeSamples.count) + let sMin = CGFloat(volumeSamples.min()!) + let sMax = CGFloat(volumeSamples.max()!) + let w = width() - durationLabel.width() - Values.smallSpacing + let h = height() - 2 * vMargin + let sW = (w - sampleSpacing * CGFloat(volumeSamples.count - 1)) / CGFloat(volumeSamples.count) let backgroundPath = UIBezierPath() let foregroundPath = UIBezierPath() for (i, value) in volumeSamples.enumerated() { - let x = margin + CGFloat(i) * (sW + sampleSpacing) - let fraction = (CGFloat(value) - min) / (max - min) - let sH = h * fraction - let y = margin + (h - sH) / 2 + let x = CGFloat(i) * (sW + sampleSpacing) + let fraction = (CGFloat(value) - sMin) / (sMax - sMin) + let sH = max(8, h * fraction) + let y = vMargin + (h - sH) / 2 let subPath = UIBezierPath(roundedRect: CGRect(x: x, y: y, width: sW, height: sH), cornerRadius: sW / 2) backgroundPath.append(subPath) if progress > CGFloat(i) / CGFloat(volumeSamples.count) { foregroundPath.append(subPath) } @@ -141,4 +155,9 @@ final class VoiceMessageView2 : UIView { backgroundShapeLayer.path = backgroundPath.cgPath foregroundShapeLayer.path = foregroundPath.cgPath } + + private func updateDurationLabel() { + durationLabel.text = OWSFormat.formatDurationSeconds(duration) + updateShapeLayers() + } } diff --git a/Signal/src/Loki/Utilities/AudioUtilities.swift b/Signal/src/Loki/Utilities/AudioUtilities.swift index b009b1a1c..8a0316882 100644 --- a/Signal/src/Loki/Utilities/AudioUtilities.swift +++ b/Signal/src/Loki/Utilities/AudioUtilities.swift @@ -27,7 +27,7 @@ enum AudioUtilities { } } - static func getVolumeSamples(for audioFileURL: URL, targetSampleCount: Int = 32) -> Promise<[Float]> { + static func getVolumeSamples(for audioFileURL: URL, targetSampleCount: Int) -> Promise<[Float]> { return loadFile(audioFileURL).then { fileInfo in AudioUtilities.parseSamples(from: fileInfo, with: targetSampleCount) } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m index d75bf7327..b34f0b99a 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageBubbleView.m @@ -840,6 +840,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug([attachment isAudio]); LKVoiceMessageView2 *voiceMessageView = [[LKVoiceMessageView2 alloc] initWithVoiceMessage:attachment]; + voiceMessageView.duration = (int)self.viewItem.audioDurationSeconds; self.viewItem.lastAudioMessageView = voiceMessageView;