From ce197b0ada5600ba4d06e011ad18cf2da3a59a7f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 11:40:42 -0400 Subject: [PATCH 01/14] Remove usage of ! in call view. --- .../ViewControllers/CallViewController.swift | 257 +++++++++++------- 1 file changed, 159 insertions(+), 98 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 106c7ecac..f25187afe 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 - var contactNameLabel: MarqueeLabel! - var contactAvatarView: AvatarImageView! - var contactAvatarContainerView: UIView! - var callStatusLabel: UILabel! + let contactNameLabel = MarqueeLabel() + let contactAvatarView = AvatarImageView() + let contactAvatarContainerView = UIView.container() + let 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, } } } - var settingsNagView: UIView! - var settingsNagDescriptionLabel: UILabel! + let settingsNagView = UIView() + let settingsNagDescriptionLabel = UILabel() // MARK: Audio Source @@ -219,7 +219,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // Dark blurred background. let blurEffect = UIBlurEffect(style: .dark) - blurView = UIVisualEffectView(effect: blurEffect) + let blurView = UIVisualEffectView(effect: blurEffect) + self.blurView = blurView blurView.isUserInteractionEnabled = false self.view.addSubview(blurView) @@ -234,15 +235,22 @@ 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() { - remoteVideoView = RemoteVideoView() + let remoteVideoView = RemoteVideoView() + self.remoteVideoView = remoteVideoView remoteVideoView.isUserInteractionEnabled = false - localVideoView = RTCCameraPreviewView() + + let localVideoView = RTCCameraPreviewView() + self.localVideoView = localVideoView remoteVideoView.isHidden = true localVideoView.isHidden = true @@ -251,8 +259,6 @@ 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. @@ -272,7 +278,6 @@ 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 @@ -280,14 +285,11 @@ 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) @@ -296,7 +298,6 @@ 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)) @@ -348,32 +349,38 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // textMessageButton = createButton(imageName:"message-active-wide", // action:#selector(didPressTextMessage)) - 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") + 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 setButtonSelectedImage(button: audioModeMuteButton, imageName: "audio-call-mute-active") setButtonSelectedImage(button: videoModeMuteButton, imageName: "video-mute-selected") @@ -425,14 +432,16 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, func createIncomingCallControls() { - 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") + 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 incomingCallView = createContainerForCallControls(controlGroups: [ [acceptIncomingButton, declineIncomingButton ] @@ -451,19 +460,19 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, for row in rows { containerView.addSubview(row) row.autoHCenterInSuperview() - if prevRow != nil { - row.autoPinEdge(.top, to: .bottom, of: prevRow!, withOffset: rowspacing) + if let prevRow = prevRow { + 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) -> UIButton { + func createButton(imageName: String, action: Selector, accessibilityLabel: String) -> UIButton { let image = UIImage(named: imageName) assert(image != nil) let button = UIButton() @@ -475,6 +484,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, button.addTarget(self, action: action, for: .touchUpInside) button.autoSetDimension(.width, toSize: buttonSize()) button.autoSetDimension(.height, toSize: buttonSize()) + button.accessibilityLabel = accessibilityLabel return button } @@ -493,11 +503,11 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, subview.setContentHuggingHorizontalHigh() subview.autoVCenterInSuperview() - if lastSubview != nil { + if let lastSubview = lastSubview { 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() @@ -512,8 +522,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, 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! @@ -528,6 +538,27 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // 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. // @@ -613,11 +644,19 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, } 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) @@ -662,9 +701,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, let callDuration = call.connectionDuration() let callDurationDate = Date(timeIntervalSinceReferenceDate: callDuration) if dateFormatter == nil { - dateFormatter = DateFormatter() - dateFormatter!.dateFormat = "HH:mm:ss" - dateFormatter!.timeZone = TimeZone(identifier: "UTC")! + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "HH:mm:ss" + dateFormatter.timeZone = TimeZone(identifier: "UTC")! + self.dateFormatter = dateFormatter } var formattedDate = dateFormatter!.string(from: callDurationDate) if formattedDate.hasPrefix("00:") { @@ -707,29 +747,39 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, 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 @@ -749,7 +799,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, if shouldRemoteVideoControlsBeHidden && !remoteVideoView.isHidden { contactNameLabel.isHidden = true callStatusLabel.isHidden = true - ongoingCallView.isHidden = true + ongoingCallView?.isHidden = true } else { contactNameLabel.isHidden = false callStatusLabel.isHidden = false @@ -759,24 +809,24 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, 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 @@ -819,18 +869,18 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // 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 @@ -936,7 +986,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, private func markSettingsNagAsComplete() { Logger.info("\(TAG) called \(#function)") - let preferences = Environment.current().preferences! + guard let preferences = Environment.current().preferences else { + owsFail("\(TAG) missing preferences.") + return + } preferences.setIsCallKitEnabled(preferences.isCallKitEnabled()) preferences.setIsCallKitPrivacyEnabled(preferences.isCallKitPrivacyEnabled()) @@ -1000,6 +1053,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, guard self.localVideoTrack != localVideoTrack else { return } + guard let localVideoView = localVideoView else { + owsFail("\(TAG) missing localVideoView.") + return + } self.localVideoTrack = localVideoTrack @@ -1023,6 +1080,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, guard self.remoteVideoTrack != remoteVideoTrack else { return } + guard let remoteVideoView = remoteVideoView else { + owsFail("\(TAG) missing remoteVideoView.") + return + } self.remoteVideoTrack?.remove(remoteVideoView) self.remoteVideoTrack = nil From 699bf0a8293bb1beb85926ec25d75d8ce886a688 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 13:28:33 -0400 Subject: [PATCH 02/14] Remove usage of ! in call view. --- .../ViewControllers/CallViewController.swift | 44 +++++++------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index f25187afe..239824054 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -30,7 +30,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Views var hasConstraints = false - var blurView: UIVisualEffectView? + let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) var dateFormatter: DateFormatter? // MARK: Contact Views @@ -43,7 +43,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Ongoing Call Controls - var ongoingCallView: UIView? + let ongoingCallView = UIView() var hangUpButton: UIButton? var audioSourceButton: UIButton? @@ -58,7 +58,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Incoming Call Controls - var incomingCallView: UIView? + let incomingCallView = UIView() var acceptIncomingButton: UIButton? var declineIncomingButton: UIButton? @@ -218,9 +218,6 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, action: #selector(didTouchRootView))) // Dark blurred background. - let blurEffect = UIBlurEffect(style: .dark) - let blurView = UIVisualEffectView(effect: blurEffect) - self.blurView = blurView blurView.isUserInteractionEnabled = false self.view.addSubview(blurView) @@ -387,7 +384,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, setButtonSelectedImage(button: audioModeVideoButton, imageName: "audio-call-video-active") setButtonSelectedImage(button: videoModeVideoButton, imageName: "video-video-selected") - ongoingCallView = createContainerForCallControls(controlGroups: [ + createContainerForCallControls(containerView: ongoingCallView, + controlGroups: [ [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], [videoModeMuteButton, hangUpButton, videoModeVideoButton ] ]) @@ -443,13 +441,14 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", comment: "Accessibility label for declining incoming calls")) self.declineIncomingButton = declineIncomingButton - incomingCallView = createContainerForCallControls(controlGroups: [ + createContainerForCallControls(containerView: incomingCallView, + controlGroups: [ [acceptIncomingButton, declineIncomingButton ] ]) } - func createContainerForCallControls(controlGroups: [[UIView]]) -> UIView { - let containerView = UIView() + func createContainerForCallControls(containerView: UIView, + controlGroups: [[UIView]]) { self.view.addSubview(containerView) var rows: [UIView] = [] for controlGroup in controlGroups { @@ -469,7 +468,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", containerView.setContentHuggingVerticalHigh() rows.first?.autoPinEdge(toSuperviewEdge: .top) rows.last?.autoPinEdge(toSuperviewEdge: .bottom) - return containerView } func createButton(imageName: String, action: Selector, accessibilityLabel: String) -> UIButton { @@ -538,10 +536,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 @@ -550,14 +544,6 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", 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. @@ -762,7 +748,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", if isShowingSettingsNag { settingsNagView.isHidden = false contactAvatarView.isHidden = true - ongoingCallView?.isHidden = true + ongoingCallView.isHidden = true return } @@ -776,10 +762,10 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // 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 +785,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 From 3cbd49627aedaa42974b2568f0fd8f9791ea7194 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 13:58:43 -0400 Subject: [PATCH 03/14] Remove usage of ! in call view. --- .../ViewControllers/CallViewController.swift | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 239824054..7d9c7b750 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -52,9 +52,9 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, 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 + // so users can send and read messages during a // call. -// var textMessageButton: UIButton! + // var textMessageButton: UIButton! // MARK: Incoming Call Controls @@ -309,7 +309,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, let descriptionVSpacingHeight = ScaleFromIPhone5To7Plus(30, 60) let callSettingsButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_SHOW_CALL_SETTINGS", - comment: "Label for button that shows the privacy settings."), + comment: "Label for button that shows the privacy settings."), font: OWSFlatButton.fontForHeight(buttonHeight), titleColor: UIColor.white, backgroundColor: UIColor.ows_signalBrandBlue, @@ -321,7 +321,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, callSettingsButton.autoPinEdge(.top, to: .bottom, of: settingsNagDescriptionLabel, withOffset: descriptionVSpacingHeight) let notNowButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_NOT_NOW_BUTTON", - comment: "Label for button that dismiss the call view's settings nag."), + comment: "Label for button that dismiss the call view's settings nag."), font: OWSFlatButton.fontForHeight(buttonHeight), titleColor: UIColor.white, backgroundColor: UIColor.ows_signalBrandBlue, @@ -344,39 +344,39 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, func createOngoingCallControls() { -// textMessageButton = createButton(imageName:"message-active-wide", -// action:#selector(didPressTextMessage)) + // 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")) + 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")) + 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")) + 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")) + 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")) + 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")) + action: #selector(didPressVideo), + accessibilityLabel: NSLocalizedString("CALL_VIEW_SWITCH_TO_AUDIO_LABEL", comment: "Accessibility label to switch to audio only")) self.videoModeVideoButton = videoModeVideoButton setButtonSelectedImage(button: audioModeMuteButton, imageName: "audio-call-mute-active") @@ -386,9 +386,9 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, createContainerForCallControls(containerView: ongoingCallView, controlGroups: [ - [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], - [videoModeMuteButton, hangUpButton, videoModeVideoButton ] - ]) + [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], + [videoModeMuteButton, hangUpButton, videoModeVideoButton ] + ]) } func presentAudioSourcePicker() { @@ -431,19 +431,19 @@ 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")) + 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")) + action: #selector(didPressDeclineCall), + accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", + comment: "Accessibility label for declining incoming calls")) self.declineIncomingButton = declineIncomingButton createContainerForCallControls(containerView: incomingCallView, controlGroups: [ - [acceptIncomingButton, declineIncomingButton ] + [acceptIncomingButton, declineIncomingButton ] ]) } @@ -565,7 +565,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // The buttons have built-in 10% margins, so to appear centered // the avatar's bottom spacing should be a bit less. let avatarBottomSpacing = ScaleFromIPhone5To7Plus(18, 41) - // Layout of the local video view is a bit unusual because + // Layout of the local video view is a bit unusual because // although the view is square, it will be used let videoPreviewHMargin = CGFloat(0) @@ -830,10 +830,10 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", if callDurationTimer == nil { let kDurationUpdateFrequencySeconds = 1 / 20.0 callDurationTimer = WeakTimer.scheduledTimer(timeInterval: TimeInterval(kDurationUpdateFrequencySeconds), - target: self, - userInfo: nil, - repeats: true) {[weak self] _ in - self?.updateCallDuration() + target: self, + userInfo: nil, + repeats: true) {[weak self] _ in + self?.updateCallDuration() } } } else { @@ -965,8 +965,8 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // We only show the "blocking" settings nag until the user has chosen // to view the privacy settings _or_ dismissed the nag at least once. - // - // In either case, we set the "CallKit enabled" and "CallKit privacy enabled" + // + // In either case, we set the "CallKit enabled" and "CallKit privacy enabled" // settings to their default values to indicate that the user has reviewed // them. private func markSettingsNagAsComplete() { From 594ddfaec3bef360541322ada7c5bf741abc9923 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 14:39:37 -0400 Subject: [PATCH 04/14] Revert "Remove usage of ! in call view." This reverts commit 3cbd49627aedaa42974b2568f0fd8f9791ea7194. --- .../ViewControllers/CallViewController.swift | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 7d9c7b750..239824054 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -52,9 +52,9 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, 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 + // so users can send and read messages during a // call. - // var textMessageButton: UIButton! +// var textMessageButton: UIButton! // MARK: Incoming Call Controls @@ -309,7 +309,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, let descriptionVSpacingHeight = ScaleFromIPhone5To7Plus(30, 60) let callSettingsButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_SHOW_CALL_SETTINGS", - comment: "Label for button that shows the privacy settings."), + comment: "Label for button that shows the privacy settings."), font: OWSFlatButton.fontForHeight(buttonHeight), titleColor: UIColor.white, backgroundColor: UIColor.ows_signalBrandBlue, @@ -321,7 +321,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, callSettingsButton.autoPinEdge(.top, to: .bottom, of: settingsNagDescriptionLabel, withOffset: descriptionVSpacingHeight) let notNowButton = OWSFlatButton.button(title: NSLocalizedString("CALL_VIEW_SETTINGS_NAG_NOT_NOW_BUTTON", - comment: "Label for button that dismiss the call view's settings nag."), + comment: "Label for button that dismiss the call view's settings nag."), font: OWSFlatButton.fontForHeight(buttonHeight), titleColor: UIColor.white, backgroundColor: UIColor.ows_signalBrandBlue, @@ -344,39 +344,39 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, func createOngoingCallControls() { - // textMessageButton = createButton(imageName:"message-active-wide", - // action:#selector(didPressTextMessage)) +// 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")) + 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")) + 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")) + 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")) + 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")) + 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")) + action: #selector(didPressVideo), + accessibilityLabel: NSLocalizedString("CALL_VIEW_SWITCH_TO_AUDIO_LABEL", comment: "Accessibility label to switch to audio only")) self.videoModeVideoButton = videoModeVideoButton setButtonSelectedImage(button: audioModeMuteButton, imageName: "audio-call-mute-active") @@ -386,9 +386,9 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, createContainerForCallControls(containerView: ongoingCallView, controlGroups: [ - [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], - [videoModeMuteButton, hangUpButton, videoModeVideoButton ] - ]) + [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], + [videoModeMuteButton, hangUpButton, videoModeVideoButton ] + ]) } func presentAudioSourcePicker() { @@ -431,19 +431,19 @@ 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")) + 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")) + action: #selector(didPressDeclineCall), +accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", + comment: "Accessibility label for declining incoming calls")) self.declineIncomingButton = declineIncomingButton createContainerForCallControls(containerView: incomingCallView, controlGroups: [ - [acceptIncomingButton, declineIncomingButton ] + [acceptIncomingButton, declineIncomingButton ] ]) } @@ -565,7 +565,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // The buttons have built-in 10% margins, so to appear centered // the avatar's bottom spacing should be a bit less. let avatarBottomSpacing = ScaleFromIPhone5To7Plus(18, 41) - // Layout of the local video view is a bit unusual because + // Layout of the local video view is a bit unusual because // although the view is square, it will be used let videoPreviewHMargin = CGFloat(0) @@ -830,10 +830,10 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, if callDurationTimer == nil { let kDurationUpdateFrequencySeconds = 1 / 20.0 callDurationTimer = WeakTimer.scheduledTimer(timeInterval: TimeInterval(kDurationUpdateFrequencySeconds), - target: self, - userInfo: nil, - repeats: true) {[weak self] _ in - self?.updateCallDuration() + target: self, + userInfo: nil, + repeats: true) {[weak self] _ in + self?.updateCallDuration() } } } else { @@ -965,8 +965,8 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // We only show the "blocking" settings nag until the user has chosen // to view the privacy settings _or_ dismissed the nag at least once. - // - // In either case, we set the "CallKit enabled" and "CallKit privacy enabled" + // + // In either case, we set the "CallKit enabled" and "CallKit privacy enabled" // settings to their default values to indicate that the user has reviewed // them. private func markSettingsNagAsComplete() { From 943b3f031c43bc4b838a0187712791f4eedd61a8 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 14:39:50 -0400 Subject: [PATCH 05/14] Revert "Remove usage of ! in call view." This reverts commit 699bf0a8293bb1beb85926ec25d75d8ce886a688. --- .../ViewControllers/CallViewController.swift | 44 ++++++++++++------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 239824054..f25187afe 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -30,7 +30,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Views var hasConstraints = false - let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark)) + var blurView: UIVisualEffectView? var dateFormatter: DateFormatter? // MARK: Contact Views @@ -43,7 +43,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Ongoing Call Controls - let ongoingCallView = UIView() + var ongoingCallView: UIView? var hangUpButton: UIButton? var audioSourceButton: UIButton? @@ -58,7 +58,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, // MARK: Incoming Call Controls - let incomingCallView = UIView() + var incomingCallView: UIView? var acceptIncomingButton: UIButton? var declineIncomingButton: UIButton? @@ -218,6 +218,9 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, action: #selector(didTouchRootView))) // Dark blurred background. + let blurEffect = UIBlurEffect(style: .dark) + let blurView = UIVisualEffectView(effect: blurEffect) + self.blurView = blurView blurView.isUserInteractionEnabled = false self.view.addSubview(blurView) @@ -384,8 +387,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, setButtonSelectedImage(button: audioModeVideoButton, imageName: "audio-call-video-active") setButtonSelectedImage(button: videoModeVideoButton, imageName: "video-video-selected") - createContainerForCallControls(containerView: ongoingCallView, - controlGroups: [ + ongoingCallView = createContainerForCallControls(controlGroups: [ [audioModeMuteButton, audioSourceButton, audioModeVideoButton ], [videoModeMuteButton, hangUpButton, videoModeVideoButton ] ]) @@ -441,14 +443,13 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", comment: "Accessibility label for declining incoming calls")) self.declineIncomingButton = declineIncomingButton - createContainerForCallControls(containerView: incomingCallView, - controlGroups: [ + incomingCallView = createContainerForCallControls(controlGroups: [ [acceptIncomingButton, declineIncomingButton ] ]) } - func createContainerForCallControls(containerView: UIView, - controlGroups: [[UIView]]) { + func createContainerForCallControls(controlGroups: [[UIView]]) -> UIView { + let containerView = UIView() self.view.addSubview(containerView) var rows: [UIView] = [] for controlGroup in controlGroups { @@ -468,6 +469,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", containerView.setContentHuggingVerticalHigh() rows.first?.autoPinEdge(toSuperviewEdge: .top) rows.last?.autoPinEdge(toSuperviewEdge: .bottom) + return containerView } func createButton(imageName: String, action: Selector, accessibilityLabel: String) -> UIButton { @@ -536,6 +538,10 @@ 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 @@ -544,6 +550,14 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", 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. @@ -748,7 +762,7 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", if isShowingSettingsNag { settingsNagView.isHidden = false contactAvatarView.isHidden = true - ongoingCallView.isHidden = true + ongoingCallView?.isHidden = true return } @@ -762,10 +776,10 @@ accessibilityLabel: NSLocalizedString("CALL_VIEW_DECLINE_INCOMING_CALL_LABEL", // 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 @@ -785,7 +799,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 From 621d54db1762e9c565251b5850483ab1ba472c45 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 14:39:59 -0400 Subject: [PATCH 06/14] 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 From cc42e85bd6afd0fe350d6af68f2f3b3c153c0f98 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 15:39:35 -0400 Subject: [PATCH 07/14] Avoid race condition in call view controller. --- .../ViewControllers/CallViewController.swift | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Signal/src/ViewControllers/CallViewController.swift b/Signal/src/ViewControllers/CallViewController.swift index 106c7ecac..d9ed3dd01 100644 --- a/Signal/src/ViewControllers/CallViewController.swift +++ b/Signal/src/ViewControllers/CallViewController.swift @@ -140,17 +140,6 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, super.init(nibName: nil, bundle: nil) allAudioSources = Set(callUIAdapter.audioService.availableInputs) - - assert(callUIAdapter.audioService.delegate == nil) - callUIAdapter.audioService.delegate = self - observeNotifications() - } - - func observeNotifications() { - NotificationCenter.default.addObserver(self, - selector: #selector(didBecomeActive), - name: NSNotification.Name.OWSApplicationDidBecomeActive, - object: nil) } deinit { @@ -208,6 +197,14 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver, call.addObserverAndSyncState(observer: self) SignalApp.shared().callService.addObserverAndSyncState(observer: self) + + assert(callUIAdapter.audioService.delegate == nil) + callUIAdapter.audioService.delegate = self + + NotificationCenter.default.addObserver(self, + selector: #selector(didBecomeActive), + name: NSNotification.Name.OWSApplicationDidBecomeActive, + object: nil) } // MARK: - Create Views From 4f1f1a107f82b837c58f608e3a82209327b3856c Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 15:33:17 -0400 Subject: [PATCH 08/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.m | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 307ebe66c..0885c8f95 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -138,36 +138,50 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) DDLogVerbose(@"%@ async registrations enqueued.", self.logTag); - // Block until all async registrations are complete. - // - // NOTE: This has to happen on the "registration connections" for this - // database. - NSMutableSet *pendingRegistrationConnectionSet = - [[((OWSDatabase *)self.database)clearCollectedRegistrationConnections] mutableCopy]; - DDLogVerbose(@"%@ flushing registration connections: %zd.", self.logTag, pendingRegistrationConnectionSet.count); - - dispatch_async(dispatch_get_main_queue(), ^{ - for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { - [dbConnection - flushTransactionsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssertIsOnMainThread(); - OWSAssert(!self.areAsyncRegistrationsComplete); - - [pendingRegistrationConnectionSet removeObject:dbConnection]; - if (pendingRegistrationConnectionSet.count > 0) { - DDLogVerbose(@"%@ registration connection flushed.", self.logTag); - return; - } - - DDLogVerbose(@"%@ async registrations complete.", self.logTag); - - self.areAsyncRegistrationsComplete = YES; - - completion(); - }]; - } - }); + [[self registrationConnection] asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + // Block until all async registrations are complete. + // + // NOTE: This has to happen on the "registration connections" for this + // database. + NSMutableSet *pendingRegistrationConnectionSet = + [[((OWSDatabase *)self.database)clearCollectedRegistrationConnections] mutableCopy]; + DDLogVerbose(@"%@ flushing registration connections: %zd.", self.logTag, pendingRegistrationConnectionSet.count); + + dispatch_async(dispatch_get_main_queue(), ^{ + if (pendingRegistrationConnectionSet.count > 0) { + for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { + [dbConnection + flushTransactionsWithCompletionQueue:dispatch_get_main_queue() + completionBlock:^{ + OWSAssertIsOnMainThread(); + + [pendingRegistrationConnectionSet removeObject:dbConnection]; + if (pendingRegistrationConnectionSet.count > 0) { + DDLogVerbose(@"%@ registration connection flushed.", self.logTag); + return; + } + + [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; + }]; + } + } else { + [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; + } + }); + }]; +} + +- (void)markAsyncRegistrationsAsCompleteWithCompletion:(void (^_Nonnull)(void))completion +{ + OWSAssertIsOnMainThread(); + OWSAssert(!self.areAsyncRegistrationsComplete); + OWSAssert(completion); + + DDLogVerbose(@"%@ async registrations complete.", self.logTag); + + self.areAsyncRegistrationsComplete = YES; + + completion(); } + (void)protectFiles From 5d627ee89ff0e392ca9144423b8bc3102295cc9f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 15:37:32 -0400 Subject: [PATCH 09/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.m | 73 +++++++++++-------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 0885c8f95..5e182ec88 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -138,37 +138,48 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) DDLogVerbose(@"%@ async registrations enqueued.", self.logTag); - [[self registrationConnection] asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - // Block until all async registrations are complete. - // - // NOTE: This has to happen on the "registration connections" for this - // database. - NSMutableSet *pendingRegistrationConnectionSet = - [[((OWSDatabase *)self.database)clearCollectedRegistrationConnections] mutableCopy]; - DDLogVerbose(@"%@ flushing registration connections: %zd.", self.logTag, pendingRegistrationConnectionSet.count); - - dispatch_async(dispatch_get_main_queue(), ^{ - if (pendingRegistrationConnectionSet.count > 0) { - for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { - [dbConnection - flushTransactionsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssertIsOnMainThread(); - - [pendingRegistrationConnectionSet removeObject:dbConnection]; - if (pendingRegistrationConnectionSet.count > 0) { - DDLogVerbose(@"%@ registration connection flushed.", self.logTag); - return; - } - - [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; - }]; - } - } else { - [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; - } - }); - }]; + // Flush the write queue to ensure all async registrations have begun. + [[self registrationConnection] + flushTransactionsWithCompletionQueue:dispatch_get_main_queue() + completionBlock:^{ + // Block until all async registrations are complete. + // + // NOTE: This has to happen on the "registration connections" for this + // database. + NSMutableSet *pendingRegistrationConnectionSet = [ + [((OWSDatabase *)self.database)clearCollectedRegistrationConnections] mutableCopy]; + DDLogVerbose(@"%@ flushing registration connections: %zd.", + self.logTag, + pendingRegistrationConnectionSet.count); + + dispatch_async(dispatch_get_main_queue(), ^{ + if (pendingRegistrationConnectionSet.count > 0) { + for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { + [dbConnection + flushTransactionsWithCompletionQueue:dispatch_get_main_queue() + completionBlock:^{ + OWSAssertIsOnMainThread(); + + [pendingRegistrationConnectionSet + removeObject:dbConnection]; + if (pendingRegistrationConnectionSet.count + > 0) { + DDLogVerbose(@"%@ registration " + @"connection flushed.", + self.logTag); + return; + } + + [self + markAsyncRegistrationsAsCompleteWithCompletion: + completion]; + }]; + } + } else { + [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; + } + }); + }]; } - (void)markAsyncRegistrationsAsCompleteWithCompletion:(void (^_Nonnull)(void))completion From 5bbce14020248ca9f2a7963615c2e70085267f8d Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 15:53:12 -0400 Subject: [PATCH 10/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.m | 60 +++++++------------ 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 5e182ec88..b15cbdc9f 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -153,48 +153,34 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) pendingRegistrationConnectionSet.count); dispatch_async(dispatch_get_main_queue(), ^{ - if (pendingRegistrationConnectionSet.count > 0) { - for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { - [dbConnection - flushTransactionsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssertIsOnMainThread(); - - [pendingRegistrationConnectionSet - removeObject:dbConnection]; - if (pendingRegistrationConnectionSet.count - > 0) { - DDLogVerbose(@"%@ registration " - @"connection flushed.", - self.logTag); - return; - } - - [self - markAsyncRegistrationsAsCompleteWithCompletion: - completion]; - }]; - } - } else { - [self markAsyncRegistrationsAsCompleteWithCompletion:completion]; + for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { + [dbConnection + flushTransactionsWithCompletionQueue:dispatch_get_main_queue() + completionBlock:^{ + OWSAssertIsOnMainThread(); + OWSAssert(!self.areAsyncRegistrationsComplete); + + [pendingRegistrationConnectionSet + removeObject:dbConnection]; + if (pendingRegistrationConnectionSet.count > 0) { + DDLogVerbose(@"%@ registration " + @"connection flushed.", + self.logTag); + return; + } + + DDLogVerbose(@"%@ async registrations complete.", + self.logTag); + + self.areAsyncRegistrationsComplete = YES; + + completion(); + }]; } }); }]; } -- (void)markAsyncRegistrationsAsCompleteWithCompletion:(void (^_Nonnull)(void))completion -{ - OWSAssertIsOnMainThread(); - OWSAssert(!self.areAsyncRegistrationsComplete); - OWSAssert(completion); - - DDLogVerbose(@"%@ async registrations complete.", self.logTag); - - self.areAsyncRegistrationsComplete = YES; - - completion(); -} - + (void)protectFiles { DDLogInfo( From e1138df771045c682c4041cc8f43781b535638bd Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 16:24:18 -0400 Subject: [PATCH 11/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.m | 52 ++++++------------- SignalServiceKit/src/Storage/OWSStorage.h | 6 --- SignalServiceKit/src/Storage/OWSStorage.m | 22 -------- 3 files changed, 17 insertions(+), 63 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index b15cbdc9f..5a2701434 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -132,52 +132,34 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) { OWSAssert(completion); - [((OWSDatabase *)self.database)collectRegistrationConnections]; - runAsyncRegistrationsForStorage(self); DDLogVerbose(@"%@ async registrations enqueued.", self.logTag); // Flush the write queue to ensure all async registrations have begun. - [[self registrationConnection] + [[self newDatabaseConnection] flushTransactionsWithCompletionQueue:dispatch_get_main_queue() completionBlock:^{ // Block until all async registrations are complete. // // NOTE: This has to happen on the "registration connections" for this // database. - NSMutableSet *pendingRegistrationConnectionSet = [ - [((OWSDatabase *)self.database)clearCollectedRegistrationConnections] mutableCopy]; - DDLogVerbose(@"%@ flushing registration connections: %zd.", - self.logTag, - pendingRegistrationConnectionSet.count); - - dispatch_async(dispatch_get_main_queue(), ^{ - for (YapDatabaseConnection *dbConnection in pendingRegistrationConnectionSet) { - [dbConnection - flushTransactionsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssertIsOnMainThread(); - OWSAssert(!self.areAsyncRegistrationsComplete); - - [pendingRegistrationConnectionSet - removeObject:dbConnection]; - if (pendingRegistrationConnectionSet.count > 0) { - DDLogVerbose(@"%@ registration " - @"connection flushed.", - self.logTag); - return; - } - - DDLogVerbose(@"%@ async registrations complete.", - self.logTag); - - self.areAsyncRegistrationsComplete = YES; - - completion(); - }]; - } - }); + + OWSAssert(!self.areAsyncRegistrationsComplete); + + [pendingRegistrationConnectionSet removeObject:dbConnection]; + if (pendingRegistrationConnectionSet.count > 0) { + DDLogVerbose(@"%@ registration " + @"connection flushed.", + self.logTag); + return; + } + + DDLogVerbose(@"%@ async registrations complete.", self.logTag); + + self.areAsyncRegistrationsComplete = YES; + + completion(); }]; } diff --git a/SignalServiceKit/src/Storage/OWSStorage.h b/SignalServiceKit/src/Storage/OWSStorage.h index 5beab984e..bff225e68 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.h +++ b/SignalServiceKit/src/Storage/OWSStorage.h @@ -44,12 +44,6 @@ extern NSString *const StorageIsReadyNotification; options:(YapDatabaseOptions *)inOptions delegate:(id)delegate NS_DESIGNATED_INITIALIZER; -// Starts collecting references to the registration connections. -- (void)collectRegistrationConnections; -// Stops collecting references to the registration connections and returns -// all collected connections. -- (NSSet *)clearCollectedRegistrationConnections; - @end #pragma mark - diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index e79cc8069..c3a3418c0 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -134,8 +134,6 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); @property (atomic, weak) id delegate; -@property (nonatomic, readonly, nullable) NSMutableSet *registrationConnectionSet; - @end #pragma mark - @@ -185,29 +183,9 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); ((OWSDatabaseConnection *)connection).canWriteBeforeStorageReady = YES; #endif - [self.registrationConnectionSet addObject:connection]; - return connection; } -- (void)collectRegistrationConnections -{ - OWSAssert(!self.registrationConnectionSet); - - _registrationConnectionSet = [NSMutableSet set]; -} - -- (NSSet *)clearCollectedRegistrationConnections -{ - OWSAssert(self.registrationConnectionSet); - - NSSet *registrationConnectionSetCopy = [self.registrationConnectionSet copy]; - - _registrationConnectionSet = nil; - - return registrationConnectionSetCopy; -} - @end #pragma mark - From a264268253327012b1008f4f5c92e9796a212789 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 16:28:15 -0400 Subject: [PATCH 12/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.m | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 5a2701434..9a182e0b6 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -136,31 +136,23 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) DDLogVerbose(@"%@ async registrations enqueued.", self.logTag); - // Flush the write queue to ensure all async registrations have begun. - [[self newDatabaseConnection] - flushTransactionsWithCompletionQueue:dispatch_get_main_queue() - completionBlock:^{ - // Block until all async registrations are complete. - // - // NOTE: This has to happen on the "registration connections" for this - // database. - - OWSAssert(!self.areAsyncRegistrationsComplete); - - [pendingRegistrationConnectionSet removeObject:dbConnection]; - if (pendingRegistrationConnectionSet.count > 0) { - DDLogVerbose(@"%@ registration " - @"connection flushed.", - self.logTag); - return; - } - - DDLogVerbose(@"%@ async registrations complete.", self.logTag); - - self.areAsyncRegistrationsComplete = YES; - - completion(); - }]; + // Use an empty read/write transaction to to ensure all async registrations have completed. + [[self newDatabaseConnection] asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + // Do nothing. + // + // We can't use flushTransactionsWithCompletionQueue because it + // doesn't flush the YapDatabase.writeQueue. + } + completionQueue:dispatch_get_main_queue() + completionBlock:^{ + OWSAssert(!self.areAsyncRegistrationsComplete); + + DDLogVerbose(@"%@ async registrations complete.", self.logTag); + + self.areAsyncRegistrationsComplete = YES; + + completion(); + }]; } + (void)protectFiles From 35ee8c1a0da46da122e86261b1e3353a79f3bea7 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 16:44:47 -0400 Subject: [PATCH 13/14] Rework flush of registration connection(s). --- .../src/Storage/OWSPrimaryStorage.h | 3 -- .../src/Storage/OWSPrimaryStorage.m | 31 ++++++++----------- SignalServiceKit/src/Storage/OWSStorage.h | 3 ++ SignalServiceKit/src/Storage/OWSStorage.m | 13 ++++++++ SignalServiceKit/src/Storage/TSDatabaseView.h | 3 +- SignalServiceKit/src/Storage/TSDatabaseView.m | 5 ++- 6 files changed, 35 insertions(+), 23 deletions(-) diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h b/SignalServiceKit/src/Storage/OWSPrimaryStorage.h index 39cc94af2..64c68ba8d 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.h @@ -6,9 +6,6 @@ NS_ASSUME_NONNULL_BEGIN -void runSyncRegistrationsForStorage(OWSStorage *storage); -void runAsyncRegistrationsForStorage(OWSStorage *storage); - @interface OWSPrimaryStorage : OWSStorage - (instancetype)init NS_UNAVAILABLE; diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index 9a182e0b6..3329e494b 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -30,9 +30,10 @@ void runSyncRegistrationsForStorage(OWSStorage *storage) [TSDatabaseView registerCrossProcessNotifier:storage]; } -void runAsyncRegistrationsForStorage(OWSStorage *storage) +void runAsyncRegistrationsForStorage(OWSStorage *storage, dispatch_block_t completion) { OWSCAssert(storage); + OWSCAssert(completion); // Asynchronously register other extensions. // @@ -57,7 +58,9 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) [OWSFailedMessagesJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage]; [OWSFailedAttachmentDownloadsJob asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage]; [OWSMediaGalleryFinder asyncRegisterDatabaseExtensionsWithPrimaryStorage:storage]; - [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:storage]; + // NOTE: Always pass the completion to the _LAST_ of the async database + // view registrations. + [TSDatabaseView asyncRegisterLazyRestoreAttachmentsDatabaseView:storage completion:completion]; } #pragma mark - @@ -132,27 +135,19 @@ void runAsyncRegistrationsForStorage(OWSStorage *storage) { OWSAssert(completion); - runAsyncRegistrationsForStorage(self); + DDLogVerbose(@"%@ async registrations enqueuing.", self.logTag); - DDLogVerbose(@"%@ async registrations enqueued.", self.logTag); + runAsyncRegistrationsForStorage(self, ^{ + OWSAssertIsOnMainThread(); - // Use an empty read/write transaction to to ensure all async registrations have completed. - [[self newDatabaseConnection] asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - // Do nothing. - // - // We can't use flushTransactionsWithCompletionQueue because it - // doesn't flush the YapDatabase.writeQueue. - } - completionQueue:dispatch_get_main_queue() - completionBlock:^{ - OWSAssert(!self.areAsyncRegistrationsComplete); + OWSAssert(!self.areAsyncRegistrationsComplete); - DDLogVerbose(@"%@ async registrations complete.", self.logTag); + DDLogVerbose(@"%@ async registrations complete.", self.logTag); - self.areAsyncRegistrationsComplete = YES; + self.areAsyncRegistrationsComplete = YES; - completion(); - }]; + completion(); + }); } + (void)protectFiles diff --git a/SignalServiceKit/src/Storage/OWSStorage.h b/SignalServiceKit/src/Storage/OWSStorage.h index bff225e68..12198be48 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.h +++ b/SignalServiceKit/src/Storage/OWSStorage.h @@ -71,6 +71,9 @@ extern NSString *const StorageIsReadyNotification; #endif - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName; +- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension + withName:(NSString *)extensionName + completion:(nullable dispatch_block_t)completion; - (nullable id)registeredExtension:(NSString *)extensionName; diff --git a/SignalServiceKit/src/Storage/OWSStorage.m b/SignalServiceKit/src/Storage/OWSStorage.m index c3a3418c0..75e97c45e 100644 --- a/SignalServiceKit/src/Storage/OWSStorage.m +++ b/SignalServiceKit/src/Storage/OWSStorage.m @@ -487,6 +487,13 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); - (void)asyncRegisterExtension:(YapDatabaseExtension *)extension withName:(NSString *)extensionName +{ + [self asyncRegisterExtension:extension withName:extensionName completion:nil]; +} + +- (void)asyncRegisterExtension:(YapDatabaseExtension *)extension + withName:(NSString *)extensionName + completion:(nullable dispatch_block_t)completion { [self.database asyncRegisterExtension:extension withName:extensionName @@ -496,6 +503,12 @@ typedef NSData *_Nullable (^CreateDatabaseMetadataBlock)(void); } else { DDLogVerbose(@"%@ asyncRegisterExtension succeeded: %@", self.logTag, extensionName); } + + dispatch_async(dispatch_get_main_queue(), ^{ + if (completion) { + completion(); + } + }); }]; } diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.h b/SignalServiceKit/src/Storage/TSDatabaseView.h index 3e83d174b..9954804a6 100644 --- a/SignalServiceKit/src/Storage/TSDatabaseView.h +++ b/SignalServiceKit/src/Storage/TSDatabaseView.h @@ -58,6 +58,7 @@ extern NSString *const TSLazyRestoreAttachmentsDatabaseViewExtensionName; + (void)asyncRegisterSecondaryDevicesDatabaseView:(OWSStorage *)storage; -+ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage; ++ (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage + completion:(nullable dispatch_block_t)completion; @end diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.m b/SignalServiceKit/src/Storage/TSDatabaseView.m index 9e5098b61..c73cf8426 100644 --- a/SignalServiceKit/src/Storage/TSDatabaseView.m +++ b/SignalServiceKit/src/Storage/TSDatabaseView.m @@ -343,6 +343,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" } + (void)asyncRegisterLazyRestoreAttachmentsDatabaseView:(OWSStorage *)storage + completion:(nullable dispatch_block_t)completion { YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *_Nullable( YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key, id object) { @@ -391,7 +392,9 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSAttachment collection]]]; YapDatabaseView *view = [[YapDatabaseAutoView alloc] initWithGrouping:viewGrouping sorting:viewSorting versionTag:@"3" options:options]; - [storage asyncRegisterExtension:view withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName]; + [storage asyncRegisterExtension:view + withName:TSLazyRestoreAttachmentsDatabaseViewExtensionName + completion:completion]; } + (id)unseenDatabaseViewExtension:(YapDatabaseReadTransaction *)transaction From f45970922fef72a2ae57032f7c2475e90f2b19fa Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Apr 2018 17:39:21 -0400 Subject: [PATCH 14/14] "Bump build to 2.24.0.9." --- Signal/Signal-Info.plist | 2 +- SignalShareExtension/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist index eddeb7c85..071ba1d2a 100644 --- a/Signal/Signal-Info.plist +++ b/Signal/Signal-Info.plist @@ -38,7 +38,7 @@ CFBundleVersion - 2.24.0.8 + 2.24.0.9 ITSAppUsesNonExemptEncryption LOGS_EMAIL diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist index ecdc7d90a..e0996cfa7 100644 --- a/SignalShareExtension/Info.plist +++ b/SignalShareExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 2.24.0 CFBundleVersion - 2.24.0.8 + 2.24.0.9 ITSAppUsesNonExemptEncryption NSAppTransportSecurity