Video Chat Improvements

This commit is contained in:
Ilya Laktyushin 2021-05-26 14:49:22 +04:00
parent c8b05c1fc3
commit da0f47b655
4 changed files with 82 additions and 24 deletions

View File

@ -55,7 +55,7 @@ class VoiceChatActionItem: ListViewItem {
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
async {
let node = VoiceChatActionItemNode()
let (layout, apply) = node.asyncLayout()(self, params, false, nextItem == nil)
let (layout, apply) = node.asyncLayout()(self, params, previousItem == nil || previousItem is VoiceChatTilesGridItem, nextItem == nil)
node.contentSize = layout.contentSize
node.insets = layout.insets
@ -74,7 +74,7 @@ class VoiceChatActionItem: ListViewItem {
let makeLayout = nodeValue.asyncLayout()
async {
let (layout, apply) = makeLayout(self, params, false, nextItem == nil)
let (layout, apply) = makeLayout(self, params, previousItem == nil || previousItem is VoiceChatTilesGridItem, nextItem == nil)
Queue.mainQueue().async {
completion(layout, { _ in
apply()
@ -95,6 +95,7 @@ class VoiceChatActionItem: ListViewItem {
class VoiceChatActionItemNode: ListViewItemNode {
private let topStripeNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode
private let highlightContainerNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
private let iconNode: ASImageNode
@ -121,13 +122,17 @@ class VoiceChatActionItemNode: ListViewItemNode {
self.iconNode.displayWithoutProcessing = true
self.iconNode.displaysAsynchronously = false
self.highlightContainerNode = ASDisplayNode()
self.highlightContainerNode.clipsToBounds = true
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
self.activateArea = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false)
self.highlightContainerNode.addSubnode(self.highlightedBackgroundNode)
self.addSubnode(self.iconNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.activateArea)
@ -138,11 +143,19 @@ class VoiceChatActionItemNode: ListViewItemNode {
}
}
func asyncLayout() -> (_ item: VoiceChatActionItem, _ params: ListViewItemLayoutParams, _ firstWithHeader: Bool, _ last: Bool) -> (ListViewItemNodeLayout, () -> Void) {
override func didLoad() {
super.didLoad()
if #available(iOS 13.0, *) {
self.highlightContainerNode.layer.cornerCurve = .continuous
}
}
func asyncLayout() -> (_ item: VoiceChatActionItem, _ params: ListViewItemLayoutParams, _ first: Bool, _ last: Bool) -> (ListViewItemNodeLayout, () -> Void) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let currentItem = self.item
return { item, params, firstWithHeader, last in
return { item, params, first, last in
var updatedTheme: PresentationTheme?
var updatedContent = false
@ -165,7 +178,7 @@ class VoiceChatActionItemNode: ListViewItemNode {
let contentHeight: CGFloat = 12.0 * 2.0 + titleLayout.size.height
let contentSize = CGSize(width: params.width, height: contentHeight)
let insets = UIEdgeInsets(top: firstWithHeader ? 29.0 : 0.0, left: 0.0, bottom: 0.0, right: 0.0)
let insets = UIEdgeInsets()
let separatorHeight = UIScreenPixel
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
@ -214,6 +227,10 @@ class VoiceChatActionItemNode: ListViewItemNode {
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: titleOffset + 1.0, y: floor((contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size)
strongSelf.highlightContainerNode.frame = CGRect(origin: CGPoint(x: params.leftInset, y: -UIScreenPixel), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height + UIScreenPixel + UIScreenPixel + 11.0))
strongSelf.highlightContainerNode.cornerRadius = first ? 11.0 : 0.0
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + UIScreenPixel + UIScreenPixel))
}
})
@ -224,8 +241,8 @@ class VoiceChatActionItemNode: ListViewItemNode {
super.setHighlighted(highlighted, at: point, animated: animated)
if highlighted {
self.highlightedBackgroundNode.alpha = 1.0
if self.highlightedBackgroundNode.supernode == nil {
self.highlightContainerNode.alpha = 1.0
if self.highlightContainerNode.supernode == nil {
var anchorNode: ASDisplayNode?
if self.bottomStripeNode.supernode != nil {
anchorNode = self.bottomStripeNode
@ -233,24 +250,24 @@ class VoiceChatActionItemNode: ListViewItemNode {
anchorNode = self.topStripeNode
}
if let anchorNode = anchorNode {
self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode)
self.insertSubnode(self.highlightContainerNode, aboveSubnode: anchorNode)
} else {
self.addSubnode(self.highlightedBackgroundNode)
self.addSubnode(self.highlightContainerNode)
}
}
} else {
if self.highlightedBackgroundNode.supernode != nil {
if self.highlightContainerNode.supernode != nil {
if animated {
self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
self.highlightContainerNode.layer.animateAlpha(from: self.highlightContainerNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in
if let strongSelf = self {
if completed {
strongSelf.highlightedBackgroundNode.removeFromSupernode()
strongSelf.highlightContainerNode.removeFromSupernode()
}
}
})
self.highlightedBackgroundNode.alpha = 0.0
self.highlightContainerNode.alpha = 0.0
} else {
self.highlightedBackgroundNode.removeFromSupernode()
self.highlightContainerNode.removeFromSupernode()
}
}
}

View File

@ -96,8 +96,8 @@ struct VoiceChatPeerEntry: Identifiable {
var peer: Peer
var about: String?
var isMyPeer: Bool
var videoEndpointId: String?
var presentationEndpointId: String?
var _videoEndpointId: String?
var _presentationEndpointId: String?
var state: State
var muteState: GroupCallParticipantsContext.Participant.MuteState?
var canManageCall: Bool
@ -107,6 +107,22 @@ struct VoiceChatPeerEntry: Identifiable {
var active: Bool
var isLandscape: Bool
var videoEndpointId: String? {
if let muteState = self.muteState, !muteState.canUnmute || muteState.mutedByYou {
return nil
} else {
return self._videoEndpointId
}
}
var presentationEndpointId: String? {
if let muteState = self.muteState, !muteState.canUnmute || muteState.mutedByYou {
return nil
} else {
return self._presentationEndpointId
}
}
var effectiveVideoEndpointId: String? {
return self.presentationEndpointId ?? self.videoEndpointId
}
@ -129,8 +145,8 @@ struct VoiceChatPeerEntry: Identifiable {
self.peer = peer
self.about = about
self.isMyPeer = isMyPeer
self.videoEndpointId = videoEndpointId
self.presentationEndpointId = presentationEndpointId
self._videoEndpointId = videoEndpointId
self._presentationEndpointId = presentationEndpointId
self.state = state
self.muteState = muteState
self.canManageCall = canManageCall
@ -155,10 +171,10 @@ struct VoiceChatPeerEntry: Identifiable {
if lhs.isMyPeer != rhs.isMyPeer {
return false
}
if lhs.videoEndpointId != rhs.videoEndpointId {
if lhs._videoEndpointId != rhs._videoEndpointId {
return false
}
if lhs.presentationEndpointId != rhs.presentationEndpointId {
if lhs._presentationEndpointId != rhs._presentationEndpointId {
return false
}
if lhs.state != rhs.state {
@ -5587,6 +5603,9 @@ public final class VoiceChatController: ViewController {
})
self.transitionMaskTopFillLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15)
if !transitionOffset.isZero {
self.transitionMaskBottomFillLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: transition)

View File

@ -191,7 +191,9 @@ final class VoiceChatTileItemNode: ASDisplayNode {
gesture.cancel()
return
}
contextAction(strongSelf.contextSourceNode, gesture)
if item.videoReady {
contextAction(strongSelf.contextSourceNode, gesture)
}
}
self.contextSourceNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtracted, transition in
guard let strongSelf = self, let _ = strongSelf.item else {
@ -275,6 +277,8 @@ final class VoiceChatTileItemNode: ASDisplayNode {
let previousItem = self.item
self.item = item
self.containerNode.isGestureEnabled = item.videoReady
if !item.videoReady {
let shimmerNode: VoiceChatTileShimmeringNode
if let current = self.shimmerNode {

View File

@ -156,6 +156,10 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
presentationJsonDescription = data
}
}
if muteState?.canUnmute == false {
videoJsonDescription = nil
presentationJsonDescription = nil
}
parsedParticipants.append(GroupCallParticipantsContext.Participant(
peer: peer,
ssrc: ssrc,
@ -481,6 +485,10 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
presentationJsonDescription = data
}
}
if muteState?.canUnmute == false {
videoJsonDescription = nil
presentationJsonDescription = nil
}
parsedParticipants.append(GroupCallParticipantsContext.Participant(
peer: peer,
ssrc: ssrc,
@ -741,6 +749,10 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal
presentationJsonDescription = data
}
}
if muteState?.canUnmute == false {
videoJsonDescription = nil
presentationJsonDescription = nil
}
if !state.participants.contains(where: { $0.peer.id == peer.id }) {
state.participants.append(GroupCallParticipantsContext.Participant(
peer: peer,
@ -2150,7 +2162,10 @@ extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate {
presentationJsonDescription = data
}
}
if muteState?.canUnmute == false {
videoJsonDescription = nil
presentationJsonDescription = nil
}
self.init(
peerId: peerId,
ssrc: ssrc,
@ -2213,7 +2228,10 @@ extension GroupCallParticipantsContext.Update.StateUpdate {
presentationJsonDescription = data
}
}
if muteState?.canUnmute == false {
videoJsonDescription = nil
presentationJsonDescription = nil
}
participantUpdates.append(GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(
peerId: peerId,
ssrc: ssrc,