From 45db3a963eab405526745bb9ed6dfe26d7cd63ef Mon Sep 17 00:00:00 2001 From: Igor Solomennikov Date: Wed, 2 Mar 2022 13:31:10 -0800 Subject: [PATCH] Minimize use of implicitly unwrapped optionals in code. And mark `init(coder:)` as unavailable. --- .../Photos/ImagePickerController.swift | 21 +-- .../Photos/MediaControls.swift | 172 +++++++++--------- .../Photos/PhotoCaptureViewController.swift | 127 ++++++------- 3 files changed, 144 insertions(+), 176 deletions(-) diff --git a/Signal/src/ViewControllers/Photos/ImagePickerController.swift b/Signal/src/ViewControllers/Photos/ImagePickerController.swift index e851856b48..1b5a201af1 100644 --- a/Signal/src/ViewControllers/Photos/ImagePickerController.swift +++ b/Signal/src/ViewControllers/Photos/ImagePickerController.swift @@ -562,7 +562,7 @@ private class TitleView: UIView { private let label = UILabel() private let iconView = UIImageView() - private var stackView: UIStackView! + private let stackView: UIStackView // Returns same font as UIBarButtonItem uses. private func titleLabelFont() -> UIFont { @@ -573,18 +573,10 @@ private class TitleView: UIView { // MARK: - Initializers 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]) + + super.init(frame: frame) + stackView.axis = .horizontal stackView.alignment = .center stackView.spacing = 5 @@ -605,6 +597,11 @@ private class TitleView: UIView { addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped))) } + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + override func tintColorDidChange() { super.tintColorDidChange() label.textColor = tintColor diff --git a/Signal/src/ViewControllers/Photos/MediaControls.swift b/Signal/src/ViewControllers/Photos/MediaControls.swift index e63197255e..f53a633b11 100644 --- a/Signal/src/ViewControllers/Photos/MediaControls.swift +++ b/Signal/src/ViewControllers/Photos/MediaControls.swift @@ -40,8 +40,8 @@ class CameraCaptureControl: UIView { private static let shutterButtonDefaultSize: CGFloat = 72 private static let shutterButtonRecordingSize: CGFloat = 122 - private var outerCircleSizeConstraint: NSLayoutConstraint! - private var innerCircleSizeConstraint: NSLayoutConstraint! + private let outerCircleSizeConstraint: NSLayoutConstraint + private let innerCircleSizeConstraint: NSLayoutConstraint private var slidingCircleHPositionConstraint: NSLayoutConstraint! private var slidingCircleVPositionConstraint: NSLayoutConstraint! @@ -67,23 +67,13 @@ class CameraCaptureControl: UIView { weak var delegate: CameraCaptureControlDelegate? - convenience init(axis: NSLayoutConstraint.Axis) { - self.init(frame: CGRect(origin: .zero, size: CameraCaptureControl.intrinsicContentSize(forAxis: axis))) + required init(axis: NSLayoutConstraint.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 - 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 addLayoutGuide(shutterButtonLayoutGuide) @@ -104,11 +94,9 @@ class CameraCaptureControl: UIView { addSubview(shutterButtonOuterCircle) shutterButtonOuterCircle.centerXAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerXAnchor).isActive = true shutterButtonOuterCircle.centerYAnchor.constraint(equalTo: shutterButtonLayoutGuide.centerYAnchor).isActive = true - outerCircleSizeConstraint = shutterButtonOuterCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize) shutterButtonOuterCircle.autoPin(toAspectRatio: 1) addSubview(shutterButtonInnerCircle) - innerCircleSizeConstraint = shutterButtonInnerCircle.autoSetDimension(.width, toSize: CameraCaptureControl.shutterButtonDefaultSize) shutterButtonInnerCircle.autoPin(toAspectRatio: 1) shutterButtonInnerCircle.isUserInteractionEnabled = false 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 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 shutterButtonOuterCircle.addGestureRecognizer(longPressGesture) reactivateConstraintsForCurrentAxis() } + @available(*, unavailable, message: "Use init(axis:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + // MARK: - UI 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 } Logger.debug("New state: \(_internalState) -> \(state)") _internalState = state + self.isRecordingWithLongPress = isRecordingWithLongPress if animationDuration > 0 { UIView.animate(withDuration: animationDuration, delay: 0, @@ -190,12 +184,11 @@ class CameraCaptureControl: UIView { case .recording: prepareRecordingControlsIfNecessary() - let recordingWithLongPress = longPressGesture.state != .possible - let sliderProgress = recordingWithLongPress ? sliderTrackingProgress : 0 + let sliderProgress = isRecordingWithLongPress ? sliderTrackingProgress : 0 // element visibility stopButton.isHidden = sliderProgress == 0 slidingCircleView.isHidden = sliderProgress == 0 - lockIconView.isHidden = !recordingWithLongPress + lockIconView.isHidden = !isRecordingWithLongPress lockIconView.setState(sliderProgress > 0.5 ? .locking : .unlocked, animated: true) shutterButtonInnerCircle.backgroundColor = .ows_white // element sizes @@ -307,7 +300,7 @@ class CameraCaptureControl: UIView { // MARK: - Gestures - private var longPressGesture: UILongPressGestureRecognizer! + private var isRecordingWithLongPress = false private static let longPressDurationThreshold = 0.5 private static let minDistanceBeforeActivatingLockSlider: CGFloat = 30 private var initialTouchLocation: CGPoint? @@ -340,7 +333,7 @@ class CameraCaptureControl: UIView { ) { [weak self] _ in guard let self = self else { return } - self.setState(.recording, animationDuration: 0.4) + self.setState(.recording, isRecordingWithLongPress: true, animationDuration: 0.4) self.delegate?.cameraCaptureControlDidRequestStartVideoRecording(self) } @@ -471,10 +464,10 @@ class CameraCaptureControl: UIView { private class LockView: UIView { - private var imageViewLock = UIImageView(image: UIImage(named: "media-composer-lock-outline-24")) - private var blurBackgroundView = CircleBlurView(effect: UIBlurEffect(style: .dark)) - private var whiteBackgroundView = CircleView() - private var whiteCircleView = CircleView() + private let imageViewLock = UIImageView(image: UIImage(named: "media-composer-lock-outline-24")) + private let blurBackgroundView = CircleBlurView(effect: UIBlurEffect(style: .dark)) + private let whiteBackgroundView = CircleView() + private let whiteCircleView = CircleView() enum State { case unlocked @@ -531,15 +524,7 @@ private class LockView: UIView { override init(frame: CGRect) { super.init(frame: frame) - commonInit() - } - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - private func commonInit() { isUserInteractionEnabled = false addSubview(blurBackgroundView) @@ -562,6 +547,11 @@ private class LockView: UIView { updateAppearance() } + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + override var intrinsicContentSize: CGSize { 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 defaultInset: CGFloat = 4 @@ -632,32 +626,28 @@ class CameraOverlayButton: UIButton, UserInterfaceStyleOverride { } } - convenience init(image: UIImage?, userInterfaceStyleOverride: UIUserInterfaceStyle = .unspecified) { - self.init(frame: CGRect(origin: .zero, size: .square(Self.visibleButtonSize + 2*Self.defaultInset))) + required init(image: UIImage?, userInterfaceStyleOverride: UIUserInterfaceStyle = .unspecified) { + super.init(frame: CGRect(origin: .zero, size: .square(Self.visibleButtonSize + 2*Self.defaultInset))) + self.userInterfaceStyleOverride = userInterfaceStyleOverride + + layoutMargins = contentInsets + + addSubview(backgroundView) + backgroundView.autoPinEdgesToSuperviewMargins() + setImage(image, for: .normal) updateStyle() } - private override init(frame: CGRect) { - super.init(frame: frame) - commonInit() + @available(*, unavailable, message: "Use init(image:userInterfaceStyleOverride:) instead") + override init(frame: CGRect) { + notImplemented() } + @available(*, unavailable, message: "Use init(image:userInterfaceStyleOverride:) instead") required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - private func commonInit() { - layoutMargins = contentInsets - - backgroundView = CircleBlurView(effect: UIBlurEffect(style: CameraOverlayButton.blurEffectStyle(for: effectiveUserInterfaceStyle))) - backgroundView.isUserInteractionEnabled = false - addSubview(backgroundView) - backgroundView.autoPinEdgesToSuperviewMargins() - - updateStyle() + notImplemented() } override func layoutSubviews() { @@ -700,14 +690,8 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride { } } - override init(frame: CGRect) { - super.init(frame: frame) - commonInit() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() + private static var font: UIFont { + return UIFont.ows_dynamicTypeSubheadline.ows_monospaced } private let numberFormatter: NumberFormatter = { @@ -720,22 +704,38 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride { let label = UILabel() label.textColor = .ows_white label.textAlignment = .center - label.font = .ows_dynamicTypeSubheadline.ows_monospaced + label.font = MediaDoneButton.font return label }() - private var pillView: PillView! - private var blurBackgroundView: UIVisualEffectView! - private var chevronImageView: UIImageView! - private var dimmerView: UIView! - - private func commonInit() { - pillView = PillView(frame: bounds) + private let pillView: PillView = { + let pillView = PillView(frame: .zero) pillView.isUserInteractionEnabled = false 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) pillView.autoPinEdgesToSuperviewEdges() - blurBackgroundView = UIVisualEffectView(effect: UIBlurEffect(style: MediaDoneButton.blurEffectStyle(for: effectiveUserInterfaceStyle))) pillView.addSubview(blurBackgroundView) blurBackgroundView.autoPinEdgesToSuperviewEdges() @@ -745,18 +745,6 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride { blueBadgeView.addSubview(textLabel) 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]) hStack.spacing = 6 pillView.addSubview(hStack) @@ -765,6 +753,11 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride { updateStyle() } + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { if traitCollection.preferredContentSizeCategory != previousTraitCollection?.preferredContentSizeCategory { textLabel.font = .ows_dynamicTypeSubheadline.ows_monospaced @@ -781,13 +774,14 @@ class MediaDoneButton: UIButton, UserInterfaceStyleOverride { didSet { if isHighlighted { if dimmerView == nil { - dimmerView = UIView(frame: bounds) + let dimmerView = UIView(frame: bounds) dimmerView.isUserInteractionEnabled = false dimmerView.backgroundColor = .ows_black pillView.addSubview(dimmerView) dimmerView.autoPinEdgesToSuperviewEdges() + self.dimmerView = dimmerView } - dimmerView.alpha = 0.5 + dimmerView?.alpha = 0.5 } else if let dimmerView = dimmerView { dimmerView.alpha = 0 } diff --git a/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift b/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift index 3d45bb3d2e..6282ea81ae 100644 --- a/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift +++ b/Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift @@ -707,45 +707,38 @@ private struct ButtonImages { } private class TopBar: UIView { - private(set) var closeButton: CameraOverlayButton! + let closeButton = CameraOverlayButton(image: ButtonImages.close, userInterfaceStyleOverride: .dark) - private var cameraControlsContainerView: UIView! - private(set) var flashModeButton: CameraOverlayButton! - private(set) var batchModeButton: CameraOverlayButton! + private let cameraControlsContainerView: UIStackView + let flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark) + let batchModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark) - private(set) var recordingTimerView: RecordingTimerView! + let recordingTimerView = RecordingTimerView(frame: .zero) override init(frame: CGRect) { + cameraControlsContainerView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton ]) + super.init(frame: frame) - commonInit() - } - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - private func commonInit() { layoutMargins = UIEdgeInsets(hMargin: 8, vMargin: 4) - closeButton = CameraOverlayButton(image: ButtonImages.close, userInterfaceStyleOverride: .dark) addSubview(closeButton) closeButton.autoPinHeightToSuperviewMargins() closeButton.autoPinLeadingToSuperviewMargin() - recordingTimerView = RecordingTimerView(frame: .zero) addSubview(recordingTimerView) recordingTimerView.autoPinHeightToSuperview(withMargin: 8) recordingTimerView.autoHCenterInSuperview() - flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark) - batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark) - let stackView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton ]) - stackView.spacing = 16 - addSubview(stackView) - stackView.autoPinHeightToSuperviewMargins() - stackView.autoPinTrailingToSuperviewMargin() - cameraControlsContainerView = stackView + cameraControlsContainerView.spacing = 16 + addSubview(cameraControlsContainerView) + cameraControlsContainerView.autoPinHeightToSuperviewMargins() + cameraControlsContainerView.autoPinTrailingToSuperviewMargin() + } + + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() } // MARK: - Mode @@ -760,12 +753,12 @@ private class TopBar: UIView { case .cameraControls: closeButton.isHidden = false cameraControlsContainerView.isHidden = false - recordingTimerView?.isHidden = true + recordingTimerView.isHidden = true case .closeButton: closeButton.isHidden = false cameraControlsContainerView.isHidden = true - recordingTimerView?.isHidden = true + recordingTimerView.isHidden = true case .videoRecording: closeButton.isHidden = true @@ -793,47 +786,36 @@ private class BottomBar: UIView { } } - private(set) var photoLibraryButton: MediaPickerThumbnailButton! - private(set) var switchCameraButton: CameraOverlayButton! + let photoLibraryButton = MediaPickerThumbnailButton(frame: .zero) + let switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark) let controlButtonsLayoutGuide = UILayoutGuide() // area encompassing Photo Library and Switch Camera buttons. - private(set) var captureControl: CameraCaptureControl! + let captureControl = CameraCaptureControl(axis: .horizontal) var shutterButtonLayoutGuide: UILayoutGuide { captureControl.shutterButtonLayoutGuide } override init(frame: CGRect) { 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) addLayoutGuide(controlButtonsLayoutGuide) addConstraints([ controlButtonsLayoutGuide.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), controlButtonsLayoutGuide.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor) ]) - photoLibraryButton = MediaPickerThumbnailButton(frame: CGRect(origin: .zero, size: .square(bounds.height))) photoLibraryButton.translatesAutoresizingMaskIntoConstraints = false addSubview(photoLibraryButton) addConstraints([ photoLibraryButton.leadingAnchor.constraint(equalTo: controlButtonsLayoutGuide.leadingAnchor), photoLibraryButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor), photoLibraryButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor) ]) - switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark) switchCameraButton.translatesAutoresizingMaskIntoConstraints = false addSubview(switchCameraButton) addConstraints([ switchCameraButton.trailingAnchor.constraint(equalTo: controlButtonsLayoutGuide.trailingAnchor), switchCameraButton.topAnchor.constraint(greaterThanOrEqualTo: controlButtonsLayoutGuide.topAnchor), switchCameraButton.centerYAnchor.constraint(equalTo: controlButtonsLayoutGuide.centerYAnchor) ]) - captureControl = CameraCaptureControl(axis: .horizontal) captureControl.translatesAutoresizingMaskIntoConstraints = false addSubview(captureControl) captureControl.autoPinTopToSuperviewMargin() @@ -849,6 +831,11 @@ private class BottomBar: UIView { updateCompactHeightLayoutConstraints() } + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + private func updateCompactHeightLayoutConstraints() { if isCompactHeightLayout { removeConstraints(regularHeightLayoutConstraints) @@ -869,49 +856,41 @@ private class SideBar: UIView { } } - private var cameraControlsContainerView: UIView! - private(set) var flashModeButton: CameraOverlayButton! - private(set) var batchModeButton: CameraOverlayButton! - private(set) var switchCameraButton: CameraOverlayButton! + private let cameraControlsContainerView: UIStackView + let flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark) + let batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark) + 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) override init(frame: CGRect) { + cameraControlsContainerView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton, switchCameraButton ]) + super.init(frame: frame) - commonInit() - } - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - private func commonInit() { layoutMargins = UIEdgeInsets(margin: 8) - flashModeButton = CameraOverlayButton(image: ButtonImages.flashAuto, userInterfaceStyleOverride: .dark) - switchCameraButton = CameraOverlayButton(image: ButtonImages.switchCamera, userInterfaceStyleOverride: .dark) - batchModeButton = CameraOverlayButton(image: ButtonImages.batchModeOff, userInterfaceStyleOverride: .dark) - let stackView = UIStackView(arrangedSubviews: [ batchModeButton, flashModeButton, switchCameraButton ]) - stackView.spacing = 16 - stackView.axis = .vertical - addSubview(stackView) - stackView.autoPinWidthToSuperviewMargins() - stackView.autoPinTopToSuperviewMargin() - cameraControlsContainerView = stackView + cameraControlsContainerView.spacing = 16 + cameraControlsContainerView.axis = .vertical + addSubview(cameraControlsContainerView) + cameraControlsContainerView.autoPinWidthToSuperviewMargins() + cameraControlsContainerView.autoPinTopToSuperviewMargin() addSubview(cameraCaptureControl) 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) photoLibraryButton.autoHCenterInSuperview() photoLibraryButton.topAnchor.constraint(equalTo: cameraCaptureControl.shutterButtonLayoutGuide.bottomAnchor, constant: 36).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) } - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") + @available(*, unavailable, message: "Use init(session:) instead") + required init?(coder: NSCoder) { + notImplemented() } } @@ -1123,15 +1103,7 @@ private class RecordingTimerView: PillView { override init(frame: CGRect) { super.init(frame: frame) - commonInit() - } - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - private func commonInit() { layoutMargins = UIEdgeInsets(hMargin: 16, vMargin: 0) let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) @@ -1148,9 +1120,14 @@ private class RecordingTimerView: PillView { updateView() } + @available(*, unavailable, message: "Use init(frame:) instead") + required init?(coder: NSCoder) { + notImplemented() + } + // MARK: - Subviews - private lazy var label: UILabel = { + private let label: UILabel = { let label = UILabel() label.font = UIFont.ows_monospacedDigitFont(withSize: 20) label.textAlignment = .center