@@ -263,7 +263,7 @@ private final class CallVideoNode: ASDisplayNode {
263263 if withBackground {
264264 self . backgroundColor = . black
265265 }
266- UIView . transition ( with: self . videoTransformContainer. view, duration: 0.4 , options: [ . transitionFlipFromLeft, . curveEaseOut] , animations: {
266+ UIView . transition ( with: withBackground ? self . videoTransformContainer. view : self . view, duration: 0.4 , options: [ . transitionFlipFromLeft, . curveEaseOut] , animations: {
267267 UIView . performWithoutAnimation {
268268 self . updateIsBlurred ( isBlurred: true , light: true , animated: false )
269269 }
@@ -315,6 +315,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
315315 private var isRequestingVideo : Bool = false
316316 private var animateRequestedVideoOnce : Bool = false
317317
318+ private var displayedCameraConfirmation : Bool = false
318319 private var displayedCameraTooltip : Bool = false
319320
320321 private var expandedVideoNode : CallVideoNode ?
@@ -365,6 +366,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
365366 var present : ( ( ViewController ) -> Void ) ?
366367
367368 private var toastContent : CallControllerToastContent ?
369+ private var displayToastsAfterTimestamp : Double ?
370+
368371 private var buttonsMode : CallControllerButtonsMode ?
369372
370373 private var isUIHidden : Bool = false
@@ -460,7 +463,10 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
460463 }
461464
462465 self . buttonsNode. speaker = { [ weak self] in
463- self ? . beginAudioOuputSelection ? ( true )
466+ guard let strongSelf = self else {
467+ return
468+ }
469+ strongSelf. beginAudioOuputSelection ? ( strongSelf. hasVideoNodes)
464470 }
465471
466472 self . buttonsNode. acceptOrEnd = { [ weak self] in
@@ -491,6 +497,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
491497 case . active:
492498 if strongSelf. outgoingVideoNodeValue == nil {
493499 let proceed = {
500+ strongSelf. displayedCameraConfirmation = true
494501 switch callState. videoState {
495502 case . inactive:
496503 strongSelf. isRequestingVideo = true
@@ -501,9 +508,13 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
501508 strongSelf. call. requestVideo ( )
502509 }
503510
504- strongSelf . present ? ( textAlertController ( sharedContext : strongSelf. sharedContext , title : nil , text : strongSelf . presentationData . strings . Call_CameraConfirmationText , actions : [ TextAlertAction ( type : . genericAction , title : presentationData . strings . Common_Cancel , action : { } ) , TextAlertAction ( type : . defaultAction , title : strongSelf . presentationData . strings . Call_CameraConfirmationConfirm , action : {
511+ if strongSelf. displayedCameraConfirmation {
505512 proceed ( )
506- } ) ] ) )
513+ } else {
514+ strongSelf. present ? ( textAlertController ( sharedContext: strongSelf. sharedContext, title: nil , text: strongSelf. presentationData. strings. Call_CameraConfirmationText, actions: [ TextAlertAction ( type: . genericAction, title: presentationData. strings. Common_Cancel, action: { } ) , TextAlertAction ( type: . defaultAction, title: strongSelf. presentationData. strings. Call_CameraConfirmationConfirm, action: {
515+ proceed ( )
516+ } ) ] ) )
517+ }
507518 } else {
508519 strongSelf. call. disableVideo ( )
509520 }
@@ -517,8 +528,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
517528 return
518529 }
519530 strongSelf. disableActionsUntilTimestamp = CACurrentMediaTime ( ) + 1.0
520- if let outgoingVideoNode = strongSelf. outgoingVideoNodeValue, let ( layout , _ ) = strongSelf . validLayout {
521- outgoingVideoNode. flip ( withBackground: outgoingVideoNode. frame . width == layout . size . width )
531+ if let outgoingVideoNode = strongSelf. outgoingVideoNodeValue {
532+ outgoingVideoNode. flip ( withBackground: outgoingVideoNode ! == strongSelf . minimizedVideoNode )
522533 }
523534 strongSelf. call. switchVideoCamera ( )
524535 if let _ = strongSelf. outgoingVideoNodeValue {
@@ -924,30 +935,40 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
924935 }
925936 }
926937
927- var toastContent : CallControllerToastContent = [ ]
928- if callState. state. isOrWasActive {
929- if self . hasVideoNodes && [ . inactive, . paused] . contains ( callState. remoteVideoState) {
930- toastContent. insert ( . camera)
931- }
932- if case . muted = callState. remoteAudioState {
933- toastContent. insert ( . microphone)
938+ if case . terminating = callState. state {
939+ } else if case . terminated = callState. state {
940+ } else {
941+ var toastContent : CallControllerToastContent = [ ]
942+ if case . active = callState. state {
943+ if let displayToastsAfterTimestamp = self . displayToastsAfterTimestamp {
944+ if CACurrentMediaTime ( ) > displayToastsAfterTimestamp {
945+ if case . inactive = callState. remoteVideoState, self . hasVideoNodes {
946+ toastContent. insert ( . camera)
947+ }
948+ if case . muted = callState. remoteAudioState {
949+ toastContent. insert ( . microphone)
950+ }
951+ if case . low = callState. remoteBatteryLevel {
952+ toastContent. insert ( . battery)
953+ }
954+ }
955+ } else {
956+ self . displayToastsAfterTimestamp = CACurrentMediaTime ( ) + 2.0
957+ }
934958 }
935- if case . low = callState . remoteBatteryLevel {
936- toastContent. insert ( . battery )
959+ if self . isMuted , let ( availableOutputs , _ ) = self . audioOutputState , availableOutputs . count > 2 {
960+ toastContent. insert ( . mute )
937961 }
962+ self . toastContent = toastContent
938963 }
939- if self . isMuted, let ( availableOutputs, _) = self . audioOutputState, availableOutputs. count > 2 {
940- toastContent. insert ( . mute)
941- }
942- self . toastContent = toastContent
943964
944965 self . updateButtonsMode ( )
945966 self . updateDimVisibility ( )
946967
947968 if self . incomingVideoViewRequested && self . outgoingVideoViewRequested {
948969 self . displayedCameraTooltip = true
949970 }
950- if self . incomingVideoViewRequested && !self . outgoingVideoViewRequested && !self . displayedCameraTooltip && toastContent. isEmpty {
971+ if self . incomingVideoViewRequested && !self . outgoingVideoViewRequested && !self . displayedCameraTooltip && ( self . toastContent? . isEmpty ?? true ) {
951972 self . displayedCameraTooltip = true
952973 Queue . mainQueue ( ) . after ( 2.0 ) {
953974 self . displayCameraTooltip ( )
@@ -1098,21 +1119,19 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
10981119 }
10991120
11001121 private func calculatePreviewVideoRect( layout: ContainerViewLayout , navigationHeight: CGFloat ) -> CGRect {
1101- var uiDisplayTransition : CGFloat = self . isUIHidden ? 0.0 : 1.0
1102- uiDisplayTransition *= 1.0 - self . pictureInPictureTransitionFraction
1103-
11041122 let buttonsHeight : CGFloat = self . buttonsNode. bounds. height
11051123 let toastHeight : CGFloat = self . toastNode. bounds. height
1124+ let toastInset = ( toastHeight > 0.0 ? toastHeight + 22.0 : 0.0 )
11061125
11071126 var fullInsets = layout. insets ( options: . statusBar)
1108-
1127+
11091128 var cleanInsets = fullInsets
1110- cleanInsets. bottom = layout. intrinsicInsets. bottom
1129+ cleanInsets. bottom = max ( layout. intrinsicInsets. bottom, 20.0 ) + toastInset
11111130 cleanInsets. left = 20.0
11121131 cleanInsets. right = 20.0
11131132
11141133 fullInsets. top += 44.0 + 8.0
1115- fullInsets. bottom = buttonsHeight + toastHeight + 27.0
1134+ fullInsets. bottom = buttonsHeight + 22.0 + toastInset
11161135 fullInsets. left = 20.0
11171136 fullInsets. right = 20.0
11181137
@@ -1179,8 +1198,17 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
11791198 func containerLayoutUpdated( _ layout: ContainerViewLayout , navigationBarHeight: CGFloat , transition: ContainedViewLayoutTransition ) {
11801199 self . validLayout = ( layout, navigationBarHeight)
11811200
1182- var uiDisplayTransition : CGFloat = self . isUIHidden ? 0.0 : 1.0
1183- uiDisplayTransition *= 1.0 - self . pictureInPictureTransitionFraction
1201+ var isUIHidden = self . isUIHidden
1202+ switch self . callState? . state {
1203+ case . terminated, . terminating:
1204+ isUIHidden = false
1205+ default :
1206+ break
1207+ }
1208+
1209+ var uiDisplayTransition : CGFloat = isUIHidden ? 0.0 : 1.0
1210+ let pipTransitionAlpha : CGFloat = 1.0 - self . pictureInPictureTransitionFraction
1211+ uiDisplayTransition *= pipTransitionAlpha
11841212
11851213 let previousVideoButtonFrame = self . buttonsNode. videoButtonFrame ( ) . flatMap { frame -> CGRect in
11861214 return self . buttonsNode. view. convert ( frame, to: self . view)
@@ -1193,15 +1221,22 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
11931221 buttonsHeight = 0.0
11941222 }
11951223 let defaultButtonsOriginY = layout. size. height - buttonsHeight
1196- let buttonsOriginY = interpolate ( from: layout. size. height + 10.0 , to: defaultButtonsOriginY, value: uiDisplayTransition)
1224+ let buttonsCollapsedOriginY = self . pictureInPictureTransitionFraction > 0.0 ? layout. size. height + 30.0 : layout. size. height + 10.0
1225+ let buttonsOriginY = interpolate ( from: buttonsCollapsedOriginY, to: defaultButtonsOriginY, value: uiDisplayTransition)
11971226
11981227 let toastHeight = self . toastNode. updateLayout ( strings: self . presentationData. strings, content: self . toastContent, constrainedWidth: layout. size. width, bottomInset: layout. intrinsicInsets. bottom + buttonsHeight, transition: transition)
11991228
1229+ let toastSpacing : CGFloat = 22.0
1230+ let toastCollapsedOriginY = self . pictureInPictureTransitionFraction > 0.0 ? layout. size. height : layout. size. height - max( layout. intrinsicInsets. bottom, 20.0 ) - toastHeight
1231+ let toastOriginY = interpolate ( from: toastCollapsedOriginY, to: defaultButtonsOriginY - toastSpacing - toastHeight, value: uiDisplayTransition)
1232+
12001233 var overlayAlpha : CGFloat = uiDisplayTransition
1234+ var toastAlpha : CGFloat = pipTransitionAlpha
12011235
12021236 switch self . callState? . state {
12031237 case . terminated, . terminating:
12041238 overlayAlpha *= 0.5
1239+ toastAlpha *= 0.5
12051240 default :
12061241 break
12071242 }
@@ -1229,15 +1264,17 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
12291264 apply ( )
12301265
12311266 let navigationOffset : CGFloat = max ( 20.0 , layout. safeInsets. top)
1267+ let topOriginY = interpolate ( from: - 20.0 , to: navigationOffset, value: uiDisplayTransition)
12321268
12331269 let backSize = self . backButtonNode. measure ( CGSize ( width: 320.0 , height: 100.0 ) )
12341270 if let image = self . backButtonArrowNode. image {
1235- transition. updateFrame ( node: self . backButtonArrowNode, frame: CGRect ( origin: CGPoint ( x: 10.0 , y: navigationOffset + 11.0 ) , size: image. size) )
1271+ transition. updateFrame ( node: self . backButtonArrowNode, frame: CGRect ( origin: CGPoint ( x: 10.0 , y: topOriginY + 11.0 ) , size: image. size) )
12361272 }
1237- transition. updateFrame ( node: self . backButtonNode, frame: CGRect ( origin: CGPoint ( x: 29.0 , y: navigationOffset + 11.0 ) , size: backSize) )
1273+ transition. updateFrame ( node: self . backButtonNode, frame: CGRect ( origin: CGPoint ( x: 29.0 , y: topOriginY + 11.0 ) , size: backSize) )
12381274
12391275 transition. updateAlpha ( node: self . backButtonArrowNode, alpha: overlayAlpha)
12401276 transition. updateAlpha ( node: self . backButtonNode, alpha: overlayAlpha)
1277+ transition. updateAlpha ( node: self . toastNode, alpha: toastAlpha)
12411278
12421279 var statusOffset : CGFloat
12431280 if layout. metrics. widthClass == . regular && layout. metrics. heightClass == . regular {
@@ -1265,7 +1302,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
12651302 let videoPausedSize = self . videoPausedNode. updateLayout ( CGSize ( width: layout. size. width - 16.0 , height: 100.0 ) )
12661303 transition. updateFrame ( node: self . videoPausedNode, frame: CGRect ( origin: CGPoint ( x: floor ( ( layout. size. width - videoPausedSize. width) / 2.0 ) , y: floor ( ( layout. size. height - videoPausedSize. height) / 2.0 ) ) , size: videoPausedSize) )
12671304
1268- transition. updateFrame ( node: self . toastNode, frame: CGRect ( origin: CGPoint ( x: 0.0 , y: buttonsOriginY - toastHeight ) , size: CGSize ( width: layout. size. width, height: toastHeight) ) )
1305+ transition. updateFrame ( node: self . toastNode, frame: CGRect ( origin: CGPoint ( x: 0.0 , y: toastOriginY ) , size: CGSize ( width: layout. size. width, height: toastHeight) ) )
12691306 transition. updateFrame ( node: self . buttonsNode, frame: CGRect ( origin: CGPoint ( x: 0.0 , y: buttonsOriginY) , size: CGSize ( width: layout. size. width, height: buttonsHeight) ) )
12701307 transition. updateAlpha ( node: self . buttonsNode, alpha: overlayAlpha)
12711308
@@ -1362,7 +1399,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
13621399 }
13631400
13641401 let keyTextSize = self . keyButtonNode. frame. size
1365- transition. updateFrame ( node: self . keyButtonNode, frame: CGRect ( origin: CGPoint ( x: layout. size. width - keyTextSize. width - 8.0 , y: navigationOffset + 8.0 ) , size: keyTextSize) )
1402+ transition. updateFrame ( node: self . keyButtonNode, frame: CGRect ( origin: CGPoint ( x: layout. size. width - keyTextSize. width - 8.0 , y: topOriginY + 8.0 ) , size: keyTextSize) )
13661403 transition. updateAlpha ( node: self . keyButtonNode, alpha: overlayAlpha)
13671404
13681405 if let debugNode = self . debugNode {
@@ -1719,7 +1756,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
17191756 case . collapsing:
17201757 self . pictureInPictureGestureState = . none
17211758 let velocity = recognizer. velocity ( in: self . view) . y
1722- if abs ( velocity) < 100.0 {
1759+ if abs ( velocity) < 100.0 && self . pictureInPictureTransitionFraction < 0.5 {
17231760 if let ( layout, navigationHeight) = self . validLayout {
17241761 self . pictureInPictureTransitionFraction = 0.0
17251762
0 commit comments