Change loader design

pull/288/head
nielsandriesse 5 years ago
parent f45a6ce00c
commit 0e03bba96e

@ -1,19 +1,12 @@
import Accelerate import Accelerate
@objc(LKVoiceMessageViewDelegate)
protocol VoiceMessageViewDelegate {
func showLoader()
func hideLoader()
}
@objc(LKVoiceMessageView) @objc(LKVoiceMessageView)
final class VoiceMessageView : UIView { final class VoiceMessageView : UIView {
private let voiceMessage: TSAttachment private let voiceMessage: TSAttachment
private let isOutgoing: Bool private let isOutgoing: Bool
private var isLoading = false
private var volumeSamples: [Float] = [] { didSet { updateShapeLayers() } } private var volumeSamples: [Float] = [] { didSet { updateShapeLayers() } }
private var progress: CGFloat = 0 @objc var progress: CGFloat = 0 { didSet { updateShapeLayers() } }
@objc var delegate: VoiceMessageViewDelegate?
@objc var duration: Int = 0 { didSet { updateDurationLabel() } } @objc var duration: Int = 0 { didSet { updateDurationLabel() } }
@objc var isPlaying = false { didSet { updateToggleImageView() } } @objc var isPlaying = false { didSet { updateToggleImageView() } }
@ -40,10 +33,11 @@ final class VoiceMessageView : UIView {
}() }()
// MARK: Settings // MARK: Settings
private let vMargin: CGFloat = 0 private let leadingInset: CGFloat = 0
private let sampleSpacing: CGFloat = 1 private let sampleSpacing: CGFloat = 1
private let targetSampleCount = 48
private let toggleContainerSize: CGFloat = 32 private let toggleContainerSize: CGFloat = 32
private let leadingInset: CGFloat = 0 private let vMargin: CGFloat = 0
@objc public static let contentHeight: CGFloat = 40 @objc public static let contentHeight: CGFloat = 40
@ -69,27 +63,24 @@ final class VoiceMessageView : 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.")
} }
let targetSampleCount = 48
if let cachedVolumeSamples = Storage.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount { if let cachedVolumeSamples = Storage.getVolumeSamples(for: voiceMessage.uniqueId!), cachedVolumeSamples.count == targetSampleCount {
self.hideLoader()
self.volumeSamples = cachedVolumeSamples self.volumeSamples = cachedVolumeSamples
self.delegate?.hideLoader()
} else { } else {
let voiceMessageID = voiceMessage.uniqueId! let voiceMessageID = voiceMessage.uniqueId!
AudioUtilities.getVolumeSamples(for: url, targetSampleCount: targetSampleCount).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.hideLoader()
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.delegate?.hideLoader()
}.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()
delegate?.showLoader()
} }
} }
@ -121,14 +112,30 @@ final class VoiceMessageView : UIView {
} }
// MARK: UI & Updating // MARK: UI & Updating
override func layoutSubviews() { private func showLoader() {
super.layoutSubviews() isLoading = true
updateShapeLayers() Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { [weak self] timer in
guard let self = self else { return timer.invalidate() }
if self.isLoading {
self.updateFakeVolumeSamples()
} else {
timer.invalidate()
}
}
updateFakeVolumeSamples()
}
private func updateFakeVolumeSamples() {
let fakeVolumeSamples = (0..<targetSampleCount).map { _ in Float.random(in: 0...1) }
volumeSamples = fakeVolumeSamples
}
private func hideLoader() {
isLoading = false
} }
@objc(updateForProgress:) override func layoutSubviews() {
func update(for progress: CGFloat) { super.layoutSubviews()
self.progress = progress
updateShapeLayers() updateShapeLayers()
} }
@ -153,7 +160,16 @@ final class VoiceMessageView : UIView {
} }
backgroundPath.close() backgroundPath.close()
foregroundPath.close() foregroundPath.close()
backgroundShapeLayer.path = backgroundPath.cgPath if isLoading {
let animation = CABasicAnimation(keyPath: "path")
animation.duration = 0.25
animation.toValue = backgroundPath
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
backgroundShapeLayer.add(animation, forKey: "path")
backgroundShapeLayer.path = backgroundPath.cgPath
} else {
backgroundShapeLayer.path = backgroundPath.cgPath
}
foregroundShapeLayer.path = foregroundPath.cgPath foregroundShapeLayer.path = foregroundPath.cgPath
} }

@ -20,7 +20,7 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageBubbleView () <OWSQuotedMessageViewDelegate, OWSContactShareButtonsViewDelegate, LKVoiceMessageViewDelegate> @interface OWSMessageBubbleView () <OWSQuotedMessageViewDelegate, OWSContactShareButtonsViewDelegate>
@property (nonatomic) OWSBubbleView *bubbleView; @property (nonatomic) OWSBubbleView *bubbleView;
@ -50,10 +50,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, nullable) OWSContactShareButtonsView *contactShareButtonsView; @property (nonatomic, nullable) OWSContactShareButtonsView *contactShareButtonsView;
@property (nonatomic) UIView *loader;
@property (nonatomic) BOOL isAnimating;
@end @end
#pragma mark - #pragma mark -
@ -112,10 +108,6 @@ NS_ASSUME_NONNULL_BEGIN
self.linkPreviewView = [[LinkPreviewView alloc] initWithDraftDelegate:nil]; self.linkPreviewView = [[LinkPreviewView alloc] initWithDraftDelegate:nil];
self.footerView = [OWSMessageFooterView new]; self.footerView = [OWSMessageFooterView new];
self.loader = [UIView new];
self.loader.backgroundColor = [LKColors.text colorWithAlphaComponent:0.6f];
self.loader.alpha = 0.0f;
} }
- (OWSMessageTextView *)newTextView - (OWSMessageTextView *)newTextView
@ -422,9 +414,6 @@ NS_ASSUME_NONNULL_BEGIN
addObject:[bodyMediaView autoSetDimension:ALDimensionHeight toSize:bodyMediaSize.CGSizeValue.height]]; addObject:[bodyMediaView autoSetDimension:ALDimensionHeight toSize:bodyMediaSize.CGSizeValue.height]];
} }
[self.bubbleView addSubview:self.loader];
[self.loader autoPinEdgesToSuperviewEdges];
[self insertContactShareButtonsIfNecessary]; [self insertContactShareButtonsIfNecessary];
[self updateBubbleColor]; [self updateBubbleColor];
@ -672,34 +661,6 @@ NS_ASSUME_NONNULL_BEGIN
} }
} }
- (void)showLoader
{
self.isAnimating = YES;
self.loader.alpha = 1.0f;
[self animateLoader];
}
- (void)animateLoader
{
__weak OWSMessageBubbleView *weakSelf = self;
self.loader.frame = CGRectMake(0.0f, 0.0f, 0.0f, self.frame.size.height);
[UIView animateWithDuration:2 animations:^{
if (weakSelf != nil) {
weakSelf.loader.frame = CGRectMake(0.0f, 0.0f, weakSelf.frame.size.width, weakSelf.frame.size.height);
}
} completion:^(BOOL isFinished) {
if (weakSelf != nil && weakSelf.isAnimating) {
[weakSelf animateLoader];
}
}];
}
- (void)hideLoader
{
self.isAnimating = NO;
self.loader.alpha = 0.0f;
}
#pragma mark - Subviews #pragma mark - Subviews
- (void)configureBodyTextView - (void)configureBodyTextView
@ -880,8 +841,7 @@ NS_ASSUME_NONNULL_BEGIN
LKVoiceMessageView *voiceMessageView = [[LKVoiceMessageView alloc] initWithVoiceMessage:attachment isOutgoing:self.isOutgoing]; LKVoiceMessageView *voiceMessageView = [[LKVoiceMessageView alloc] initWithVoiceMessage:attachment isOutgoing:self.isOutgoing];
[voiceMessageView setDuration:(int)self.viewItem.audioDurationSeconds]; [voiceMessageView setDuration:(int)self.viewItem.audioDurationSeconds];
[voiceMessageView updateForProgress:self.viewItem.audioProgressSeconds / self.viewItem.audioDurationSeconds]; [voiceMessageView setProgress:self.viewItem.audioProgressSeconds / self.viewItem.audioDurationSeconds];
[voiceMessageView setDelegate:self];
[voiceMessageView initialize]; [voiceMessageView initialize];
self.viewItem.lastAudioMessageView = voiceMessageView; self.viewItem.lastAudioMessageView = voiceMessageView;

@ -485,7 +485,7 @@ NSString *NSStringForOWSMessageCellType(OWSMessageCellType cellType)
self.audioProgressSeconds = progress; self.audioProgressSeconds = progress;
[self.lastAudioMessageView updateForProgress:progress / duration]; [self.lastAudioMessageView setProgress:progress / duration];
} }
#pragma mark - Displayable Text #pragma mark - Displayable Text

Loading…
Cancel
Save