@@ -380,6 +380,13 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
380380 UIView . animate ( withDuration: 0.25 ) {
381381 let remoteVideoView : RemoteVideoView = self . floatingViewVideoSource == . remote ? self . floatingRemoteVideoView : self . fullScreenRemoteVideoView
382382 remoteVideoView. alpha = isEnabled ? 1 : 0
383+
384+ // Retain floating view visibility if any of the video feeds are enabled
385+ let isAnyVideoFeedEnabled : Bool = ( isEnabled || self . call. isVideoEnabled)
386+
387+ // Shows floating camera to allow user to switch to fullscreen or floating
388+ // even if the other party has not yet turned on their video feed.
389+ self . floatingViewContainer. isHidden = !isAnyVideoFeedEnabled
383390 }
384391
385392 if self . callInfoLabelStackView. alpha < 0.5 {
@@ -464,9 +471,8 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
464471 setUpViewHierarchy ( )
465472 setUpProfilePictureImage ( )
466473
467- if shouldRestartCamera { cameraManager. prepare ( ) }
468-
469474 _ = call. videoCapturer // Force the lazy var to instantiate
475+
470476 titleLabel. text = self . call. contactName
471477 if self . call. hasConnected {
472478 callDurationLabel. isHidden = false
@@ -659,14 +665,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
659665 self . callInfoLabelStackView. alpha = 1
660666 }
661667
662- Timer . scheduledTimer ( withTimeInterval: 2 , repeats: false ) { [ weak self] _ in
663- DispatchQueue . main. async {
664- self ? . dismiss ( animated: true , completion: {
665- self ? . conversationVC? . becomeFirstResponder ( )
666- self ? . conversationVC? . showInputAccessoryView ( )
667- } )
668- }
669- }
668+ self . shouldHandleCallDismiss ( delay: 2 )
670669 }
671670
672671 @objc private func answerCall( ) {
@@ -680,21 +679,14 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
680679 }
681680 }
682681
683- @objc private func endCall( ) {
682+ @objc private func endCall( presentCameraRequestDialog : Bool = false ) {
684683 dependencies [ singleton: . callManager] . endCall ( call) { [ weak self, dependencies] error in
684+ self ? . shouldHandleCallDismiss ( delay: 1 , presentCameraRequestDialog: presentCameraRequestDialog)
685+
685686 if let _ = error {
686687 self ? . call. endSessionCall ( )
687688 dependencies [ singleton: . callManager] . reportCurrentCallEnded ( reason: . declinedElsewhere)
688689 }
689-
690- Timer . scheduledTimer ( withTimeInterval: 1 , repeats: false ) { [ weak self] _ in
691- DispatchQueue . main. async {
692- self ? . dismiss ( animated: true , completion: {
693- self ? . conversationVC? . becomeFirstResponder ( )
694- self ? . conversationVC? . showInputAccessoryView ( )
695- } )
696- }
697- }
698690 }
699691 }
700692
@@ -721,43 +713,88 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
721713 // MARK: - Video and Audio
722714
723715 @objc private func operateCamera( ) {
716+
724717 if ( call. isVideoEnabled) {
725- floatingViewContainer. isHidden = true
718+ // Hides local video feed
719+ ( floatingViewVideoSource == . local
720+ ? floatingLocalVideoView
721+ : fullScreenLocalVideoView) . alpha = 0
722+
723+ floatingViewContainer. isHidden = !call. isRemoteVideoEnabled
724+
726725 cameraManager. stop ( )
727726 videoButton. themeTintColor = . textPrimary
728727 videoButton. themeBackgroundColor = . backgroundSecondary
729728 switchCameraButton. isEnabled = false
730729 call. isVideoEnabled = false
731730 }
732731 else {
733- guard Permissions . requestCameraPermissionIfNeeded ( using: dependencies) else {
734- let confirmationModal : ConfirmationModal = ConfirmationModal (
735- info: ConfirmationModal . Info (
736- title: " permissionsRequired " . localized ( ) ,
737- body: . text( " permissionsCameraAccessRequiredCallsIos " . localized ( ) ) ,
738- showCondition: . disabled,
739- confirmTitle: " sessionSettings " . localized ( ) ,
740- onConfirm: { _ in
741- UIApplication . shared. openSystemSettings ( )
742- }
743- )
744- )
732+
733+ // Added delay of preview due to permission dialog alert dismissal on allow.
734+ // It causes issue on `VideoPreviewVC` presentation animation,
735+ // If camera permission is already allowed no animation delay is needed
736+ let previewDelay = Permissions . camera == . undetermined ? 0.5 : 0
737+
738+ Permissions . requestCameraPermissionIfNeeded (
739+ useCustomDeniedAlert: true ,
740+ using: dependencies
741+ ) { [ weak self, dependencies] isAuthorized in
745742
746- self . navigationController? . present ( confirmationModal, animated: true , completion: nil )
747- return
743+ let status = Permissions . camera
744+
745+ switch ( isAuthorized, status) {
746+ case ( false , . denied) :
747+ guard let presentingViewController: UIViewController = ( self ? . navigationController ?? dependencies [ singleton: . appContext] . frontMostViewController)
748+ else { return }
749+
750+ DispatchQueue . main. async {
751+ let confirmationModal : ConfirmationModal = ConfirmationModal (
752+ info: ConfirmationModal . Info (
753+ title: " cameraAccessRequired " . localized ( ) ,
754+ body: . attributedText(
755+ " cameraAccessDeniedMessage "
756+ . put ( key: " app_name " , value: Constants . app_name)
757+ . localizedFormatted ( ) ,
758+ scrollMode: . never
759+ ) ,
760+ confirmTitle: " endCallToEnable " . localized ( ) ,
761+ confirmStyle: . danger,
762+ cancelTitle: " remindMeLater " . localized ( ) ,
763+ cancelStyle: . alert_text,
764+ onConfirm: { _ in
765+ self ? . endCall ( presentCameraRequestDialog: true )
766+ } ,
767+ onCancel: { modal in
768+ dependencies [ defaults: . standard, key: . shouldRemindGrantingCameraPermissionForCalls] = true
769+ modal. dismiss ( animated: true )
770+ }
771+ )
772+ )
773+ presentingViewController. present ( confirmationModal, animated: true , completion: nil )
774+ }
775+ case ( true , _) :
776+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + previewDelay) { [ weak self] in
777+ let previewVC = VideoPreviewVC ( )
778+ previewVC. delegate = self
779+ self ? . present ( previewVC, animated: true , completion: nil )
780+ }
781+ break
782+ default : break
783+ }
748784 }
749- let previewVC = VideoPreviewVC ( )
750- previewVC. delegate = self
751- present ( previewVC, animated: true , completion: nil )
752785 }
753786 }
754-
787+
755788 func cameraDidConfirmTurningOn( ) {
756789 floatingViewContainer. isHidden = false
790+
757791 let localVideoView : LocalVideoView = self . floatingViewVideoSource == . local ? self . floatingLocalVideoView : self . fullScreenLocalVideoView
758792 localVideoView. alpha = 1
793+
794+ // Camera preparation
759795 cameraManager. prepare ( )
760796 cameraManager. start ( )
797+
761798 videoButton. themeTintColor = . backgroundSecondary
762799 videoButton. themeBackgroundColor = . textPrimary
763800 switchCameraButton. isEnabled = true
@@ -874,13 +911,26 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
874911 }
875912 }
876913
914+ private func shouldHandleCallDismiss( delay: TimeInterval , presentCameraRequestDialog: Bool = false ) {
915+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + . seconds( Int ( delay) ) ) { [ weak self, dependencies] in
916+ guard self ? . presentingViewController != nil else { return }
917+
918+ self ? . dismiss ( animated: true , completion: {
919+ self ? . conversationVC? . becomeFirstResponder ( )
920+ self ? . conversationVC? . showInputAccessoryView ( )
921+
922+ if presentCameraRequestDialog {
923+ Permissions . showEnableCameraAccessInstructions ( using: dependencies)
924+ } else {
925+ Permissions . remindCameraAccessRequirement ( using: dependencies)
926+ }
927+ } )
928+ }
929+ }
930+
877931 // MARK: - AVRoutePickerViewDelegate
878932
879- func routePickerViewWillBeginPresentingRoutes( _ routePickerView: AVRoutePickerView ) {
880-
881- }
933+ func routePickerViewWillBeginPresentingRoutes( _ routePickerView: AVRoutePickerView ) { }
882934
883- func routePickerViewDidEndPresentingRoutes( _ routePickerView: AVRoutePickerView ) {
884-
885- }
935+ func routePickerViewDidEndPresentingRoutes( _ routePickerView: AVRoutePickerView ) { }
886936}
0 commit comments