Merge commit '7e769a725c3c039977c7f4d9cc89bfc2ce714a1e'

This commit is contained in:
Ali 2020-12-05 23:45:39 +00:00
commit c59c45c694
8 changed files with 202 additions and 59 deletions

View File

@ -190,14 +190,14 @@ public struct PresentationGroupCallState: Equatable {
}
public struct PresentationGroupCallSummaryState: Equatable {
public var info: GroupCallInfo
public var info: GroupCallInfo?
public var participantCount: Int
public var callState: PresentationGroupCallState
public var topParticipants: [GroupCallParticipantsContext.Participant]
public var activeSpeakers: Set<PeerId>
public init(
info: GroupCallInfo,
info: GroupCallInfo?,
participantCount: Int,
callState: PresentationGroupCallState,
topParticipants: [GroupCallParticipantsContext.Participant],

View File

@ -899,12 +899,17 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
let itemInBounds = bounds.intersects(item.frame)
var absoluteRect = item.frame
if let itemNode = self.itemNodes[item.index] {
if itemNode.frame != item.frame {
itemNode.frame = item.frame
}
itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads && itemInBounds)
itemNode.updateAbsoluteRect(item.frame, within: bounds.size)
if let supernode = self.supernode {
absoluteRect = supernode.convert(itemNode.bounds, from: itemNode)
}
itemNode.updateAbsoluteRect(absoluteRect, within: bounds.size)
} else {
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout, synchronousLoad: synchronousLoads && itemInBounds)
itemNode.frame = item.frame
@ -912,7 +917,11 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
addedNodes = true
itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads)
self.setupNode?(itemNode)
itemNode.updateAbsoluteRect(item.frame, within: bounds.size)
if let supernode = self.supernode {
absoluteRect = supernode.convert(itemNode.bounds, from: itemNode)
}
itemNode.updateAbsoluteRect(absoluteRect, within: bounds.size)
}
}

View File

@ -9,7 +9,6 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
private let rightLine: ASDisplayNode
private var isCurrentlyInHierarchy = true
private var shouldBeAnimating = false
var color: UIColor = UIColor(rgb: 0xffffff) {
didSet {
@ -64,10 +63,9 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
}
private func updateAnimation() {
let shouldBeAnimating = self.isCurrentlyInHierarchy
if shouldBeAnimating != self.shouldBeAnimating {
self.shouldBeAnimating = shouldBeAnimating
if shouldBeAnimating {
if self.isCurrentlyInHierarchy {
if let _ = self.leftLine.layer.animation(forKey: "animation") {
} else {
let timingFunctions: [CAMediaTimingFunction] = (0 ..< 5).map { _ in CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) }
let leftAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
@ -75,6 +73,7 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
leftAnimation.values = [NSNumber(value: 10.0), NSNumber(value: 4.0), NSNumber(value: 8.0), NSNumber(value: 4.0), NSNumber(value: 10.0)]
leftAnimation.repeatCount = Float.infinity
leftAnimation.duration = 2.2
leftAnimation.beginTime = 1.0
self.leftLine.layer.add(leftAnimation, forKey: "animation")
let centerAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
@ -82,6 +81,7 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
centerAnimation.values = [NSNumber(value: 6.0), NSNumber(value: 10.0), NSNumber(value: 4.0), NSNumber(value: 12.0), NSNumber(value: 6.0)]
centerAnimation.repeatCount = Float.infinity
centerAnimation.duration = 2.2
centerAnimation.beginTime = 1.0
self.centerLine.layer.add(centerAnimation, forKey: "animation")
let rightAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
@ -89,12 +89,13 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
rightAnimation.values = [NSNumber(value: 10.0), NSNumber(value: 4.0), NSNumber(value: 8.0), NSNumber(value: 4.0), NSNumber(value: 10.0)]
rightAnimation.repeatCount = Float.infinity
rightAnimation.duration = 2.2
rightAnimation.beginTime = 1.0
self.rightLine.layer.add(rightAnimation, forKey: "animation")
} else {
self.leftLine.layer.removeAnimation(forKey: "animation")
self.centerLine.layer.removeAnimation(forKey: "animation")
self.rightLine.layer.removeAnimation(forKey: "animation")
}
} else {
self.leftLine.layer.removeAnimation(forKey: "animation")
self.centerLine.layer.removeAnimation(forKey: "animation")
self.rightLine.layer.removeAnimation(forKey: "animation")
}
}
}
@ -124,15 +125,14 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
}
public func setImage(_ image: UIImage?, color: UIColor?, transition: ContainedViewLayoutTransition) {
if case let .animated(duration, curve) = transition {
if let snapshotLayer = self.iconNode.layer.snapshotContentTree() {
snapshotLayer.frame = self.iconNode.frame
self.iconNode.layer.insertSublayer(snapshotLayer, at: 0)
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
snapshotLayer?.removeFromSuperlayer()
})
}
if case let .animated(duration, curve) = transition, !self.iconNode.isHidden {
let snapshotLayer = CALayer()
snapshotLayer.contents = self.iconNode.layer.contents
snapshotLayer.frame = self.iconNode.bounds
self.iconNode.layer.insertSublayer(snapshotLayer, at: 0)
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
snapshotLayer?.removeFromSuperlayer()
})
}
self.iconNode.image = image
if let color = color {
@ -147,7 +147,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
if let strongSelf = self {
strongSelf.iconNode.frame = CGRect(x: 0.0, y: 0.0, width: size, height: size)
if isVoiceChat {
if online && isVoiceChat {
if let _ = strongSelf.animationNode {
} else {
let animationNode = VoiceChatIndicatorNode()
@ -166,7 +166,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
if let strongSelf = self, finished {
strongSelf.iconNode.isHidden = !online
if let animationNode = strongSelf.animationNode, !isVoiceChat {
if let animationNode = strongSelf.animationNode, !online {
animationNode.removeFromSupernode()
}
}
@ -174,7 +174,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
} else {
strongSelf.iconNode.isHidden = !online
if let animationNode = strongSelf.animationNode, !isVoiceChat {
if let animationNode = strongSelf.animationNode, !online {
animationNode.removeFromSupernode()
}
}

View File

@ -162,6 +162,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
private var currentCallState: PresentationCallState?
private var currentGroupCallState: PresentationGroupCallSummaryState?
private var currentIsMuted = true
private var currentIsConnected = true
public override init() {
self.backgroundNode = CallStatusBarBackgroundNode()
@ -224,15 +225,24 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
self.nameDisplayOrder = presentationData.nameDisplayOrder
self.stateDisposable.set(
(combineLatest(
account.postbox.loadedPeerWithId(call.peerId),
account.postbox.peerView(id: call.peerId),
call.summaryState,
call.isMuted
)
|> deliverOnMainQueue).start(next: { [weak self] peer, state, isMuted in
|> deliverOnMainQueue).start(next: { [weak self] view, state, isMuted in
if let strongSelf = self {
strongSelf.currentPeer = peer
strongSelf.currentPeer = view.peers[view.peerId]
strongSelf.currentGroupCallState = state
strongSelf.currentIsMuted = isMuted
let currentIsConnected: Bool
if let state = state, case .connected = state.callState.networkState {
currentIsConnected = true
} else {
currentIsConnected = false
}
strongSelf.currentIsConnected = currentIsConnected
strongSelf.update()
}
}))
@ -291,7 +301,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
self.titleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing, y: verticalOrigin + floor((contentHeight - titleSize.height) / 2.0)), size: titleSize)
self.subtitleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize)
self.backgroundNode.speaking = !self.currentIsMuted
self.backgroundNode.speaking = self.currentIsConnected && !self.currentIsMuted
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 18.0))
}
}

View File

@ -574,14 +574,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.statePromise.get()
)
|> map { infoState, participantsState, callState -> PresentationGroupCallSummaryState? in
guard let infoState = infoState else {
return nil
}
guard let participantsState = participantsState else {
return nil
}
return PresentationGroupCallSummaryState(
info: infoState.info,
info: infoState?.info,
participantCount: participantsState.participantCount,
callState: callState,
topParticipants: participantsState.topParticipants,

View File

@ -338,6 +338,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.maskBlobView = VoiceBlobView(frame: CGRect(origin: CGPoint(x: (areaSize.width - blobSize.width) / 2.0, y: (areaSize.height - blobSize.height) / 2.0), size: blobSize), maxLevel: 2.0, mediumBlobRange: (0.69, 0.87), bigBlobRange: (0.71, 1.0))
self.maskBlobView.setColor(white)
self.maskBlobView.isHidden = true
var updateInHierarchy: ((Bool) -> Void)?
self.hierarchyTrackingNode = HierarchyTrackingNode({ value in
@ -404,11 +405,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.foregroundView.mask = self.maskView
self.foregroundView.layer.addSublayer(self.foregroundGradientLayer)
self.maskView.layer.addSublayer(self.maskGradientLayer)
self.maskView.layer.addSublayer(self.maskProgressLayer)
self.maskView.addSubview(self.maskBlobView)
self.maskView.layer.addSublayer(self.maskCircleLayer)
@ -424,10 +423,10 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
} else {
let previousValue = self.foregroundGradientLayer.startPoint
let newValue: CGPoint
if self.maskBlobView.presentationAudioLevel > 0.1 {
newValue = CGPoint(x: CGFloat.random(in: 0.9 ..< 1.0), y: CGFloat.random(in: 0.0 ..< 0.45))
if self.maskBlobView.presentationAudioLevel > 0.15 {
newValue = CGPoint(x: CGFloat.random(in: 0.8 ..< 1.0), y: CGFloat.random(in: 0.1 ..< 0.45))
} else {
newValue = CGPoint(x: CGFloat.random(in: 0.7 ..< 0.9), y: CGFloat.random(in: 0.0 ..< 0.45))
newValue = CGPoint(x: CGFloat.random(in: 0.6 ..< 0.8), y: CGFloat.random(in: 0.1 ..< 0.45))
}
self.foregroundGradientLayer.startPoint = newValue
@ -452,6 +451,8 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
private func setupProgressAnimations() {
if let _ = self.maskProgressLayer.animation(forKey: "progressRotation") {
} else {
self.maskProgressLayer.isHidden = false
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = 1.0
@ -537,7 +538,110 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.foregroundGradientLayer.colors = targetColors
self.foregroundGradientLayer.animate(from: initialColors as AnyObject, to: targetColors as AnyObject, keyPath: "colors", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.3)
}
private func playConnectionDisappearanceAnimation() {
let initialRotation: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.transform.rotation.z") as? NSNumber)?.floatValue ?? 0.0)
let initialStrokeEnd: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.strokeEnd") as? NSNumber)?.floatValue ?? 1.0)
self.maskProgressLayer.removeAnimation(forKey: "progressGrowth")
self.maskProgressLayer.removeAnimation(forKey: "progressRotation")
let duration: Double = (1.0 - Double(initialStrokeEnd)) * 0.6
let growthAnimation = CABasicAnimation(keyPath: "strokeEnd")
growthAnimation.fromValue = initialStrokeEnd
growthAnimation.toValue = 0.0
growthAnimation.duration = duration
growthAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotateAnimation.fromValue = initialRotation
rotateAnimation.toValue = initialRotation + CGFloat.pi * 2
rotateAnimation.isAdditive = true
rotateAnimation.duration = duration
rotateAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [growthAnimation, rotateAnimation]
groupAnimation.duration = duration
CATransaction.setCompletionBlock {
CATransaction.begin()
CATransaction.setDisableActions(true)
self.maskProgressLayer.isHidden = true
self.maskProgressLayer.removeAllAnimations()
CATransaction.commit()
}
self.maskProgressLayer.add(groupAnimation, forKey: "progressDisappearance")
CATransaction.commit()
}
private func playBlobsDisappearanceAnimation() {
self.foregroundCircleLayer.isHidden = false
self.updateGlowAndGradientAnimations(active: nil, previousActive: nil)
self.maskBlobView.startAnimating()
self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak self] _ in
self?.maskBlobView.isHidden = true
self?.maskBlobView.stopAnimating()
self?.maskBlobView.layer.removeAllAnimations()
})
CATransaction.begin()
let growthAnimation = CABasicAnimation(keyPath: "transform.scale")
growthAnimation.fromValue = 0.0
growthAnimation.toValue = 1.0
growthAnimation.duration = 0.15
growthAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
CATransaction.setCompletionBlock {
CATransaction.begin()
CATransaction.setDisableActions(true)
self.maskGradientLayer.isHidden = true
self.maskCircleLayer.isHidden = true
self.foregroundCircleLayer.isHidden = true
CATransaction.commit()
}
self.foregroundCircleLayer.add(growthAnimation, forKey: "insideGrowth")
CATransaction.commit()
}
private func playBlobsAppearanceAnimation(active: Bool) {
CATransaction.begin()
CATransaction.setDisableActions(true)
self.foregroundCircleLayer.isHidden = false
self.maskCircleLayer.isHidden = false
self.maskProgressLayer.isHidden = true
self.maskGradientLayer.isHidden = false
CATransaction.commit()
self.updateGlowAndGradientAnimations(active: active, previousActive: nil)
self.maskBlobView.isHidden = false
self.maskBlobView.startAnimating()
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
CATransaction.begin()
let shrinkAnimation = CABasicAnimation(keyPath: "transform.scale")
shrinkAnimation.fromValue = 1.0
shrinkAnimation.toValue = 0.0
shrinkAnimation.duration = 0.15
shrinkAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
CATransaction.setCompletionBlock {
CATransaction.begin()
CATransaction.setDisableActions(true)
self.foregroundCircleLayer.isHidden = true
CATransaction.commit()
}
self.foregroundCircleLayer.add(shrinkAnimation, forKey: "insideShrink")
CATransaction.commit()
}
private func playConnectionAnimation(active: Bool, completion: @escaping () -> Void) {
CATransaction.begin()
let initialRotation: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.transform.rotation.z") as? NSNumber)?.floatValue ?? 0.0)
@ -578,6 +682,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.updateGlowAndGradientAnimations(active: active, previousActive: nil)
self.maskBlobView.isHidden = false
self.maskBlobView.startAnimating()
self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45)
@ -626,21 +731,34 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
if transition == .connecting {
self.playConnectionAnimation(active: newActive) { [weak self] in
self?.isActive = newActive
self?.transition = nil
}
} else if transition == .disabled {
self.playBlobsAppearanceAnimation(active: newActive)
self.transition = nil
self.isActive = newActive
self.updatedActive?(true)
} else if case let .blob(previousActive) = transition {
updateGlowAndGradientAnimations(active: newActive, previousActive: previousActive)
self.transition = nil
self.isActive = newActive
}
self.transition = nil
} else {
self.maskBlobView.startAnimating()
}
case .disabled:
self.updatedActive?(true)
self.isActive = false
self.updateGlowScale(nil)
if let transition = self.transition {
if case .connecting = transition {
playConnectionDisappearanceAnimation()
} else if case .blob = transition {
playBlobsDisappearanceAnimation()
}
self.transition = nil
}
break
}
}

View File

@ -1447,7 +1447,7 @@ public final class VoiceChatController: ViewController {
self.audioOutputNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: soundAppearance, image: soundImage), text: self.presentationData.strings.VoiceChat_Audio, transition: .animated(duration: 0.3, curve: .linear))
self.leaveNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: .color(.custom(0x4d120e)), image: .end), text: self.presentationData.strings.VoiceChat_Leave, transition: .immediate)
self.leaveNode.update(size: sideButtonSize, content: CallControllerButtonItemNode.Content(appearance: .color(.custom(0x602522)), image: .end), text: self.presentationData.strings.VoiceChat_Leave, transition: .immediate)
let sideButtonMinimalInset: CGFloat = 16.0
let sideButtonOffset = min(36.0, floor((((layout.size.width - 144.0) / 2.0) - sideButtonSize.width) / 2.0))
@ -1588,15 +1588,15 @@ public final class VoiceChatController: ViewController {
index += 1
}
if callMembers.isEmpty, let accountPeer = self.accountPeer {
entries.append(.peer(PeerEntry(
if let accountPeer = self.accountPeer, !processedPeerIds.contains(accountPeer.id) {
entries.insert(.peer(PeerEntry(
peer: accountPeer,
presence: nil,
activityTimestamp: Int32.max - 1 - index,
state: .listening,
muteState: GroupCallParticipantsContext.Participant.MuteState(canUnmute: true),
canManageCall: callState?.canManageCall ?? false
)))
)), at: 1)
}
for peer in invitedPeers {
@ -1785,6 +1785,7 @@ public final class VoiceChatController: ViewController {
super.viewDidDisappear(animated)
self.idleTimerExtensionDisposable.set(nil)
self.onViewDidDisappear?()
}
func dismissInteractively(completion: (() -> Void)? = nil) {

View File

@ -5278,23 +5278,31 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
if let peer = peer as? TelegramUser, peer.id != strongSelf.context.account.peerId, let contextController = contextController {
var contextItems: [ContextMenuItem] = []
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(peer.compactDisplayTitle).0, textColor: .primary, icon: { _ in nil }, action: { c, _ in
c.dismiss(completion: {
pinAction(true, false)
})
})))
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesForMe, textColor: .primary, icon: { _ in nil }, action: { c, _ in
c.dismiss(completion: {
if let peer = peer as? TelegramChannel, case .broadcast = peer.info, let contextController = contextController {
contextController.dismiss(completion: {
pinAction(true, false)
})
} else if let peer = peer as? TelegramUser, let contextController = contextController {
if peer.id == strongSelf.context.account.peerId {
contextController.dismiss(completion: {
pinAction(true, true)
})
})))
contextController.setItems(.single(contextItems))
} else {
var contextItems: [ContextMenuItem] = []
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(peer.compactDisplayTitle).0, textColor: .primary, icon: { _ in nil }, action: { c, _ in
c.dismiss(completion: {
pinAction(true, false)
})
})))
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesForMe, textColor: .primary, icon: { _ in nil }, action: { c, _ in
c.dismiss(completion: {
pinAction(true, true)
})
})))
contextController.setItems(.single(contextItems))
}
return
} else {
if let contextController = contextController {