From 621d54db1762e9c565251b5850483ab1ba472c45 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 14:39:59 -0400 Subject: [PATCH] Revert "Remove usage of ! in call view." This reverts commit ce197b0ada5600ba4d06e011ad18cf2da3a59a7f. --- .../ViewControllers/CallViewController.swift | 257 +++++++----------- 1 file changed, 98 insertions(+), 159 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index f25187afe..106c7ecac 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -30,27 +30,27 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Views var hasConstraints = false - var blurView: UIVisualEffectView? + var blurView: UIVisualEffectView! var dateFormatter: DateFormatter? // MARK: Contact Views - let contactNameLabel = MarqueeLabel() - let contactAvatarView = AvatarImageView() - let contactAvatarContainerView = UIView.container() - let callStatusLabel = UILabel() + var contactNameLabel: MarqueeLabel! + var contactAvatarView: AvatarImageView! + var contactAvatarContainerView: UIView! + var callStatusLabel: UILabel! var callDurationTimer: Timer? // MARK: Ongoing Call Controls - var ongoingCallView: UIView? + var ongoingCallView: UIView! - var hangUpButton: UIButton? - var audioSourceButton: UIButton? - var audioModeMuteButton: UIButton? - var audioModeVideoButton: UIButton? - var videoModeMuteButton: UIButton? - var videoModeVideoButton: UIButton? + var hangUpButton: UIButton! + var audioSourceButton: UIButton! + var audioModeMuteButton: UIButton! + var audioModeVideoButton: UIButton! + var videoModeMuteButton: UIButton! + var videoModeVideoButton: UIButton! // TODO: Later, we'll re-enable the text message button // so users can send and read messages during a // call. @@ -58,15 +58,15 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Incoming Call Controls - var incomingCallView: UIView? + var incomingCallView: UIView! - var acceptIncomingButton: UIButton? - var declineIncomingButton: UIButton? + var acceptIncomingButton: UIButton! + var declineIncomingButton: UIButton! // MARK: Video Views - var remoteVideoView: RemoteVideoView? - var localVideoView: RTCCameraPreviewView? + var remoteVideoView: RemoteVideoView! + var localVideoView: RTCCameraPreviewView! weak var localVideoTrack: RTCVideoTrack? weak var remoteVideoTrack: RTCVideoTrack? var localVideoConstraints: [NSLayoutConstraint] = [] @@ -90,8 +90,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, } } } - let settingsNagView = UIView() - let settingsNagDescriptionLabel = UILabel() + var settingsNagView: UIView! + var settingsNagDescriptionLabel: UILabel! // MARK: Audio Source @@ -219,8 +219,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // Dark blurred background. let blurEffect = UIBlurEffect(style: .dark) - let blurView = UIVisualEffectView(effect: blurEffect) - self.blurView = blurView + blurView = UIVisualEffectView(effect: blurEffect) blurView.isUserInteractionEnabled = false self.view.addSubview(blurView) @@ -235,22 +234,15 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, } func didTouchRootView(sender: UIGestureRecognizer) { - guard let remoteVideoView = remoteVideoView else { - owsFail("\(TAG) missing remoteVideoView.") - return - } if !remoteVideoView.isHidden { shouldRemoteVideoControlsBeHidden = !shouldRemoteVideoControlsBeHidden } } func createVideoViews() { - let remoteVideoView = RemoteVideoView() - self.remoteVideoView = remoteVideoView + remoteVideoView = RemoteVideoView() remoteVideoView.isUserInteractionEnabled = false - - let localVideoView = RTCCameraPreviewView() - self.localVideoView = localVideoView + localVideoView = RTCCameraPreviewView() remoteVideoView.isHidden = true localVideoView.isHidden = true @@ -259,6 +251,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, } func createContactViews() { + contactNameLabel = MarqueeLabel() + // marquee config contactNameLabel.type = .continuous // This feels pretty slow when you're initially waiting for it, but when you're overlaying video calls, anything faster is distracting. @@ -278,6 +272,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, self.view.addSubview(contactNameLabel) + callStatusLabel = UILabel() callStatusLabel.font = UIFont.ows_regularFont(withSize: ScaleFromIPhone5To7Plus(19, 25)) callStatusLabel.textColor = UIColor.white callStatusLabel.layer.shadowOffset = CGSize.zero @@ -285,11 +280,14 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, callStatusLabel.layer.shadowRadius = 4 self.view.addSubview(callStatusLabel) + contactAvatarContainerView = UIView.container() self.view.addSubview(contactAvatarContainerView) + contactAvatarView = AvatarImageView() contactAvatarContainerView.addSubview(contactAvatarView) } func createSettingsNagViews() { + settingsNagView = UIView() settingsNagView.isHidden = true self.view.addSubview(settingsNagView) @@ -298,6 +296,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, viewStack.autoPinWidthToSuperview() viewStack.autoVCenterInSuperview() + settingsNagDescriptionLabel = UILabel() settingsNagDescriptionLabel.text = NSLocalizedString("CALL_VIEW_SETTINGS_NAG_DESCRIPTION_ALL", comment: "Reminder to the user of the benefits of enabling CallKit and disabling CallKit privacy.") settingsNagDescriptionLabel.font = UIFont.ows_regularFont(withSize: ScaleFromIPhone5To7Plus(16, 18)) @@ -349,38 +348,32 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // textMessageButton = createButton(imageName:"message-active-wide", // action:#selector(didPressTextMessage)) - let audioSourceButton = createButton(imageName: "audio-call-speaker-inactive", - action: #selector(didPressAudioSource), - accessibilityLabel: NSLocalizedString("CALL_VIEW_AUDIO_SOURCE_LABEL", - comment: "Accessibility label for selection the audio source")) - self.audioSourceButton = audioSourceButton - - let hangUpButton = createButton(imageName: "hangup-active-wide", - action: #selector(didPressHangup), - accessibilityLabel: NSLocalizedString("CALL_VIEW_HANGUP_LABEL", - comment: "Accessibility label for hang up call")) - self.hangUpButton = hangUpButton - - let audioModeMuteButton = createButton(imageName: "audio-call-mute-inactive", - action: #selector(didPressMute), - accessibilityLabel: NSLocalizedString("CALL_VIEW_MUTE_LABEL", - comment: "Accessibility label for muting the microphone")) - self.audioModeMuteButton = audioModeMuteButton - - let videoModeMuteButton = createButton(imageName: "video-mute-unselected", - action: #selector(didPressMute), - accessibilityLabel: NSLocalizedString("CALL_VIEW_MUTE_LABEL", comment: "Accessibility label for muting the microphone")) - self.videoModeMuteButton = videoModeMuteButton - - let audioModeVideoButton = createButton(imageName: "audio-call-video-inactive", - action: #selector(didPressVideo), - accessibilityLabel: NSLocalizedString("CALL_VIEW_SWITCH_TO_VIDEO_LABEL", comment: "Accessibility label to switch to video call")) - self.audioModeMuteButton = audioModeVideoButton - - let videoModeVideoButton = createButton(imageName: "video-video-unselected", - action: #selector(didPressVideo), - accessibilityLabel: NSLocalizedString("CALL_VIEW_SWITCH_TO_AUDIO_LABEL", comment: "Accessibility label to switch to audio only")) - self.videoModeVideoButton = videoModeVideoButton + audioSourceButton = createButton(imageName: "audio-call-speaker-inactive", + action: #selector(didPressAudioSource)) + audioSourceButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_AUDIO_SOURCE_LABEL", + comment: "Accessibility label for selection the audio source") + + hangUpButton = createButton(imageName: "hangup-active-wide", + action: #selector(didPressHangup)) + hangUpButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_HANGUP_LABEL", + comment: "Accessibility label for hang up call") + + audioModeMuteButton = createButton(imageName: "audio-call-mute-inactive", + action: #selector(didPressMute)) + audioModeMuteButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_MUTE_LABEL", + comment: "Accessibility label for muting the microphone") + + videoModeMuteButton = createButton(imageName: "video-mute-unselected", + action: #selector(didPressMute)) + videoModeMuteButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_MUTE_LABEL", comment: "Accessibility label for muting the microphone") + + audioModeVideoButton = createButton(imageName: "audio-call-video-inactive", + action: #selector(didPressVideo)) + audioModeVideoButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_SWITCH_TO_VIDEO_LABEL", comment: "Accessibility label to switch to video call") + + videoModeVideoButton = createButton(imageName: "video-video-unselected", + action: #selector(didPressVideo)) + videoModeVideoButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_SWITCH_TO_AUDIO_LABEL", comment: "Accessibility label to switch to audio only") setButtonSelectedImage(button: audioModeMuteButton, imageName: "audio-call-mute-active") setButtonSelectedImage(button: videoModeMuteButton, imageName: "video-mute-selected") @@ -432,16 +425,14 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, func createIncomingCallControls() { - let acceptIncomingButton = createButton(imageName: "call-active-wide", - action: #selector(didPressAnswerCall), - accessibilityLabel: NSLocalizedString("CALL_VIEW_ACCEPT_INCOMING_CALL_LABEL", - comment: "Accessibility label for accepting incoming calls")) - self.acceptIncomingButton = acceptIncomingButton - let declineIncomingButton = createButton(imageName: "hangup-active-wide", - action: #selector(didPressDeclineCall), -accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", - comment: "Accessibility label for declining incoming calls")) - self.declineIncomingButton = declineIncomingButton + acceptIncomingButton = createButton(imageName: "call-active-wide", + action: #selector(didPressAnswerCall)) + acceptIncomingButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_ACCEPT_INCOMING_CALL_LABEL", + comment: "Accessibility label for accepting incoming calls") + declineIncomingButton = createButton(imageName: "hangup-active-wide", + action: #selector(didPressDeclineCall)) + declineIncomingButton.accessibilityLabel = NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", + comment: "Accessibility label for declining incoming calls") incomingCallView = createContainerForCallControls(controlGroups: [ [acceptIncomingButton, declineIncomingButton ] @@ -460,19 +451,19 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", for row in rows { containerView.addSubview(row) row.autoHCenterInSuperview() - if let prevRow = prevRow { - row.autoPinEdge(.top, to: .bottom, of: prevRow, withOffset: rowspacing) + if prevRow != nil { + row.autoPinEdge(.top, to: .bottom, of: prevRow!, withOffset: rowspacing) } prevRow = row } containerView.setContentHuggingVerticalHigh() - rows.first?.autoPinEdge(toSuperviewEdge: .top) - rows.last?.autoPinEdge(toSuperviewEdge: .bottom) + rows.first!.autoPinEdge(toSuperviewEdge: .top) + rows.last!.autoPinEdge(toSuperviewEdge: .bottom) return containerView } - func createButton(imageName: String, action: Selector, accessibilityLabel: String) -> UIButton { + func createButton(imageName: String, action: Selector) -> UIButton { let image = UIImage(named: imageName) assert(image != nil) let button = UIButton() @@ -484,7 +475,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", button.addTarget(self, action: action, for: .touchUpInside) button.autoSetDimension(.width, toSize: buttonSize()) button.autoSetDimension(.height, toSize: buttonSize()) - button.accessibilityLabel = accessibilityLabel return button } @@ -503,11 +493,11 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", subview.setContentHuggingHorizontalHigh() subview.autoVCenterInSuperview() - if let lastSubview = lastSubview { + if lastSubview != nil { let spacer = UIView() spacer.isHidden = true row.addSubview(spacer) - spacer.autoPinEdge(.left, to: .right, of: lastSubview) + spacer.autoPinEdge(.left, to: .right, of: lastSubview!) spacer.autoPinEdge(.right, to: .left, of: subview) spacer.setContentHuggingHorizontalLow() spacer.autoVCenterInSuperview() @@ -522,8 +512,8 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", lastSubview = subview } - subviews.first?.autoPinEdge(toSuperviewEdge: .left) - subviews.last?.autoPinEdge(toSuperviewEdge: .right) + subviews.first!.autoPinEdge(toSuperviewEdge: .left) + subviews.last!.autoPinEdge(toSuperviewEdge: .right) } else if subviews.count == 1 { // If there's only one subview in this row, center it. let subview = subviews.first! @@ -538,27 +528,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // MARK: - Layout override func updateViewConstraints() { - guard let blurView = blurView else { - owsFail("\(TAG) missing blurView.") - return - } - guard let localVideoView = localVideoView else { - owsFail("\(TAG) missing localVideoView.") - return - } - guard let remoteVideoView = remoteVideoView else { - owsFail("\(TAG) missing remoteVideoView.") - return - } - guard let ongoingCallView = ongoingCallView else { - owsFail("\(TAG) missing ongoingCallView.") - return - } - guard let incomingCallView = incomingCallView else { - owsFail("\(TAG) missing incomingCallView.") - return - } - if !hasConstraints { // We only want to create our constraints once. // @@ -644,19 +613,11 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", } internal func updateRemoteVideoLayout() { - guard let remoteVideoView = remoteVideoView else { - owsFail("\(TAG) missing remoteVideoView.") - return - } remoteVideoView.isHidden = !self.hasRemoteVideoTrack updateCallUI(callState: call.state) } internal func updateLocalVideoLayout() { - guard let localVideoView = localVideoView else { - owsFail("\(TAG) missing localVideoView.") - return - } NSLayoutConstraint.deactivate(self.localVideoConstraints) @@ -701,10 +662,9 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", let callDuration = call.connectionDuration() let callDurationDate = Date(timeIntervalSinceReferenceDate: callDuration) if dateFormatter == nil { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "HH:mm:ss" - dateFormatter.timeZone = TimeZone(identifier: "UTC")! - self.dateFormatter = dateFormatter + dateFormatter = DateFormatter() + dateFormatter!.dateFormat = "HH:mm:ss" + dateFormatter!.timeZone = TimeZone(identifier: "UTC")! } var formattedDate = dateFormatter!.string(from: callDurationDate) if formattedDate.hasPrefix("00:") { @@ -747,39 +707,29 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", func updateCallUI(callState: CallState) { assert(Thread.isMainThread) - - guard let remoteVideoView = remoteVideoView else { - owsFail("\(TAG) missing remoteVideoView.") - return - } - guard let localVideoView = localVideoView else { - owsFail("\(TAG) missing localVideoView.") - return - } - updateCallStatusLabel(callState: callState) if isShowingSettingsNag { settingsNagView.isHidden = false contactAvatarView.isHidden = true - ongoingCallView?.isHidden = true + ongoingCallView.isHidden = true return } // Marquee scrolling is distracting during a video call, disable it. contactNameLabel.labelize = call.hasLocalVideo - audioModeMuteButton?.isSelected = call.isMuted - videoModeMuteButton?.isSelected = call.isMuted - audioModeVideoButton?.isSelected = call.hasLocalVideo - videoModeVideoButton?.isSelected = call.hasLocalVideo + audioModeMuteButton.isSelected = call.isMuted + videoModeMuteButton.isSelected = call.isMuted + audioModeVideoButton.isSelected = call.hasLocalVideo + videoModeVideoButton.isSelected = call.hasLocalVideo // Show Incoming vs. Ongoing call controls let isRinging = callState == .localRinging - incomingCallView?.isHidden = !isRinging - incomingCallView?.isUserInteractionEnabled = isRinging - ongoingCallView?.isHidden = isRinging - ongoingCallView?.isUserInteractionEnabled = !isRinging + incomingCallView.isHidden = !isRinging + incomingCallView.isUserInteractionEnabled = isRinging + ongoingCallView.isHidden = isRinging + ongoingCallView.isUserInteractionEnabled = !isRinging // Rework control state if remote video is available. let hasRemoteVideo = !remoteVideoView.isHidden @@ -799,7 +749,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", if shouldRemoteVideoControlsBeHidden && !remoteVideoView.isHidden { contactNameLabel.isHidden = true callStatusLabel.isHidden = true - ongoingCallView?.isHidden = true + ongoingCallView.isHidden = true } else { contactNameLabel.isHidden = false callStatusLabel.isHidden = false @@ -809,24 +759,24 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", if self.hasAlternateAudioSources { // With bluetooth, button does not stay selected. Pressing it pops an actionsheet // and the button should immediately "unselect". - audioSourceButton?.isSelected = false + audioSourceButton.isSelected = false if hasLocalVideo { - audioSourceButton?.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .normal) - audioSourceButton?.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .selected) + audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .normal) + audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_video_mode"), for: .selected) } else { - audioSourceButton?.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .normal) - audioSourceButton?.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .selected) + audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .normal) + audioSourceButton.setImage(#imageLiteral(resourceName: "ic_speaker_bluetooth_inactive_audio_mode"), for: .selected) } - audioSourceButton?.isHidden = false + audioSourceButton.isHidden = false } else { // No bluetooth audio detected - audioSourceButton?.setImage(#imageLiteral(resourceName: "audio-call-speaker-inactive"), for: .normal) - audioSourceButton?.setImage(#imageLiteral(resourceName: "audio-call-speaker-active"), for: .selected) + audioSourceButton.setImage(#imageLiteral(resourceName: "audio-call-speaker-inactive"), for: .normal) + audioSourceButton.setImage(#imageLiteral(resourceName: "audio-call-speaker-active"), for: .selected) // If there's no bluetooth, we always use speakerphone, so no need for // a button, giving more screen back for the video. - audioSourceButton?.isHidden = hasLocalVideo + audioSourceButton.isHidden = hasLocalVideo } // Dismiss Handling @@ -869,18 +819,18 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // before the operation completes. func updateAudioSourceButtonIsSelected() { guard callUIAdapter.audioService.isSpeakerphoneEnabled else { - self.audioSourceButton?.isSelected = false + self.audioSourceButton.isSelected = false return } // VideoChat mode enables the output speaker, but we don't // want to highlight the speaker button in that case. guard !call.hasLocalVideo else { - self.audioSourceButton?.isSelected = false + self.audioSourceButton.isSelected = false return } - self.audioSourceButton?.isSelected = true + self.audioSourceButton.isSelected = true } // MARK: - Actions @@ -986,10 +936,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", private func markSettingsNagAsComplete() { Logger.info("\(TAG) called \(#function)") - guard let preferences = Environment.current().preferences else { - owsFail("\(TAG) missing preferences.") - return - } + let preferences = Environment.current().preferences! preferences.setIsCallKitEnabled(preferences.isCallKitEnabled()) preferences.setIsCallKitPrivacyEnabled(preferences.isCallKitPrivacyEnabled()) @@ -1053,10 +1000,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", guard self.localVideoTrack != localVideoTrack else { return } - guard let localVideoView = localVideoView else { - owsFail("\(TAG) missing localVideoView.") - return - } self.localVideoTrack = localVideoTrack @@ -1080,10 +1023,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", guard self.remoteVideoTrack != remoteVideoTrack else { return } - guard let remoteVideoView = remoteVideoView else { - owsFail("\(TAG) missing remoteVideoView.") - return - } self.remoteVideoTrack?.remove(remoteVideoView) self.remoteVideoTrack = nil