[WIP] Conference

This commit is contained in:
Isaac
2025-01-21 11:04:37 +04:00
parent 550fd89558
commit a4717b7906
47 changed files with 4439 additions and 816 deletions

View File

@@ -199,6 +199,9 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
private var isUpdating: Bool = false
private var isAnimatedOutToGroupCall: Bool = false
private var animateOutToGroupCallCompletion: (() -> Void)?
private var canAnimateAudioLevel: Bool = false
private var displayEmojiTooltip: Bool = false
private var isEmojiKeyExpanded: Bool = false
@@ -233,8 +236,6 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
private var pipVideoCallViewController: UIViewController?
private var pipController: AVPictureInPictureController?
private var snowEffectView: SnowEffectView?
public override init(frame: CGRect) {
self.overlayContentsView = UIView()
self.overlayContentsView.isUserInteractionEnabled = false
@@ -489,6 +490,32 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
}
public func animateOutToGroupChat(completion: @escaping () -> Void) {
self.isAnimatedOutToGroupCall = true
self.animateOutToGroupCallCompletion = completion
self.update(transition: .easeInOut(duration: 0.25))
}
public func takeIncomingVideoLayer() -> (CALayer, VideoSource.Output?)? {
var remoteVideoContainerKey: VideoContainerView.Key?
if self.swapLocalAndRemoteVideo {
if let _ = self.activeRemoteVideoSource {
remoteVideoContainerKey = .foreground
}
} else {
if let _ = self.activeRemoteVideoSource {
remoteVideoContainerKey = .background
}
}
if let remoteVideoContainerKey, let videoContainerView = self.videoContainerViews.first(where: { $0.key == remoteVideoContainerKey }) {
videoContainerView.videoContainerLayerTaken = true
return (videoContainerView.videoContainerLayer, videoContainerView.currentVideoOutput)
}
return nil
}
public func update(size: CGSize, insets: UIEdgeInsets, interfaceOrientation: UIInterfaceOrientation, screenCornerRadius: CGFloat, state: State, transition: ComponentTransition) {
let params = Params(size: size, insets: insets, interfaceOrientation: interfaceOrientation, screenCornerRadius: screenCornerRadius, state: state)
if self.params == params {
@@ -717,6 +744,16 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
self.backgroundLayer.update(stateIndex: backgroundStateIndex, isEnergySavingEnabled: params.state.isEnergySavingEnabled, transition: transition)
genericAlphaTransition.setAlpha(layer: self.backgroundLayer, alpha: self.isAnimatedOutToGroupCall ? 0.0 : 1.0, completion: { [weak self] _ in
guard let self else {
return
}
if let animateOutToGroupCallCompletion = self.animateOutToGroupCallCompletion {
self.animateOutToGroupCallCompletion = nil
animateOutToGroupCallCompletion()
}
})
transition.setFrame(view: self.buttonGroupView, frame: CGRect(origin: CGPoint(), size: params.size))
var isVideoButtonEnabled = false
@@ -793,7 +830,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}*/
let displayClose = false
let contentBottomInset = self.buttonGroupView.update(size: params.size, insets: params.insets, minWidth: wideContentWidth, controlsHidden: currentAreControlsHidden, displayClose: displayClose, strings: params.state.strings, buttons: buttons, notices: notices, transition: transition)
let contentBottomInset = self.buttonGroupView.update(size: params.size, insets: params.insets, minWidth: wideContentWidth, controlsHidden: currentAreControlsHidden, displayClose: displayClose, strings: params.state.strings, buttons: buttons, notices: notices, isAnimatedOutToGroupCall: self.isAnimatedOutToGroupCall, transition: transition)
var expandedEmojiKeyRect: CGRect?
if self.isEmojiKeyExpanded {
@@ -836,7 +873,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
emojiExpandedInfoTransition.setPosition(view: emojiExpandedInfoView, position: CGPoint(x: emojiExpandedInfoFrame.minX + emojiExpandedInfoView.layer.anchorPoint.x * emojiExpandedInfoFrame.width, y: emojiExpandedInfoFrame.minY + emojiExpandedInfoView.layer.anchorPoint.y * emojiExpandedInfoFrame.height))
emojiExpandedInfoTransition.setBounds(view: emojiExpandedInfoView, bounds: CGRect(origin: CGPoint(), size: emojiExpandedInfoFrame.size))
alphaTransition.setAlpha(view: emojiExpandedInfoView, alpha: 1.0)
alphaTransition.setAlpha(view: emojiExpandedInfoView, alpha: self.isAnimatedOutToGroupCall ? 0.0 : 1.0)
transition.setScale(view: emojiExpandedInfoView, scale: 1.0)
expandedEmojiKeyRect = emojiExpandedInfoFrame
@@ -868,7 +905,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
let backButtonFrame = CGRect(origin: CGPoint(x: params.insets.left + 10.0, y: backButtonY), size: backButtonSize)
transition.setFrame(view: self.backButtonView, frame: backButtonFrame)
transition.setAlpha(view: self.backButtonView, alpha: currentAreControlsHidden ? 0.0 : 1.0)
genericAlphaTransition.setAlpha(view: self.backButtonView, alpha: (currentAreControlsHidden || self.isAnimatedOutToGroupCall) ? 0.0 : 1.0)
if case let .active(activeState) = params.state.lifecycleState {
let emojiView: KeyEmojiView
@@ -886,9 +923,13 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
return
}
if !self.isEmojiKeyExpanded {
#if DEBUG
self.conferenceAddParticipant?()
#else
self.isEmojiKeyExpanded = true
self.displayEmojiTooltip = false
self.update(transition: .spring(duration: 0.4))
#endif
}
}
}
@@ -915,6 +956,9 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
emojiTransition.setPosition(view: emojiView, position: emojiViewFrame.center)
}
emojiTransition.setBounds(view: emojiView, bounds: CGRect(origin: CGPoint(), size: emojiViewFrame.size))
if self.isAnimatedOutToGroupCall {
emojiAlphaTransition.setAlpha(view: emojiView, alpha: (currentAreControlsHidden || self.isAnimatedOutToGroupCall) ? 0.0 : 1.0)
}
if let emojiTooltipView = self.emojiTooltipView {
self.emojiTooltipView = nil
@@ -940,7 +984,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
emojiTransition.setPosition(view: emojiView, position: emojiViewFrame.center)
}
emojiTransition.setBounds(view: emojiView, bounds: CGRect(origin: CGPoint(), size: emojiViewFrame.size))
emojiAlphaTransition.setAlpha(view: emojiView, alpha: currentAreControlsHidden ? 0.0 : 1.0)
emojiAlphaTransition.setAlpha(view: emojiView, alpha: (currentAreControlsHidden || self.isAnimatedOutToGroupCall) ? 0.0 : 1.0)
if self.displayEmojiTooltip {
let emojiTooltipView: EmojiTooltipView
@@ -1261,6 +1305,9 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
}
genericAlphaTransition.setAlpha(layer: self.avatarTransformLayer, alpha: self.isAnimatedOutToGroupCall ? 0.0 : 1.0)
genericAlphaTransition.setAlpha(layer: self.blobTransformLayer, alpha: self.isAnimatedOutToGroupCall ? 0.0 : 1.0)
let titleSize = self.titleView.update(
string: titleString,
fontSize: !havePrimaryVideo ? 28.0 : 17.0,
@@ -1335,7 +1382,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
size: titleSize
)
transition.setFrame(view: self.titleView, frame: titleFrame)
genericAlphaTransition.setAlpha(view: self.titleView, alpha: currentAreControlsHidden ? 0.0 : 1.0)
genericAlphaTransition.setAlpha(view: self.titleView, alpha: (currentAreControlsHidden || self.isAnimatedOutToGroupCall) ? 0.0 : 1.0)
let statusFrame = CGRect(
origin: CGPoint(
@@ -1354,7 +1401,7 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
} else {
transition.setFrame(view: self.statusView, frame: statusFrame)
genericAlphaTransition.setAlpha(view: self.statusView, alpha: currentAreControlsHidden ? 0.0 : 1.0)
genericAlphaTransition.setAlpha(view: self.statusView, alpha: (currentAreControlsHidden || self.isAnimatedOutToGroupCall) ? 0.0 : 1.0)
}
if case let .active(activeState) = params.state.lifecycleState, activeState.signalInfo.quality <= 0.2, !self.isEmojiKeyExpanded, (!self.displayEmojiTooltip || !havePrimaryVideo) {
@@ -1380,11 +1427,11 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
ComponentTransition.immediate.setScale(view: weakSignalView, scale: 0.001)
weakSignalView.alpha = 0.0
transition.setScaleWithSpring(view: weakSignalView, scale: 1.0)
transition.setAlpha(view: weakSignalView, alpha: 1.0)
}
} else {
transition.setFrame(view: weakSignalView, frame: weakSignalFrame)
}
transition.setAlpha(view: weakSignalView, alpha: self.isAnimatedOutToGroupCall ? 0.0 : 1.0)
} else {
if let weakSignalView = self.weakSignalView {
self.weakSignalView = nil
@@ -1396,55 +1443,3 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
}
}
}
final class SnowEffectView: UIView {
private let particlesLayer: CAEmitterLayer
override init(frame: CGRect) {
let particlesLayer = CAEmitterLayer()
self.particlesLayer = particlesLayer
self.particlesLayer.backgroundColor = nil
self.particlesLayer.isOpaque = false
particlesLayer.emitterShape = .circle
particlesLayer.emitterMode = .surface
particlesLayer.renderMode = .oldestLast
let image1 = UIImage(named: "Call/Snow")?.cgImage
let cell1 = CAEmitterCell()
cell1.contents = image1
cell1.name = "Snow"
cell1.birthRate = 92.0
cell1.lifetime = 20.0
cell1.velocity = 59.0
cell1.velocityRange = -15.0
cell1.xAcceleration = 5.0
cell1.yAcceleration = 40.0
cell1.emissionRange = 90.0 * (.pi / 180.0)
cell1.spin = -28.6 * (.pi / 180.0)
cell1.spinRange = 57.2 * (.pi / 180.0)
cell1.scale = 0.06
cell1.scaleRange = 0.3
cell1.color = UIColor(red: 255.0/255.0, green: 255.0/255.0, blue: 255.0/255.0, alpha: 1.0).cgColor
particlesLayer.emitterCells = [cell1]
super.init(frame: frame)
self.layer.addSublayer(particlesLayer)
self.clipsToBounds = true
self.backgroundColor = nil
self.isOpaque = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(size: CGSize) {
self.particlesLayer.frame = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
self.particlesLayer.emitterSize = CGSize(width: size.width * 3.0, height: size.height * 2.0)
self.particlesLayer.emitterPosition = CGPoint(x: size.width * 0.5, y: -325.0)
}
}