Minimize use of implicitly unwrapped optionals in code.
And mark `init(coder:)` as unavailable.
This commit is contained in:
parent
09048dad07
commit
45db3a963e
@ -562,7 +562,7 @@ private class TitleView: UIView {
|
|||||||
|
|
||||||
private let label = UILabel()
|
private let label = UILabel()
|
||||||
private let iconView = UIImageView()
|
private let iconView = UIImageView()
|
||||||
private var stackView: UIStackView!
|
private let stackView: UIStackView
|
||||||
|
|
||||||
// Returns same font as UIBarButtonItem uses.
|
// Returns same font as UIBarButtonItem uses.
|
||||||
private func titleLabelFont() -> UIFont {
|
private func titleLabelFont() -> UIFont {
|
||||||
@ -573,18 +573,10 @@ private class TitleView: UIView {
|
|||||||
// MARK: - Initializers
|
// MARK: - Initializers
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
|
||||||
commonInit()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
stackView = UIStackView(arrangedSubviews: [label, iconView])
|
stackView = UIStackView(arrangedSubviews: [label, iconView])
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
stackView.axis = .horizontal
|
stackView.axis = .horizontal
|
||||||
stackView.alignment = .center
|
stackView.alignment = .center
|
||||||
stackView.spacing = 5
|
stackView.spacing = 5
|
||||||
@ -605,6 +597,11 @@ private class TitleView: UIView {
|
|||||||
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped)))
|
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
override func tintColorDidChange() {
|
override func tintColorDidChange() {
|
||||||
super.tintColorDidChange()
|
super.tintColorDidChange()
|
||||||
label.textColor = tintColor
|
label.textColor = tintColor
|
||||||
|
|||||||
@ -40,8 +40,8 @@ class CameraCaptureControl: UIView {
|
|||||||
private static let shutterButtonDefaultSize: CGFloat = 72
|
private static let shutterButtonDefaultSize: CGFloat = 72
|
||||||
private static let shutterButtonRecordingSize: CGFloat = 122
|
private static let shutterButtonRecordingSize: CGFloat = 122
|
||||||
|
|
||||||
private var outerCircleSizeConstraint: NSLayoutConstraint!
|
private let outerCircleSizeConstraint: NSLayoutConstraint
|
||||||
private var innerCircleSizeConstraint: NSLayoutConstraint!
|
private let innerCircleSizeConstraint: NSLayoutConstraint
|
||||||
private var slidingCircleHPositionConstraint: NSLayoutConstraint!
|
private var slidingCircleHPositionConstraint: NSLayoutConstraint!
|
||||||
private var slidingCircleVPositionConstraint: NSLayoutConstraint!
|
private var slidingCircleVPositionConstraint: NSLayoutConstraint!
|
||||||
|
|
||||||
@ -67,23 +67,13 @@ class CameraCaptureControl: UIView {
|
|||||||
|
|
||||||
weak var delegate: CameraCaptureControlDelegate?
|
weak var delegate: CameraCaptureControlDelegate?
|
||||||
|
|
||||||
convenience init(axis: NSLayoutConstraint.Axis) {
|
required init(axis: NSLayoutConstraint.Axis) {
|
||||||
self.init(frame: CGRect(origin: .zero, size: CameraCaptureControl.intrinsicContentSize(forAxis: axis)))
|
innerCircleSizeConstraint = shutterButtonInnerCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize)
|
||||||
|
outerCircleSizeConstraint = shutterButtonOuterCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize)
|
||||||
|
|
||||||
|
super.init(frame: CGRect(origin: .zero, size: CameraCaptureControl.intrinsicContentSize(forAxis: axis)))
|
||||||
|
|
||||||
self.axis = axis
|
self.axis = axis
|
||||||
reactivateConstraintsForCurrentAxis()
|
|
||||||
}
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
|
|
||||||
// Round Shutter Button
|
// Round Shutter Button
|
||||||
addLayoutGuide(shutterButtonLayoutGuide)
|
addLayoutGuide(shutterButtonLayoutGuide)
|
||||||
@ -104,11 +94,9 @@ class CameraCaptureControl: UIView {
|
|||||||
addSubview(shutterButtonOuterCircle)
|
addSubview(shutterButtonOuterCircle)
|
||||||
shutterButtonOuterCircle.centerXAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerXAnchor).isActive = true
|
shutterButtonOuterCircle.centerXAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerXAnchor).isActive = true
|
||||||
shutterButtonOuterCircle.centerYAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerYAnchor).isActive = true
|
shutterButtonOuterCircle.centerYAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerYAnchor).isActive = true
|
||||||
outerCircleSizeConstraint = shutterButtonOuterCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize)
|
|
||||||
shutterButtonOuterCircle.autoPin(toAspectRatio: 1)
|
shutterButtonOuterCircle.autoPin(toAspectRatio: 1)
|
||||||
|
|
||||||
addSubview(shutterButtonInnerCircle)
|
addSubview(shutterButtonInnerCircle)
|
||||||
innerCircleSizeConstraint = shutterButtonInnerCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize)
|
|
||||||
shutterButtonInnerCircle.autoPin(toAspectRatio: 1)
|
shutterButtonInnerCircle.autoPin(toAspectRatio: 1)
|
||||||
shutterButtonInnerCircle.isUserInteractionEnabled = false
|
shutterButtonInnerCircle.isUserInteractionEnabled = false
|
||||||
shutterButtonInnerCircle.backgroundColor = .clear
|
shutterButtonInnerCircle.backgroundColor = .clear
|
||||||
@ -119,13 +107,18 @@ class CameraCaptureControl: UIView {
|
|||||||
|
|
||||||
// The long press handles both the tap and the hold interaction, as well as the animation
|
// The long press handles both the tap and the hold interaction, as well as the animation
|
||||||
// the presents as the user begins to hold (and the button begins to grow prior to recording)
|
// the presents as the user begins to hold (and the button begins to grow prior to recording)
|
||||||
longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
|
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
|
||||||
longPressGesture.minimumPressDuration = 0
|
longPressGesture.minimumPressDuration = 0
|
||||||
shutterButtonOuterCircle.addGestureRecognizer(longPressGesture)
|
shutterButtonOuterCircle.addGestureRecognizer(longPressGesture)
|
||||||
|
|
||||||
reactivateConstraintsForCurrentAxis()
|
reactivateConstraintsForCurrentAxis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(axis:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - UI State
|
// MARK: - UI State
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@ -154,12 +147,13 @@ class CameraCaptureControl: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setState(_ state: State, animationDuration: TimeInterval = 0) {
|
func setState(_ state: State, isRecordingWithLongPress: Bool = false, animationDuration: TimeInterval = 0) {
|
||||||
guard _internalState != state else { return }
|
guard _internalState != state else { return }
|
||||||
|
|
||||||
Logger.debug("New state: \(_internalState) -> \(state)")
|
Logger.debug("New state: \(_internalState) -> \(state)")
|
||||||
|
|
||||||
_internalState = state
|
_internalState = state
|
||||||
|
self.isRecordingWithLongPress = isRecordingWithLongPress
|
||||||
if animationDuration > 0 {
|
if animationDuration > 0 {
|
||||||
UIView.animate(withDuration: animationDuration,
|
UIView.animate(withDuration: animationDuration,
|
||||||
delay: 0,
|
delay: 0,
|
||||||
@ -190,12 +184,11 @@ class CameraCaptureControl: UIView {
|
|||||||
|
|
||||||
case .recording:
|
case .recording:
|
||||||
prepareRecordingControlsIfNecessary()
|
prepareRecordingControlsIfNecessary()
|
||||||
let recordingWithLongPress = longPressGesture.state != .possible
|
let sliderProgress = isRecordingWithLongPress ? sliderTrackingProgress : 0
|
||||||
let sliderProgress = recordingWithLongPress ? sliderTrackingProgress : 0
|
|
||||||
// element visibility
|
// element visibility
|
||||||
stopButton.isHidden = sliderProgress == 0
|
stopButton.isHidden = sliderProgress == 0
|
||||||
slidingCircleView.isHidden = sliderProgress == 0
|
slidingCircleView.isHidden = sliderProgress == 0
|
||||||
lockIconView.isHidden = !recordingWithLongPress
|
lockIconView.isHidden = !isRecordingWithLongPress
|
||||||
lockIconView.setState(sliderProgress > 0.5 ? .locking : .unlocked, animated: true)
|
lockIconView.setState(sliderProgress > 0.5 ? .locking : .unlocked, animated: true)
|
||||||
shutterButtonInnerCircle.backgroundColor = .ows_white
|
shutterButtonInnerCircle.backgroundColor = .ows_white
|
||||||
// element sizes
|
// element sizes
|
||||||
@ -307,7 +300,7 @@ class CameraCaptureControl: UIView {
|
|||||||
|
|
||||||
// MARK: - Gestures
|
// MARK: - Gestures
|
||||||
|
|
||||||
private var longPressGesture: UILongPressGestureRecognizer!
|
private var isRecordingWithLongPress = false
|
||||||
private static let longPressDurationThreshold = 0.5
|
private static let longPressDurationThreshold = 0.5
|
||||||
private static let minDistanceBeforeActivatingLockSlider: CGFloat = 30
|
private static let minDistanceBeforeActivatingLockSlider: CGFloat = 30
|
||||||
private var initialTouchLocation: CGPoint?
|
private var initialTouchLocation: CGPoint?
|
||||||
@ -340,7 +333,7 @@ class CameraCaptureControl: UIView {
|
|||||||
) { [weak self] _ in
|
) { [weak self] _ in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
|
||||||
self.setState(.recording, animationDuration: 0.4)
|
self.setState(.recording, isRecordingWithLongPress: true, animationDuration: 0.4)
|
||||||
|
|
||||||
self.delegate?.cameraCaptureControlDidRequestStartVideoRecording(self)
|
self.delegate?.cameraCaptureControlDidRequestStartVideoRecording(self)
|
||||||
}
|
}
|
||||||
@ -471,10 +464,10 @@ class CameraCaptureControl: UIView {
|
|||||||
|
|
||||||
private class LockView: UIView {
|
private class LockView: UIView {
|
||||||
|
|
||||||
private var imageViewLock = UIImageView(image: UIImage(named: "media-composer-lock-outline-24"))
|
private let imageViewLock = UIImageView(image: UIImage(named: "media-composer-lock-outline-24"))
|
||||||
private var blurBackgroundView = CircleBlurView(effect: UIBlurEffect(style: .dark))
|
private let blurBackgroundView = CircleBlurView(effect: UIBlurEffect(style: .dark))
|
||||||
private var whiteBackgroundView = CircleView()
|
private let whiteBackgroundView = CircleView()
|
||||||
private var whiteCircleView = CircleView()
|
private let whiteCircleView = CircleView()
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
case unlocked
|
case unlocked
|
||||||
@ -531,15 +524,7 @@ private class LockView: UIView {
|
|||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
isUserInteractionEnabled = false
|
isUserInteractionEnabled = false
|
||||||
|
|
||||||
addSubview(blurBackgroundView)
|
addSubview(blurBackgroundView)
|
||||||
@ -562,6 +547,11 @@ private class LockView: UIView {
|
|||||||
updateAppearance()
|
updateAppearance()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
override var intrinsicContentSize: CGSize {
|
override var intrinsicContentSize: CGSize {
|
||||||
CGSize(width: CameraCaptureControl.recordingLockControlSize, height: CameraCaptureControl.recordingLockControlSize)
|
CGSize(width: CameraCaptureControl.recordingLockControlSize, height: CameraCaptureControl.recordingLockControlSize)
|
||||||
}
|
}
|
||||||
@ -621,7 +611,11 @@ class CameraOverlayButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var backgroundView: UIVisualEffectView!
|
private let backgroundView: CircleBlurView = {
|
||||||
|
let view = CircleBlurView(effect: UIBlurEffect(style: .regular))
|
||||||
|
view.isUserInteractionEnabled = false
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
private static let visibleButtonSize: CGFloat = 36 // both height and width
|
private static let visibleButtonSize: CGFloat = 36 // both height and width
|
||||||
private static let defaultInset: CGFloat = 4
|
private static let defaultInset: CGFloat = 4
|
||||||
@ -632,32 +626,28 @@ class CameraOverlayButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(image: UIImage?, userInterfaceStyleOverride: UIUserInterfaceStyle = .unspecified) {
|
required init(image: UIImage?, userInterfaceStyleOverride: UIUserInterfaceStyle = .unspecified) {
|
||||||
self.init(frame: CGRect(origin: .zero, size: .square(Self.visibleButtonSize + 2*Self.defaultInset)))
|
super.init(frame: CGRect(origin: .zero, size: .square(Self.visibleButtonSize + 2*Self.defaultInset)))
|
||||||
|
|
||||||
self.userInterfaceStyleOverride = userInterfaceStyleOverride
|
self.userInterfaceStyleOverride = userInterfaceStyleOverride
|
||||||
|
|
||||||
|
layoutMargins = contentInsets
|
||||||
|
|
||||||
|
addSubview(backgroundView)
|
||||||
|
backgroundView.autoPinEdgesToSuperviewMargins()
|
||||||
|
|
||||||
setImage(image, for: .normal)
|
setImage(image, for: .normal)
|
||||||
updateStyle()
|
updateStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private override init(frame: CGRect) {
|
@available(*, unavailable, message: "Use init(image:userInterfaceStyleOverride:) instead")
|
||||||
super.init(frame: frame)
|
override init(frame: CGRect) {
|
||||||
commonInit()
|
notImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(image:userInterfaceStyleOverride:) instead")
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
notImplemented()
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
layoutMargins = contentInsets
|
|
||||||
|
|
||||||
backgroundView = CircleBlurView(effect: UIBlurEffect(style: CameraOverlayButton.blurEffectStyle(for: effectiveUserInterfaceStyle)))
|
|
||||||
backgroundView.isUserInteractionEnabled = false
|
|
||||||
addSubview(backgroundView)
|
|
||||||
backgroundView.autoPinEdgesToSuperviewMargins()
|
|
||||||
|
|
||||||
updateStyle()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
@ -700,14 +690,8 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
private static var font: UIFont {
|
||||||
super.init(frame: frame)
|
return UIFont.ows_dynamicTypeSubheadline.ows_monospaced
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private let numberFormatter: NumberFormatter = {
|
private let numberFormatter: NumberFormatter = {
|
||||||
@ -720,22 +704,38 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.textColor = .ows_white
|
label.textColor = .ows_white
|
||||||
label.textAlignment = .center
|
label.textAlignment = .center
|
||||||
label.font = .ows_dynamicTypeSubheadline.ows_monospaced
|
label.font = MediaDoneButton.font
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
private var pillView: PillView!
|
private let pillView: PillView = {
|
||||||
private var blurBackgroundView: UIVisualEffectView!
|
let pillView = PillView(frame: .zero)
|
||||||
private var chevronImageView: UIImageView!
|
|
||||||
private var dimmerView: UIView!
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
pillView = PillView(frame: bounds)
|
|
||||||
pillView.isUserInteractionEnabled = false
|
pillView.isUserInteractionEnabled = false
|
||||||
pillView.layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 7)
|
pillView.layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 7)
|
||||||
|
return pillView
|
||||||
|
}()
|
||||||
|
private let blurBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
|
||||||
|
private let chevronImageView: UIImageView = {
|
||||||
|
let image: UIImage?
|
||||||
|
if #available(iOS 13, *) {
|
||||||
|
image = CurrentAppContext().isRTL ? UIImage(systemName: "chevron.backward") : UIImage(systemName: "chevron.right")
|
||||||
|
} else {
|
||||||
|
image = CurrentAppContext().isRTL ? UIImage(named: "chevron-left-20") : UIImage(named: "chevron-right-20")
|
||||||
|
}
|
||||||
|
let chevronImageView = UIImageView(image: image!.withRenderingMode(.alwaysTemplate))
|
||||||
|
chevronImageView.contentMode = .center
|
||||||
|
if #available(iOS 13, *) {
|
||||||
|
chevronImageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(pointSize: MediaDoneButton.font.pointSize)
|
||||||
|
}
|
||||||
|
return chevronImageView
|
||||||
|
}()
|
||||||
|
private var dimmerView: UIView?
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
addSubview(pillView)
|
addSubview(pillView)
|
||||||
pillView.autoPinEdgesToSuperviewEdges()
|
pillView.autoPinEdgesToSuperviewEdges()
|
||||||
|
|
||||||
blurBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: MediaDoneButton.blurEffectStyle(for: effectiveUserInterfaceStyle)))
|
|
||||||
pillView.addSubview(blurBackgroundView)
|
pillView.addSubview(blurBackgroundView)
|
||||||
blurBackgroundView.autoPinEdgesToSuperviewEdges()
|
blurBackgroundView.autoPinEdgesToSuperviewEdges()
|
||||||
|
|
||||||
@ -745,18 +745,6 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
blueBadgeView.addSubview(textLabel)
|
blueBadgeView.addSubview(textLabel)
|
||||||
textLabel.autoPinEdgesToSuperviewMargins()
|
textLabel.autoPinEdgesToSuperviewMargins()
|
||||||
|
|
||||||
let image: UIImage?
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
image = CurrentAppContext().isRTL ? UIImage(systemName: "chevron.backward") : UIImage(systemName: "chevron.right")
|
|
||||||
} else {
|
|
||||||
image = CurrentAppContext().isRTL ? UIImage(named: "chevron-left-20") : UIImage(named: "chevron-right-20")
|
|
||||||
}
|
|
||||||
chevronImageView = UIImageView(image: image!.withRenderingMode(.alwaysTemplate))
|
|
||||||
chevronImageView.contentMode = .center
|
|
||||||
if #available(iOS 13, *) {
|
|
||||||
chevronImageView.preferredSymbolConfiguration = UIImage.SymbolConfiguration(pointSize: textLabel.font.pointSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
let hStack = UIStackView(arrangedSubviews: [blueBadgeView, chevronImageView])
|
let hStack = UIStackView(arrangedSubviews: [blueBadgeView, chevronImageView])
|
||||||
hStack.spacing = 6
|
hStack.spacing = 6
|
||||||
pillView.addSubview(hStack)
|
pillView.addSubview(hStack)
|
||||||
@ -765,6 +753,11 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
updateStyle()
|
updateStyle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
if traitCollection.preferredContentSizeCategory != previousTraitCollection?.preferredContentSizeCategory {
|
if traitCollection.preferredContentSizeCategory != previousTraitCollection?.preferredContentSizeCategory {
|
||||||
textLabel.font = .ows_dynamicTypeSubheadline.ows_monospaced
|
textLabel.font = .ows_dynamicTypeSubheadline.ows_monospaced
|
||||||
@ -781,13 +774,14 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride {
|
|||||||
didSet {
|
didSet {
|
||||||
if isHighlighted {
|
if isHighlighted {
|
||||||
if dimmerView == nil {
|
if dimmerView == nil {
|
||||||
dimmerView = UIView(frame: bounds)
|
let dimmerView = UIView(frame: bounds)
|
||||||
dimmerView.isUserInteractionEnabled = false
|
dimmerView.isUserInteractionEnabled = false
|
||||||
dimmerView.backgroundColor = .ows_black
|
dimmerView.backgroundColor = .ows_black
|
||||||
pillView.addSubview(dimmerView)
|
pillView.addSubview(dimmerView)
|
||||||
dimmerView.autoPinEdgesToSuperviewEdges()
|
dimmerView.autoPinEdgesToSuperviewEdges()
|
||||||
|
self.dimmerView = dimmerView
|
||||||
}
|
}
|
||||||
dimmerView.alpha = 0.5
|
dimmerView?.alpha = 0.5
|
||||||
} else if let dimmerView = dimmerView {
|
} else if let dimmerView = dimmerView {
|
||||||
dimmerView.alpha = 0
|
dimmerView.alpha = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -707,45 +707,38 @@ private struct ButtonImages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class TopBar: UIView {
|
private class TopBar: UIView {
|
||||||
private(set) var closeButton: CameraOverlayButton!
|
let closeButton = CameraOverlayButton(image: ButtonImages.close, userInterfaceStyleOverride: .dark)
|
||||||
|
|
||||||
private var cameraControlsContainerView: UIView!
|
private let cameraControlsContainerView: UIStackView
|
||||||
private(set) var flashModeButton: CameraOverlayButton!
|
let flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark)
|
||||||
private(set) var batchModeButton: CameraOverlayButton!
|
let batchModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark)
|
||||||
|
|
||||||
private(set) var recordingTimerView: RecordingTimerView!
|
let recordingTimerView = RecordingTimerView(frame: .zero)
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
|
cameraControlsContainerView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton ])
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 4)
|
layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 4)
|
||||||
|
|
||||||
closeButton = CameraOverlayButton(image: ButtonImages.close, userInterfaceStyleOverride: .dark)
|
|
||||||
addSubview(closeButton)
|
addSubview(closeButton)
|
||||||
closeButton.autoPinHeightToSuperviewMargins()
|
closeButton.autoPinHeightToSuperviewMargins()
|
||||||
closeButton.autoPinLeadingToSuperviewMargin()
|
closeButton.autoPinLeadingToSuperviewMargin()
|
||||||
|
|
||||||
recordingTimerView = RecordingTimerView(frame: .zero)
|
|
||||||
addSubview(recordingTimerView)
|
addSubview(recordingTimerView)
|
||||||
recordingTimerView.autoPinHeightToSuperview(withMargin: 8)
|
recordingTimerView.autoPinHeightToSuperview(withMargin: 8)
|
||||||
recordingTimerView.autoHCenterInSuperview()
|
recordingTimerView.autoHCenterInSuperview()
|
||||||
|
|
||||||
flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark)
|
cameraControlsContainerView.spacing = 16
|
||||||
batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark)
|
addSubview(cameraControlsContainerView)
|
||||||
let stackView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton ])
|
cameraControlsContainerView.autoPinHeightToSuperviewMargins()
|
||||||
stackView.spacing = 16
|
cameraControlsContainerView.autoPinTrailingToSuperviewMargin()
|
||||||
addSubview(stackView)
|
}
|
||||||
stackView.autoPinHeightToSuperviewMargins()
|
|
||||||
stackView.autoPinTrailingToSuperviewMargin()
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
cameraControlsContainerView = stackView
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Mode
|
// MARK: - Mode
|
||||||
@ -760,12 +753,12 @@ private class TopBar: UIView {
|
|||||||
case .cameraControls:
|
case .cameraControls:
|
||||||
closeButton.isHidden = false
|
closeButton.isHidden = false
|
||||||
cameraControlsContainerView.isHidden = false
|
cameraControlsContainerView.isHidden = false
|
||||||
recordingTimerView?.isHidden = true
|
recordingTimerView.isHidden = true
|
||||||
|
|
||||||
case .closeButton:
|
case .closeButton:
|
||||||
closeButton.isHidden = false
|
closeButton.isHidden = false
|
||||||
cameraControlsContainerView.isHidden = true
|
cameraControlsContainerView.isHidden = true
|
||||||
recordingTimerView?.isHidden = true
|
recordingTimerView.isHidden = true
|
||||||
|
|
||||||
case .videoRecording:
|
case .videoRecording:
|
||||||
closeButton.isHidden = true
|
closeButton.isHidden = true
|
||||||
@ -793,47 +786,36 @@ private class BottomBar: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private(set) var photoLibraryButton: MediaPickerThumbnailButton!
|
let photoLibraryButton = MediaPickerThumbnailButton(frame: .zero)
|
||||||
private(set) var switchCameraButton: CameraOverlayButton!
|
let switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark)
|
||||||
let controlButtonsLayoutGuide = UILayoutGuide() // area encompassing Photo Library and Switch Camera buttons.
|
let controlButtonsLayoutGuide = UILayoutGuide() // area encompassing Photo Library and Switch Camera buttons.
|
||||||
|
|
||||||
private(set) var captureControl: CameraCaptureControl!
|
let captureControl = CameraCaptureControl(axis: .horizontal)
|
||||||
var shutterButtonLayoutGuide: UILayoutGuide {
|
var shutterButtonLayoutGuide: UILayoutGuide {
|
||||||
captureControl.shutterButtonLayoutGuide
|
captureControl.shutterButtonLayoutGuide
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
layoutMargins = UIEdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 14)
|
layoutMargins = UIEdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 14)
|
||||||
|
|
||||||
addLayoutGuide(controlButtonsLayoutGuide)
|
addLayoutGuide(controlButtonsLayoutGuide)
|
||||||
addConstraints([ controlButtonsLayoutGuide.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
addConstraints([ controlButtonsLayoutGuide.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||||
controlButtonsLayoutGuide.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor) ])
|
controlButtonsLayoutGuide.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor) ])
|
||||||
|
|
||||||
photoLibraryButton = MediaPickerThumbnailButton(frame: CGRect(origin: .zero, size: .square(bounds.height)))
|
|
||||||
photoLibraryButton.translatesAutoresizingMaskIntoConstraints = false
|
photoLibraryButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(photoLibraryButton)
|
addSubview(photoLibraryButton)
|
||||||
addConstraints([ photoLibraryButton.leadingAnchor.constraint(equalTo: controlButtonsLayoutGuide.leadingAnchor),
|
addConstraints([ photoLibraryButton.leadingAnchor.constraint(equalTo: controlButtonsLayoutGuide.leadingAnchor),
|
||||||
photoLibraryButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor),
|
photoLibraryButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor),
|
||||||
photoLibraryButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor) ])
|
photoLibraryButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor) ])
|
||||||
|
|
||||||
switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark)
|
|
||||||
switchCameraButton.translatesAutoresizingMaskIntoConstraints = false
|
switchCameraButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(switchCameraButton)
|
addSubview(switchCameraButton)
|
||||||
addConstraints([ switchCameraButton.trailingAnchor.constraint(equalTo: controlButtonsLayoutGuide.trailingAnchor),
|
addConstraints([ switchCameraButton.trailingAnchor.constraint(equalTo: controlButtonsLayoutGuide.trailingAnchor),
|
||||||
switchCameraButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor),
|
switchCameraButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor),
|
||||||
switchCameraButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor) ])
|
switchCameraButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor) ])
|
||||||
|
|
||||||
captureControl = CameraCaptureControl(axis: .horizontal)
|
|
||||||
captureControl.translatesAutoresizingMaskIntoConstraints = false
|
captureControl.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(captureControl)
|
addSubview(captureControl)
|
||||||
captureControl.autoPinTopToSuperviewMargin()
|
captureControl.autoPinTopToSuperviewMargin()
|
||||||
@ -849,6 +831,11 @@ private class BottomBar: UIView {
|
|||||||
updateCompactHeightLayoutConstraints()
|
updateCompactHeightLayoutConstraints()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
private func updateCompactHeightLayoutConstraints() {
|
private func updateCompactHeightLayoutConstraints() {
|
||||||
if isCompactHeightLayout {
|
if isCompactHeightLayout {
|
||||||
removeConstraints(regularHeightLayoutConstraints)
|
removeConstraints(regularHeightLayoutConstraints)
|
||||||
@ -869,49 +856,41 @@ private class SideBar: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cameraControlsContainerView: UIView!
|
private let cameraControlsContainerView: UIStackView
|
||||||
private(set) var flashModeButton: CameraOverlayButton!
|
let flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark)
|
||||||
private(set) var batchModeButton: CameraOverlayButton!
|
let batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark)
|
||||||
private(set) var switchCameraButton: CameraOverlayButton!
|
let switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark)
|
||||||
|
|
||||||
private(set) var photoLibraryButton: MediaPickerThumbnailButton!
|
let photoLibraryButton = MediaPickerThumbnailButton(frame: .zero)
|
||||||
|
|
||||||
private(set) var cameraCaptureControl = CameraCaptureControl(axis: .vertical)
|
private(set) var cameraCaptureControl = CameraCaptureControl(axis: .vertical)
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
|
cameraControlsContainerView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton, switchCameraButton ])
|
||||||
|
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
layoutMargins = UIEdgeInsets(margin: 8)
|
layoutMargins = UIEdgeInsets(margin: 8)
|
||||||
|
|
||||||
flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark)
|
cameraControlsContainerView.spacing = 16
|
||||||
switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark)
|
cameraControlsContainerView.axis = .vertical
|
||||||
batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark)
|
addSubview(cameraControlsContainerView)
|
||||||
let stackView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton, switchCameraButton ])
|
cameraControlsContainerView.autoPinWidthToSuperviewMargins()
|
||||||
stackView.spacing = 16
|
cameraControlsContainerView.autoPinTopToSuperviewMargin()
|
||||||
stackView.axis = .vertical
|
|
||||||
addSubview(stackView)
|
|
||||||
stackView.autoPinWidthToSuperviewMargins()
|
|
||||||
stackView.autoPinTopToSuperviewMargin()
|
|
||||||
cameraControlsContainerView = stackView
|
|
||||||
|
|
||||||
addSubview(cameraCaptureControl)
|
addSubview(cameraCaptureControl)
|
||||||
cameraCaptureControl.autoHCenterInSuperview()
|
cameraCaptureControl.autoHCenterInSuperview()
|
||||||
cameraCaptureControl.shutterButtonLayoutGuide.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 36).isActive = true
|
cameraCaptureControl.shutterButtonLayoutGuide.topAnchor.constraint(equalTo: cameraControlsContainerView.bottomAnchor, constant: 36).isActive = true
|
||||||
|
|
||||||
photoLibraryButton = MediaPickerThumbnailButton(frame: CGRect(origin: .zero, size: .square(bounds.height)))
|
|
||||||
addSubview(photoLibraryButton)
|
addSubview(photoLibraryButton)
|
||||||
photoLibraryButton.autoHCenterInSuperview()
|
photoLibraryButton.autoHCenterInSuperview()
|
||||||
photoLibraryButton.topAnchor.constraint(equalTo: cameraCaptureControl.shutterButtonLayoutGuide.bottomAnchor, constant: 36).isActive = true
|
photoLibraryButton.topAnchor.constraint(equalTo: cameraCaptureControl.shutterButtonLayoutGuide.bottomAnchor, constant: 36).isActive = true
|
||||||
photoLibraryButton.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor).isActive = true
|
photoLibraryButton.bottomAnchor.constraint(lessThanOrEqualTo: layoutMarginsGuide.bottomAnchor).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,8 +1093,9 @@ class CapturePreviewView: UIView {
|
|||||||
layer.addSublayer(previewLayer)
|
layer.addSublayer(previewLayer)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
@available(*, unavailable, message: "Use init(session:) instead")
|
||||||
fatalError("init(coder:) has not been implemented")
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1123,15 +1103,7 @@ private class RecordingTimerView: PillView {
|
|||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
commonInit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private func commonInit() {
|
|
||||||
layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 0)
|
layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 0)
|
||||||
|
|
||||||
let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
|
||||||
@ -1148,9 +1120,14 @@ private class RecordingTimerView: PillView {
|
|||||||
updateView()
|
updateView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable, message: "Use init(frame:) instead")
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
notImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Subviews
|
// MARK: - Subviews
|
||||||
|
|
||||||
private lazy var label: UILabel = {
|
private let label: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = UIFont.ows_monospacedDigitFont(withSize: 20)
|
label.font = UIFont.ows_monospacedDigitFont(withSize: 20)
|
||||||
label.textAlignment = .center
|
label.textAlignment = .center
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user