From c4a7c31672ec8c308b16f8c11f0ec9373a9264d8 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 16 Feb 2021 14:22:39 +1100 Subject: [PATCH] Implement lock view --- .../VoiceMessageRecordingView.swift | 106 ++++++++++++++---- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/Session/Conversations V2/Input View/VoiceMessageRecordingView.swift b/Session/Conversations V2/Input View/VoiceMessageRecordingView.swift index 91107aaa2..6b3655b0b 100644 --- a/Session/Conversations V2/Input View/VoiceMessageRecordingView.swift +++ b/Session/Conversations V2/Input View/VoiceMessageRecordingView.swift @@ -5,6 +5,7 @@ final class VoiceMessageRecordingView : UIView { private lazy var slideToCancelLabelCenterHorizontalConstraint = slideToCancelLabel.center(.horizontal, in: self) private lazy var pulseViewWidthConstraint = pulseView.set(.width, to: VoiceMessageRecordingView.circleSize) private lazy var pulseViewHeightConstraint = pulseView.set(.height, to: VoiceMessageRecordingView.circleSize) + private lazy var lockViewBottomConstraint = lockView.pin(.bottom, to: .top, of: self, withInset: Values.mediumSpacing) private let recordingStartDate = Date() private var recordingTimer: Timer? @@ -61,6 +62,8 @@ final class VoiceMessageRecordingView : UIView { return result }() + private lazy var lockView = LockView() + // MARK: Settings private static let circleSize: CGFloat = 96 private static let pulseSize: CGFloat = 24 @@ -117,7 +120,7 @@ final class VoiceMessageRecordingView : UIView { pulseView.center(in: circleView) // Slide to cancel stack view let chevronSize = VoiceMessageRecordingView.chevronSize - let chevronColor = Colors.text.withAlphaComponent(Values.mediumOpacity) + let chevronColor = (isLightMode ? UIColor.black : UIColor.white).withAlphaComponent(Values.mediumOpacity) let chevronImageView = UIImageView(image: UIImage(named: "small_chevron_left")!.withTint(chevronColor)) chevronImageView.contentMode = .scaleAspectFit chevronImageView.set(.width, to: chevronSize) @@ -134,13 +137,9 @@ final class VoiceMessageRecordingView : UIView { durationStackView.pin(.left, to: .left, of: self, withInset: Values.largeSpacing) durationStackView.center(.vertical, in: iconImageView) // Lock view - let lockView = UIView() - lockView.backgroundColor = .blue - lockView.set(.width, to: 60) - lockView.set(.height, to: 60) addSubview(lockView) - lockView.pin(.bottom, to: .top, of: self, withInset: -40) lockView.center(.horizontal, in: iconImageView) + lockViewBottomConstraint.isActive = true } // MARK: Updating @@ -152,30 +151,33 @@ final class VoiceMessageRecordingView : UIView { // MARK: Animation func animate() { layoutIfNeeded() - self.slideToCancelStackViewRightConstraint.isActive = false - self.slideToCancelLabelCenterHorizontalConstraint.isActive = true - UIView.animate(withDuration: 0.25, animations: { + slideToCancelStackViewRightConstraint.isActive = false + slideToCancelLabelCenterHorizontalConstraint.isActive = true + lockViewBottomConstraint.constant = -Values.mediumSpacing + UIView.animate(withDuration: 0.25, animations: { [weak self] in + guard let self = self else { return } self.alpha = 1 self.layoutIfNeeded() - }, completion: { _ in + }, completion: { [weak self] _ in + guard let self = self else { return } self.fadeOutDotView() self.pulse() }) } private func fadeOutDotView() { - UIView.animate(withDuration: 0.5, animations: { - self.dotView.alpha = 0 - }, completion: { _ in - self.fadeInDotView() + UIView.animate(withDuration: 0.5, animations: { [weak self] in + self?.dotView.alpha = 0 + }, completion: { [weak self] _ in + self?.fadeInDotView() }) } private func fadeInDotView() { - UIView.animate(withDuration: 0.5, animations: { - self.dotView.alpha = 1 - }, completion: { _ in - self.fadeOutDotView() + UIView.animate(withDuration: 0.5, animations: { [weak self] in + self?.dotView.alpha = 1 + }, completion: { [weak self] _ in + self?.fadeOutDotView() }) } @@ -186,12 +188,14 @@ final class VoiceMessageRecordingView : UIView { let expandedFrame = CGRect(center: pulseView.center, size: CGSize(width: expandedSize, height: expandedSize)) pulseViewWidthConstraint.constant = expandedSize pulseViewHeightConstraint.constant = expandedSize - UIView.animate(withDuration: 1, animations: { + UIView.animate(withDuration: 1, animations: { [weak self] in + guard let self = self else { return } self.layoutIfNeeded() self.pulseView.frame = expandedFrame self.pulseView.layer.cornerRadius = expandedSize / 2 self.pulseView.alpha = 0 - }, completion: { _ in + }, completion: { [weak self] _ in + guard let self = self else { return } self.pulseViewWidthConstraint.constant = collapsedSize self.pulseViewHeightConstraint.constant = collapsedSize self.pulseView.frame = collapsedFrame @@ -201,3 +205,65 @@ final class VoiceMessageRecordingView : UIView { }) } } + +// MARK: Lock View +extension VoiceMessageRecordingView { + + fileprivate final class LockView : UIView { + + private static let width: CGFloat = 44 + private static let lockIconSize: CGFloat = 20 + private static let chevronIconSize: CGFloat = 20 + + override init(frame: CGRect) { + super.init(frame: frame) + setUpViewHierarchy() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUpViewHierarchy() + } + + private func setUpViewHierarchy() { + let iconTint: UIColor = isLightMode ? .black : .white + // Background & blur + let backgroundView = UIView() + backgroundView.backgroundColor = isLightMode ? .white : .black + backgroundView.alpha = Values.lowOpacity + addSubview(backgroundView) + backgroundView.pin(to: self) + let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .regular)) + addSubview(blurView) + blurView.pin(to: self) + // Size & shape + let width = LockView.width + set(.width, to: width) + layer.cornerRadius = width / 2 + layer.masksToBounds = true + // Border + layer.borderWidth = 1 + let borderColor = (isLightMode ? UIColor.black : UIColor.white).withAlphaComponent(Values.veryLowOpacity) + layer.borderColor = borderColor.cgColor + // Lock icon + let lockIconImageView = UIImageView(image: UIImage(named: "ic_lock_outline")!.withTint(iconTint)) + let lockIconSize = LockView.lockIconSize + lockIconImageView.set(.width, to: lockIconSize) + lockIconImageView.set(.height, to: lockIconSize) + // Chevron icon + let chevronIconImageView = UIImageView(image: UIImage(named: "ic_chevron_up")!.withTint(iconTint)) + let chevronIconSize = LockView.chevronIconSize + chevronIconImageView.set(.width, to: chevronIconSize) + chevronIconImageView.set(.height, to: chevronIconSize) + // Stack view + let stackView = UIStackView(arrangedSubviews: [ lockIconImageView, chevronIconImageView ]) + stackView.axis = .vertical + stackView.spacing = Values.smallSpacing + stackView.alignment = .center + stackView.isLayoutMarginsRelativeArrangement = true + stackView.layoutMargins = UIEdgeInsets(top: 12, leading: 0, bottom: 8, trailing: 0) + addSubview(stackView) + stackView.pin(to: self) + } + } +}