mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Voice Chat UI fixes
This commit is contained in:
parent
096ae2a790
commit
e26feea167
@ -190,14 +190,14 @@ public struct PresentationGroupCallState: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct PresentationGroupCallSummaryState: Equatable {
|
public struct PresentationGroupCallSummaryState: Equatable {
|
||||||
public var info: GroupCallInfo
|
public var info: GroupCallInfo?
|
||||||
public var participantCount: Int
|
public var participantCount: Int
|
||||||
public var callState: PresentationGroupCallState
|
public var callState: PresentationGroupCallState
|
||||||
public var topParticipants: [GroupCallParticipantsContext.Participant]
|
public var topParticipants: [GroupCallParticipantsContext.Participant]
|
||||||
public var activeSpeakers: Set<PeerId>
|
public var activeSpeakers: Set<PeerId>
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
info: GroupCallInfo,
|
info: GroupCallInfo?,
|
||||||
participantCount: Int,
|
participantCount: Int,
|
||||||
callState: PresentationGroupCallState,
|
callState: PresentationGroupCallState,
|
||||||
topParticipants: [GroupCallParticipantsContext.Participant],
|
topParticipants: [GroupCallParticipantsContext.Participant],
|
||||||
|
|||||||
@ -899,12 +899,17 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
|
|
||||||
let itemInBounds = bounds.intersects(item.frame)
|
let itemInBounds = bounds.intersects(item.frame)
|
||||||
|
|
||||||
|
var absoluteRect = item.frame
|
||||||
if let itemNode = self.itemNodes[item.index] {
|
if let itemNode = self.itemNodes[item.index] {
|
||||||
if itemNode.frame != item.frame {
|
if itemNode.frame != item.frame {
|
||||||
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.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 {
|
} else {
|
||||||
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout, synchronousLoad: synchronousLoads && itemInBounds)
|
let itemNode = self.items[item.index].node(layout: presentationLayoutTransition.layout.layout, synchronousLoad: synchronousLoads && itemInBounds)
|
||||||
itemNode.frame = item.frame
|
itemNode.frame = item.frame
|
||||||
@ -912,7 +917,11 @@ open class GridNode: GridNodeScroller, UIScrollViewDelegate {
|
|||||||
addedNodes = true
|
addedNodes = true
|
||||||
itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads)
|
itemNode.updateLayout(item: self.items[item.index], size: item.frame.size, isVisible: bounds.intersects(item.frame), synchronousLoads: synchronousLoads)
|
||||||
self.setupNode?(itemNode)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
|
|||||||
private let rightLine: ASDisplayNode
|
private let rightLine: ASDisplayNode
|
||||||
|
|
||||||
private var isCurrentlyInHierarchy = true
|
private var isCurrentlyInHierarchy = true
|
||||||
private var shouldBeAnimating = false
|
|
||||||
|
|
||||||
var color: UIColor = UIColor(rgb: 0xffffff) {
|
var color: UIColor = UIColor(rgb: 0xffffff) {
|
||||||
didSet {
|
didSet {
|
||||||
@ -64,10 +63,9 @@ private final class VoiceChatIndicatorNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateAnimation() {
|
private func updateAnimation() {
|
||||||
let shouldBeAnimating = self.isCurrentlyInHierarchy
|
if self.isCurrentlyInHierarchy {
|
||||||
if shouldBeAnimating != self.shouldBeAnimating {
|
if let _ = self.leftLine.layer.animation(forKey: "animation") {
|
||||||
self.shouldBeAnimating = shouldBeAnimating
|
} else {
|
||||||
if shouldBeAnimating {
|
|
||||||
let timingFunctions: [CAMediaTimingFunction] = (0 ..< 5).map { _ in CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) }
|
let timingFunctions: [CAMediaTimingFunction] = (0 ..< 5).map { _ in CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) }
|
||||||
|
|
||||||
let leftAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
|
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.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.repeatCount = Float.infinity
|
||||||
leftAnimation.duration = 2.2
|
leftAnimation.duration = 2.2
|
||||||
|
leftAnimation.beginTime = 1.0
|
||||||
self.leftLine.layer.add(leftAnimation, forKey: "animation")
|
self.leftLine.layer.add(leftAnimation, forKey: "animation")
|
||||||
|
|
||||||
let centerAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
|
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.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.repeatCount = Float.infinity
|
||||||
centerAnimation.duration = 2.2
|
centerAnimation.duration = 2.2
|
||||||
|
centerAnimation.beginTime = 1.0
|
||||||
self.centerLine.layer.add(centerAnimation, forKey: "animation")
|
self.centerLine.layer.add(centerAnimation, forKey: "animation")
|
||||||
|
|
||||||
let rightAnimation = CAKeyframeAnimation(keyPath: "bounds.size.height")
|
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.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.repeatCount = Float.infinity
|
||||||
rightAnimation.duration = 2.2
|
rightAnimation.duration = 2.2
|
||||||
|
rightAnimation.beginTime = 1.0
|
||||||
self.rightLine.layer.add(rightAnimation, forKey: "animation")
|
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) {
|
public func setImage(_ image: UIImage?, color: UIColor?, transition: ContainedViewLayoutTransition) {
|
||||||
if case let .animated(duration, curve) = transition {
|
if case let .animated(duration, curve) = transition, !self.iconNode.isHidden {
|
||||||
if let snapshotLayer = self.iconNode.layer.snapshotContentTree() {
|
let snapshotLayer = CALayer()
|
||||||
snapshotLayer.frame = self.iconNode.frame
|
snapshotLayer.contents = self.iconNode.layer.contents
|
||||||
self.iconNode.layer.insertSublayer(snapshotLayer, at: 0)
|
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.animateAlpha(from: 1.0, to: 0.0, duration: duration, timingFunction: curve.timingFunction, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
|
||||||
snapshotLayer?.removeFromSuperlayer()
|
snapshotLayer?.removeFromSuperlayer()
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.iconNode.image = image
|
self.iconNode.image = image
|
||||||
if let color = color {
|
if let color = color {
|
||||||
@ -147,7 +147,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
|
|||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.iconNode.frame = CGRect(x: 0.0, y: 0.0, width: size, height: size)
|
strongSelf.iconNode.frame = CGRect(x: 0.0, y: 0.0, width: size, height: size)
|
||||||
|
|
||||||
if isVoiceChat {
|
if online && isVoiceChat {
|
||||||
if let _ = strongSelf.animationNode {
|
if let _ = strongSelf.animationNode {
|
||||||
} else {
|
} else {
|
||||||
let animationNode = VoiceChatIndicatorNode()
|
let animationNode = VoiceChatIndicatorNode()
|
||||||
@ -166,7 +166,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
|
|||||||
if let strongSelf = self, finished {
|
if let strongSelf = self, finished {
|
||||||
strongSelf.iconNode.isHidden = !online
|
strongSelf.iconNode.isHidden = !online
|
||||||
|
|
||||||
if let animationNode = strongSelf.animationNode, !isVoiceChat {
|
if let animationNode = strongSelf.animationNode, !online {
|
||||||
animationNode.removeFromSupernode()
|
animationNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ public final class PeerOnlineMarkerNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.iconNode.isHidden = !online
|
strongSelf.iconNode.isHidden = !online
|
||||||
|
|
||||||
if let animationNode = strongSelf.animationNode, !isVoiceChat {
|
if let animationNode = strongSelf.animationNode, !online {
|
||||||
animationNode.removeFromSupernode()
|
animationNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -162,6 +162,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
private var currentCallState: PresentationCallState?
|
private var currentCallState: PresentationCallState?
|
||||||
private var currentGroupCallState: PresentationGroupCallSummaryState?
|
private var currentGroupCallState: PresentationGroupCallSummaryState?
|
||||||
private var currentIsMuted = true
|
private var currentIsMuted = true
|
||||||
|
private var currentIsConnecting = true
|
||||||
|
|
||||||
public override init() {
|
public override init() {
|
||||||
self.backgroundNode = CallStatusBarBackgroundNode()
|
self.backgroundNode = CallStatusBarBackgroundNode()
|
||||||
@ -224,13 +225,13 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
self.nameDisplayOrder = presentationData.nameDisplayOrder
|
self.nameDisplayOrder = presentationData.nameDisplayOrder
|
||||||
self.stateDisposable.set(
|
self.stateDisposable.set(
|
||||||
(combineLatest(
|
(combineLatest(
|
||||||
account.postbox.loadedPeerWithId(call.peerId),
|
account.postbox.peerView(id: call.peerId),
|
||||||
call.summaryState,
|
call.summaryState,
|
||||||
call.isMuted
|
call.isMuted
|
||||||
)
|
)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peer, state, isMuted in
|
|> deliverOnMainQueue).start(next: { [weak self] view, state, isMuted in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.currentPeer = peer
|
strongSelf.currentPeer = view.peers[view.peerId]
|
||||||
strongSelf.currentGroupCallState = state
|
strongSelf.currentGroupCallState = state
|
||||||
strongSelf.currentIsMuted = isMuted
|
strongSelf.currentIsMuted = isMuted
|
||||||
strongSelf.update()
|
strongSelf.update()
|
||||||
|
|||||||
@ -571,14 +571,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
self.statePromise.get()
|
self.statePromise.get()
|
||||||
)
|
)
|
||||||
|> map { infoState, participantsState, callState -> PresentationGroupCallSummaryState? in
|
|> map { infoState, participantsState, callState -> PresentationGroupCallSummaryState? in
|
||||||
guard let infoState = infoState else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
guard let participantsState = participantsState else {
|
guard let participantsState = participantsState else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return PresentationGroupCallSummaryState(
|
return PresentationGroupCallSummaryState(
|
||||||
info: infoState.info,
|
info: infoState?.info,
|
||||||
participantCount: participantsState.participantCount,
|
participantCount: participantsState.participantCount,
|
||||||
callState: callState,
|
callState: callState,
|
||||||
topParticipants: participantsState.topParticipants,
|
topParticipants: participantsState.topParticipants,
|
||||||
|
|||||||
@ -404,11 +404,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.foregroundView.mask = self.maskView
|
self.foregroundView.mask = self.maskView
|
||||||
self.foregroundView.layer.addSublayer(self.foregroundGradientLayer)
|
self.foregroundView.layer.addSublayer(self.foregroundGradientLayer)
|
||||||
|
|
||||||
self.maskView.layer.addSublayer(self.maskGradientLayer)
|
self.maskView.layer.addSublayer(self.maskGradientLayer)
|
||||||
|
|
||||||
self.maskView.layer.addSublayer(self.maskProgressLayer)
|
self.maskView.layer.addSublayer(self.maskProgressLayer)
|
||||||
|
|
||||||
self.maskView.addSubview(self.maskBlobView)
|
self.maskView.addSubview(self.maskBlobView)
|
||||||
self.maskView.layer.addSublayer(self.maskCircleLayer)
|
self.maskView.layer.addSublayer(self.maskCircleLayer)
|
||||||
|
|
||||||
@ -424,10 +422,10 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
let previousValue = self.foregroundGradientLayer.startPoint
|
let previousValue = self.foregroundGradientLayer.startPoint
|
||||||
let newValue: CGPoint
|
let newValue: CGPoint
|
||||||
if self.maskBlobView.presentationAudioLevel > 0.1 {
|
if self.maskBlobView.presentationAudioLevel > 0.15 {
|
||||||
newValue = CGPoint(x: CGFloat.random(in: 0.9 ..< 1.0), y: CGFloat.random(in: 0.0 ..< 0.45))
|
newValue = CGPoint(x: CGFloat.random(in: 0.8 ..< 1.0), y: CGFloat.random(in: 0.1 ..< 0.45))
|
||||||
} else {
|
} 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
|
self.foregroundGradientLayer.startPoint = newValue
|
||||||
|
|
||||||
|
|||||||
@ -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.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 sideButtonMinimalInset: CGFloat = 16.0
|
||||||
let sideButtonOffset = min(36.0, floor((((layout.size.width - 144.0) / 2.0) - sideButtonSize.width) / 2.0))
|
let sideButtonOffset = min(36.0, floor((((layout.size.width - 144.0) / 2.0) - sideButtonSize.width) / 2.0))
|
||||||
@ -1785,6 +1785,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
super.viewDidDisappear(animated)
|
super.viewDidDisappear(animated)
|
||||||
|
|
||||||
self.idleTimerExtensionDisposable.set(nil)
|
self.idleTimerExtensionDisposable.set(nil)
|
||||||
|
self.onViewDidDisappear?()
|
||||||
}
|
}
|
||||||
|
|
||||||
func dismissInteractively(completion: (() -> Void)? = nil) {
|
func dismissInteractively(completion: (() -> Void)? = nil) {
|
||||||
|
|||||||
@ -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 {
|
if let peer = peer as? TelegramChannel, case .broadcast = peer.info, let contextController = contextController {
|
||||||
var contextItems: [ContextMenuItem] = []
|
contextController?.dismiss(completion: {
|
||||||
|
pinAction(true, false)
|
||||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(peer.compactDisplayTitle).0, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
})
|
||||||
c.dismiss(completion: {
|
} else if let peer = peer as? TelegramUser, let contextController = contextController {
|
||||||
pinAction(true, false)
|
if peer.id == strongSelf.context.account.peerId {
|
||||||
})
|
contextController?.dismiss(completion: {
|
||||||
})))
|
|
||||||
|
|
||||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesForMe, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
|
||||||
c.dismiss(completion: {
|
|
||||||
pinAction(true, true)
|
pinAction(true, true)
|
||||||
})
|
})
|
||||||
})))
|
} else {
|
||||||
|
var contextItems: [ContextMenuItem] = []
|
||||||
contextController.setItems(.single(contextItems))
|
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
|
return
|
||||||
} else {
|
} else {
|
||||||
if let contextController = contextController {
|
if let contextController = contextController {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user