mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-19 08:03:50 +02:00
#4090 - New voice recording toolbar ui and swipe to cancel interaction.
This commit is contained in:
committed by
Stefan Ceriu
parent
53b2b05b15
commit
fbb451f33c
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
private enum VoiceMessageToolbarViewState {
|
||||
case idle
|
||||
case recording
|
||||
}
|
||||
|
||||
class VoiceMessageToolbarView: PassthroughView, Themable, UIGestureRecognizerDelegate {
|
||||
|
||||
@IBOutlet private var backgroundView: UIView!
|
||||
|
||||
@IBOutlet private var recordButtonsContainerView: UIView!
|
||||
@IBOutlet private var primaryRecordButton: UIButton!
|
||||
@IBOutlet private var secondaryRecordButton: UIButton!
|
||||
|
||||
@IBOutlet private var slideToCancelContainerView: UIView!
|
||||
@IBOutlet private var slideToCancelLabel: UILabel!
|
||||
@IBOutlet private var slideToCancelChevron: UIImageView!
|
||||
@IBOutlet private var slideToCancelFade: UIImageView!
|
||||
|
||||
private var cancelLabelToRecordButtonDistance: CGFloat = 0.0
|
||||
|
||||
private var state: VoiceMessageToolbarViewState = .idle {
|
||||
didSet {
|
||||
updateUIAnimated(true)
|
||||
}
|
||||
}
|
||||
|
||||
private var currentTheme: Theme? {
|
||||
didSet {
|
||||
updateUIAnimated(true)
|
||||
}
|
||||
}
|
||||
|
||||
@objc static func instanceFromNib() -> VoiceMessageToolbarView {
|
||||
let nib = UINib(nibName: "VoiceMessageToolbarView", bundle: nil)
|
||||
guard let view = nib.instantiate(withOwner: nil, options: nil).first as? Self else {
|
||||
fatalError("The nib \(nib) expected its root view to be of type \(self)")
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
|
||||
longPressGesture.delegate = self
|
||||
longPressGesture.minimumPressDuration = 0.1
|
||||
recordButtonsContainerView.addGestureRecognizer(longPressGesture)
|
||||
|
||||
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
|
||||
longPressGesture.delegate = self
|
||||
recordButtonsContainerView.addGestureRecognizer(panGesture)
|
||||
|
||||
updateUIAnimated(false)
|
||||
}
|
||||
|
||||
// MARK: - Themable
|
||||
|
||||
func update(theme: Theme) {
|
||||
currentTheme = theme
|
||||
}
|
||||
|
||||
// MARK: - UIGestureRecognizerDelegate
|
||||
|
||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@objc private func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||
switch gestureRecognizer.state {
|
||||
case UIGestureRecognizer.State.began:
|
||||
state = .recording
|
||||
|
||||
let convertedFrame = self.convert(slideToCancelLabel.frame, from: slideToCancelContainerView)
|
||||
cancelLabelToRecordButtonDistance = recordButtonsContainerView.frame.minX - convertedFrame.maxX
|
||||
|
||||
case UIGestureRecognizer.State.ended:
|
||||
state = .idle
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
||||
guard self.state == .recording && gestureRecognizer.state == .changed else {
|
||||
return
|
||||
}
|
||||
|
||||
let translation = gestureRecognizer.translation(in: self)
|
||||
|
||||
recordButtonsContainerView.transform = CGAffineTransform(translationX: min(translation.x, 0.0), y: 0.0)
|
||||
slideToCancelContainerView.transform = CGAffineTransform(translationX: min(translation.x + cancelLabelToRecordButtonDistance, 0.0), y: 0.0)
|
||||
}
|
||||
|
||||
private func updateUIAnimated(_ animated: Bool) {
|
||||
UIView.animate(withDuration: (animated ? 0.25 : 0.0)) {
|
||||
switch self.state {
|
||||
case .idle:
|
||||
self.slideToCancelContainerView.alpha = 0.0
|
||||
self.backgroundView.alpha = 0.0
|
||||
self.slideToCancelFade.alpha = 0.0
|
||||
self.recordButtonsContainerView.transform = .identity
|
||||
self.slideToCancelContainerView.transform = .identity
|
||||
self.primaryRecordButton.alpha = 1.0
|
||||
self.secondaryRecordButton.alpha = 0.0
|
||||
case .recording:
|
||||
self.slideToCancelContainerView.alpha = 1.0
|
||||
self.backgroundView.alpha = 1.0
|
||||
self.slideToCancelFade.alpha = 1.0
|
||||
self.primaryRecordButton.alpha = 0.0
|
||||
self.secondaryRecordButton.alpha = 1.0
|
||||
}
|
||||
|
||||
guard let theme = self.currentTheme else {
|
||||
return
|
||||
}
|
||||
|
||||
self.backgroundView.backgroundColor = theme.backgroundColor
|
||||
self.primaryRecordButton.tintColor = theme.textSecondaryColor
|
||||
self.slideToCancelLabel.textColor = theme.textSecondaryColor
|
||||
self.slideToCancelChevron.tintColor = theme.textSecondaryColor
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user