mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Add duration label & debug
This commit is contained in:
parent
15b336f42a
commit
9c0f5978ce
|
@ -6,6 +6,7 @@ final class VoiceMessageView2 : UIView {
|
||||||
private var isAnimating = false
|
private var isAnimating = false
|
||||||
private var volumeSamples: [Float] = [] { didSet { updateShapeLayers() } }
|
private var volumeSamples: [Float] = [] { didSet { updateShapeLayers() } }
|
||||||
private var progress: CGFloat = 0
|
private var progress: CGFloat = 0
|
||||||
|
@objc var duration: Int = 0 { didSet { updateDurationLabel() } }
|
||||||
|
|
||||||
// MARK: Components
|
// MARK: Components
|
||||||
private lazy var loader: UIView = {
|
private lazy var loader: UIView = {
|
||||||
|
@ -14,6 +15,13 @@ final class VoiceMessageView2 : UIView {
|
||||||
return result
|
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 = {
|
private lazy var backgroundShapeLayer: CAShapeLayer = {
|
||||||
let result = CAShapeLayer()
|
let result = CAShapeLayer()
|
||||||
result.fillColor = Colors.text.cgColor
|
result.fillColor = Colors.text.cgColor
|
||||||
|
@ -27,10 +35,10 @@ final class VoiceMessageView2 : UIView {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// MARK: Settings
|
// MARK: Settings
|
||||||
private let margin: CGFloat = 4
|
private let vMargin: CGFloat = 0
|
||||||
private let sampleSpacing: CGFloat = 1
|
private let sampleSpacing: CGFloat = 1
|
||||||
|
|
||||||
@objc public static let contentHeight: CGFloat = 40
|
@objc public static let contentHeight: CGFloat = 32
|
||||||
|
|
||||||
// MARK: Initialization
|
// MARK: Initialization
|
||||||
@objc(initWithVoiceMessage:)
|
@objc(initWithVoiceMessage:)
|
||||||
|
@ -55,23 +63,26 @@ final class VoiceMessageView2 : UIView {
|
||||||
guard let url = (voiceMessage as? TSAttachmentStream)?.originalMediaURL else {
|
guard let url = (voiceMessage as? TSAttachmentStream)?.originalMediaURL else {
|
||||||
return print("[Loki] Couldn't get URL for voice message.")
|
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.volumeSamples = cachedVolumeSamples
|
||||||
self.stopAnimating()
|
self.stopAnimating()
|
||||||
} else {
|
} else {
|
||||||
let voiceMessageID = voiceMessage.uniqueId!
|
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 }
|
guard let self = self else { return }
|
||||||
self.volumeSamples = volumeSamples
|
self.volumeSamples = volumeSamples
|
||||||
Storage.write { transaction in
|
Storage.write { transaction in
|
||||||
Storage.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction)
|
Storage.setVolumeSamples(for: voiceMessageID, to: volumeSamples, using: transaction)
|
||||||
}
|
}
|
||||||
|
self.durationLabel.alpha = 1
|
||||||
self.stopAnimating()
|
self.stopAnimating()
|
||||||
}.catch(on: DispatchQueue.main) { error in
|
}.catch(on: DispatchQueue.main) { error in
|
||||||
print("[Loki] Couldn't sample audio file due to error: \(error).")
|
print("[Loki] Couldn't sample audio file due to error: \(error).")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
durationLabel.alpha = 0
|
||||||
showLoader()
|
showLoader()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,6 +94,9 @@ final class VoiceMessageView2 : UIView {
|
||||||
loader.pin(to: self)
|
loader.pin(to: self)
|
||||||
layer.insertSublayer(backgroundShapeLayer, at: 0)
|
layer.insertSublayer(backgroundShapeLayer, at: 0)
|
||||||
layer.insertSublayer(foregroundShapeLayer, at: 1)
|
layer.insertSublayer(foregroundShapeLayer, at: 1)
|
||||||
|
addSubview(durationLabel)
|
||||||
|
durationLabel.center(.vertical, in: self)
|
||||||
|
durationLabel.pin(.trailing, to: .trailing, of: self)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: UI & Updating
|
// MARK: UI & Updating
|
||||||
|
@ -120,18 +134,18 @@ final class VoiceMessageView2 : UIView {
|
||||||
|
|
||||||
private func updateShapeLayers() {
|
private func updateShapeLayers() {
|
||||||
guard !volumeSamples.isEmpty else { return }
|
guard !volumeSamples.isEmpty else { return }
|
||||||
let max = CGFloat(volumeSamples.max()!)
|
let sMin = CGFloat(volumeSamples.min()!)
|
||||||
let min = CGFloat(volumeSamples.min()!)
|
let sMax = CGFloat(volumeSamples.max()!)
|
||||||
let w = width() - 2 * margin
|
let w = width() - durationLabel.width() - Values.smallSpacing
|
||||||
let h = height() - 2 * margin
|
let h = height() - 2 * vMargin
|
||||||
let sW = (w - sampleSpacing * CGFloat(volumeSamples.count)) / CGFloat(volumeSamples.count)
|
let sW = (w - sampleSpacing * CGFloat(volumeSamples.count - 1)) / CGFloat(volumeSamples.count)
|
||||||
let backgroundPath = UIBezierPath()
|
let backgroundPath = UIBezierPath()
|
||||||
let foregroundPath = UIBezierPath()
|
let foregroundPath = UIBezierPath()
|
||||||
for (i, value) in volumeSamples.enumerated() {
|
for (i, value) in volumeSamples.enumerated() {
|
||||||
let x = margin + CGFloat(i) * (sW + sampleSpacing)
|
let x = CGFloat(i) * (sW + sampleSpacing)
|
||||||
let fraction = (CGFloat(value) - min) / (max - min)
|
let fraction = (CGFloat(value) - sMin) / (sMax - sMin)
|
||||||
let sH = h * fraction
|
let sH = max(8, h * fraction)
|
||||||
let y = margin + (h - sH) / 2
|
let y = vMargin + (h - sH) / 2
|
||||||
let subPath = UIBezierPath(roundedRect: CGRect(x: x, y: y, width: sW, height: sH), cornerRadius: sW / 2)
|
let subPath = UIBezierPath(roundedRect: CGRect(x: x, y: y, width: sW, height: sH), cornerRadius: sW / 2)
|
||||||
backgroundPath.append(subPath)
|
backgroundPath.append(subPath)
|
||||||
if progress > CGFloat(i) / CGFloat(volumeSamples.count) { foregroundPath.append(subPath) }
|
if progress > CGFloat(i) / CGFloat(volumeSamples.count) { foregroundPath.append(subPath) }
|
||||||
|
@ -141,4 +155,9 @@ final class VoiceMessageView2 : UIView {
|
||||||
backgroundShapeLayer.path = backgroundPath.cgPath
|
backgroundShapeLayer.path = backgroundPath.cgPath
|
||||||
foregroundShapeLayer.path = foregroundPath.cgPath
|
foregroundShapeLayer.path = foregroundPath.cgPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateDurationLabel() {
|
||||||
|
durationLabel.text = OWSFormat.formatDurationSeconds(duration)
|
||||||
|
updateShapeLayers()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
return loadFile(audioFileURL).then { fileInfo in
|
||||||
AudioUtilities.parseSamples(from: fileInfo, with: targetSampleCount)
|
AudioUtilities.parseSamples(from: fileInfo, with: targetSampleCount)
|
||||||
}
|
}
|
||||||
|
|
|
@ -840,6 +840,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
OWSAssertDebug([attachment isAudio]);
|
OWSAssertDebug([attachment isAudio]);
|
||||||
|
|
||||||
LKVoiceMessageView2 *voiceMessageView = [[LKVoiceMessageView2 alloc] initWithVoiceMessage:attachment];
|
LKVoiceMessageView2 *voiceMessageView = [[LKVoiceMessageView2 alloc] initWithVoiceMessage:attachment];
|
||||||
|
voiceMessageView.duration = (int)self.viewItem.audioDurationSeconds;
|
||||||
|
|
||||||
self.viewItem.lastAudioMessageView = voiceMessageView;
|
self.viewItem.lastAudioMessageView = voiceMessageView;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue