mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Voice Chat UI fixes
This commit is contained in:
parent
025a21fc49
commit
6da71a8d3b
@ -3,17 +3,23 @@ import UIKit
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import TelegramPresentationData
|
||||||
|
import TelegramUIPreferences
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
|
||||||
|
|
||||||
private class CallStatusBarBackgroundNodeDrawingState: NSObject {
|
private class CallStatusBarBackgroundNodeDrawingState: NSObject {
|
||||||
|
let timestamp: Double
|
||||||
let amplitude: CGFloat
|
let amplitude: CGFloat
|
||||||
|
let phase: CGFloat
|
||||||
let speaking: Bool
|
let speaking: Bool
|
||||||
let transitionArguments: (startTime: Double, duration: Double)?
|
let transitionArguments: (startTime: Double, duration: Double)?
|
||||||
|
|
||||||
init(amplitude: CGFloat, speaking: Bool, transitionArguments: (Double, Double)?) {
|
init(timestamp: Double, amplitude: CGFloat, phase: CGFloat, speaking: Bool, transitionArguments: (Double, Double)?) {
|
||||||
|
self.timestamp = timestamp
|
||||||
self.amplitude = amplitude
|
self.amplitude = amplitude
|
||||||
|
self.phase = phase
|
||||||
self.speaking = speaking
|
self.speaking = speaking
|
||||||
self.transitionArguments = transitionArguments
|
self.transitionArguments = transitionArguments
|
||||||
}
|
}
|
||||||
@ -23,7 +29,8 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
var muted = true
|
var muted = true
|
||||||
|
|
||||||
var audioLevel: Float = 0.0
|
var audioLevel: Float = 0.0
|
||||||
var presentationAudioLevel: Float = 0.0
|
var presentationAudioLevel: CGFloat = 0.0
|
||||||
|
var phase: CGFloat = 0.0
|
||||||
|
|
||||||
private var animator: ConstantDisplayLinkAnimator?
|
private var animator: ConstantDisplayLinkAnimator?
|
||||||
|
|
||||||
@ -36,6 +43,8 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateAnimations() {
|
func updateAnimations() {
|
||||||
|
self.presentationAudioLevel = self.presentationAudioLevel * 0.9 + max(0.1, CGFloat(self.audioLevel)) * 0.1
|
||||||
|
|
||||||
let animator: ConstantDisplayLinkAnimator
|
let animator: ConstantDisplayLinkAnimator
|
||||||
if let current = self.animator {
|
if let current = self.animator {
|
||||||
animator = current
|
animator = current
|
||||||
@ -43,23 +52,21 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
animator = ConstantDisplayLinkAnimator(update: { [weak self] in
|
||||||
self?.updateAnimations()
|
self?.updateAnimations()
|
||||||
})
|
})
|
||||||
animator.frameInterval = 2
|
|
||||||
self.animator = animator
|
self.animator = animator
|
||||||
}
|
}
|
||||||
animator.isPaused = true
|
animator.isPaused = false
|
||||||
|
|
||||||
|
self.phase -= 0.05
|
||||||
self.setNeedsDisplay()
|
self.setNeedsDisplay()
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
||||||
return CallStatusBarBackgroundNodeDrawingState(amplitude: 1.0, speaking: false, transitionArguments: nil)
|
return CallStatusBarBackgroundNodeDrawingState(timestamp: CACurrentMediaTime(), amplitude: self.presentationAudioLevel, phase: self.phase, speaking: false, transitionArguments: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
||||||
let context = UIGraphicsGetCurrentContext()!
|
let context = UIGraphicsGetCurrentContext()!
|
||||||
|
|
||||||
let drawStart = CACurrentMediaTime()
|
|
||||||
|
|
||||||
if !isRasterizing {
|
if !isRasterizing {
|
||||||
context.setBlendMode(.copy)
|
context.setBlendMode(.copy)
|
||||||
context.setFillColor(UIColor.clear.cgColor)
|
context.setFillColor(UIColor.clear.cgColor)
|
||||||
@ -71,31 +78,101 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var locations: [CGFloat] = [0.0, 1.0]
|
var locations: [CGFloat] = [0.0, 1.0]
|
||||||
let colors: [CGColor] = [UIColor(rgb: 0x007fff).cgColor, UIColor(rgb:0x00afff).cgColor]
|
|
||||||
|
var gradientTransition: CGFloat = 0.0
|
||||||
|
gradientTransition = parameters.speaking ? 1.0 : 0.0
|
||||||
|
if let transition = parameters.transitionArguments {
|
||||||
|
gradientTransition = CGFloat((parameters.timestamp - transition.startTime) / transition.duration)
|
||||||
|
if !parameters.speaking {
|
||||||
|
gradientTransition = 1.0 - gradientTransition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftColor = UIColor(rgb: 0x007fff).interpolateTo(UIColor(rgb: 0x2bb76b), fraction: gradientTransition)!
|
||||||
|
let rightColor = UIColor(rgb: 0x00afff).interpolateTo(UIColor(rgb: 0x007fff), fraction: gradientTransition)!
|
||||||
|
let colors: [CGColor] = [leftColor.cgColor, rightColor.cgColor]
|
||||||
|
|
||||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||||
|
|
||||||
|
let position: CGFloat = bounds.height - 6.0
|
||||||
|
let maxAmplitude: CGFloat = 8.0
|
||||||
|
|
||||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: bounds.width, y: 0.0), options: CGGradientDrawingOptions())
|
let amplitude = max(0.35, parameters.amplitude)
|
||||||
|
|
||||||
|
func drawWave(_ index: Int, maxAmplitude: CGFloat, normalizedAmplitude: CGFloat) {
|
||||||
|
let path = UIBezierPath()
|
||||||
|
let mid = bounds.width / 2.0
|
||||||
|
|
||||||
|
var offset: CGFloat = 0.0
|
||||||
|
if index > 0 {
|
||||||
|
offset = 3.0 * parameters.amplitude * CGFloat(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
let frequency: CGFloat = 3.5
|
||||||
|
let density: CGFloat = 2.0
|
||||||
|
for x in stride(from: 0.0, to: bounds.width + density, by: density) {
|
||||||
|
let scaling = -pow(1 / mid * (x - mid), 2) + 1
|
||||||
|
let y = scaling * maxAmplitude * normalizedAmplitude * sin(CGFloat(2 * Double.pi) * frequency * (x / bounds.width) + parameters.phase) + position + offset
|
||||||
|
if x == 0 {
|
||||||
|
path.move(to: CGPoint())
|
||||||
|
}
|
||||||
|
path.addLine(to: CGPoint(x: x, y: y))
|
||||||
|
}
|
||||||
|
path.addLine(to: CGPoint(x: bounds.width, y: 0.0))
|
||||||
|
path.close()
|
||||||
|
|
||||||
|
context.addPath(path.cgPath)
|
||||||
|
context.clip()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in (0 ..< 2).reversed() {
|
||||||
|
let progress = 1.0 - CGFloat(i) / 3.0
|
||||||
|
var normalizedAmplitude = (1.5 * progress - 0.8) * amplitude
|
||||||
|
if i == 1 {
|
||||||
|
normalizedAmplitude *= -1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
context.saveGState()
|
||||||
|
drawWave(i, maxAmplitude: maxAmplitude, normalizedAmplitude: normalizedAmplitude)
|
||||||
|
|
||||||
|
if i == 1 {
|
||||||
|
context.setFillColor(UIColor(rgb: 0x007fff, alpha: 0.3).cgColor)
|
||||||
|
context.fill(bounds)
|
||||||
|
} else {
|
||||||
|
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: bounds.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||||
|
}
|
||||||
|
context.restoreGState()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CallStatusBarNodeImpl: CallStatusBarNode {
|
public class CallStatusBarNodeImpl: CallStatusBarNode {
|
||||||
public enum Content {
|
public enum Content {
|
||||||
case call(PresentationCall)
|
case call(SharedAccountContext, Account, PresentationCall)
|
||||||
case groupCall(PresentationGroupCall)
|
case groupCall(SharedAccountContext, Account, PresentationGroupCall)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let microphoneNode: VoiceChatMicrophoneNode
|
|
||||||
private let backgroundNode: CallStatusBarBackgroundNode
|
private let backgroundNode: CallStatusBarBackgroundNode
|
||||||
|
private let microphoneNode: VoiceChatMicrophoneNode
|
||||||
private let titleNode: ImmediateTextNode
|
private let titleNode: ImmediateTextNode
|
||||||
private let subtitleNode: ImmediateTextNode
|
private let subtitleNode: ImmediateTextNode
|
||||||
|
|
||||||
private let audioLevelDisposable = MetaDisposable()
|
private let audioLevelDisposable = MetaDisposable()
|
||||||
|
private let stateDisposable = MetaDisposable()
|
||||||
|
private var didSetupData = false
|
||||||
|
|
||||||
private var currentSize: CGSize?
|
private var currentSize: CGSize?
|
||||||
private var currentContent: Content?
|
private var currentContent: Content?
|
||||||
|
|
||||||
|
private var strings: PresentationStrings?
|
||||||
|
private var nameDisplayOrder: PresentationPersonNameOrder = .firstLast
|
||||||
|
private var currentPeer: Peer?
|
||||||
|
private var currentCallTimer: SwiftSignalKit.Timer?
|
||||||
|
private var currentCallState: PresentationCallState?
|
||||||
|
private var currentGroupCallState: PresentationGroupCallSummaryState?
|
||||||
|
private var currentIsMuted = true
|
||||||
|
|
||||||
public override init() {
|
public override init() {
|
||||||
self.backgroundNode = CallStatusBarBackgroundNode()
|
self.backgroundNode = CallStatusBarBackgroundNode()
|
||||||
self.microphoneNode = VoiceChatMicrophoneNode()
|
self.microphoneNode = VoiceChatMicrophoneNode()
|
||||||
@ -105,13 +182,15 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
self.addSubnode(self.backgroundNode)
|
||||||
// self.addSubnode(self.microphoneNode)
|
self.addSubnode(self.microphoneNode)
|
||||||
// self.addSubnode(self.titleNode)
|
self.addSubnode(self.titleNode)
|
||||||
// self.addSubnode(self.subtitleNode)
|
self.addSubnode(self.subtitleNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.audioLevelDisposable.dispose()
|
self.audioLevelDisposable.dispose()
|
||||||
|
self.stateDisposable.dispose()
|
||||||
|
self.currentCallTimer?.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func update(content: Content) {
|
public func update(content: Content) {
|
||||||
@ -129,8 +208,76 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.titleNode.attributedText = NSAttributedString(string: "Voice Chat", font: Font.semibold(13.0), textColor: .white)
|
if !self.didSetupData {
|
||||||
self.subtitleNode.attributedText = NSAttributedString(string: "2 members", font: Font.regular(13.0), textColor: .white)
|
switch content {
|
||||||
|
case let .call(sharedContext, account, call):
|
||||||
|
let presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.strings = presentationData.strings
|
||||||
|
self.nameDisplayOrder = presentationData.nameDisplayOrder
|
||||||
|
self.stateDisposable.set(
|
||||||
|
(combineLatest(
|
||||||
|
account.postbox.loadedPeerWithId(call.peerId),
|
||||||
|
call.state,
|
||||||
|
call.isMuted
|
||||||
|
)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] peer, state, isMuted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.currentPeer = peer
|
||||||
|
strongSelf.currentCallState = state
|
||||||
|
strongSelf.currentIsMuted = isMuted
|
||||||
|
strongSelf.update()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
case let .groupCall(sharedContext, account, call):
|
||||||
|
let presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||||
|
self.strings = presentationData.strings
|
||||||
|
self.nameDisplayOrder = presentationData.nameDisplayOrder
|
||||||
|
self.stateDisposable.set(
|
||||||
|
(combineLatest(
|
||||||
|
account.postbox.loadedPeerWithId(call.peerId),
|
||||||
|
call.summaryState,
|
||||||
|
call.isMuted
|
||||||
|
)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] peer, state, isMuted in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.currentPeer = peer
|
||||||
|
strongSelf.currentGroupCallState = state
|
||||||
|
strongSelf.currentIsMuted = isMuted
|
||||||
|
strongSelf.update()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
self.audioLevelDisposable.set((call.myAudioLevel
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] level in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var effectiveLevel: Float = 0.0
|
||||||
|
if !strongSelf.currentIsMuted {
|
||||||
|
effectiveLevel = level
|
||||||
|
}
|
||||||
|
strongSelf.backgroundNode.audioLevel = effectiveLevel
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
self.didSetupData = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var title: String = ""
|
||||||
|
var subtitle: String = ""
|
||||||
|
|
||||||
|
if let strings = self.strings {
|
||||||
|
if let currentPeer = self.currentPeer {
|
||||||
|
title = currentPeer.displayTitle(strings: strings, displayOrder: self.nameDisplayOrder)
|
||||||
|
}
|
||||||
|
if let groupCallState = self.currentGroupCallState {
|
||||||
|
if groupCallState.numberOfActiveSpeakers != 0 {
|
||||||
|
subtitle = strings.VoiceChat_Panel_MembersSpeaking(Int32(groupCallState.numberOfActiveSpeakers))
|
||||||
|
} else {
|
||||||
|
subtitle = strings.VoiceChat_Panel_Members(Int32(max(1, groupCallState.participantCount)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(13.0), textColor: .white)
|
||||||
|
self.subtitleNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(13.0), textColor: .white)
|
||||||
|
|
||||||
let animationSize: CGFloat = 25.0
|
let animationSize: CGFloat = 25.0
|
||||||
let iconSpacing: CGFloat = 0.0
|
let iconSpacing: CGFloat = 0.0
|
||||||
@ -145,11 +292,11 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
let verticalOrigin: CGFloat = size.height - contentHeight
|
let verticalOrigin: CGFloat = size.height - contentHeight
|
||||||
|
|
||||||
self.microphoneNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin + floor((contentHeight - animationSize) / 2.0)), size: CGSize(width: animationSize, height: animationSize))
|
self.microphoneNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin, y: verticalOrigin + floor((contentHeight - animationSize) / 2.0)), size: CGSize(width: animationSize, height: animationSize))
|
||||||
self.microphoneNode.update(state: VoiceChatMicrophoneNode.State(muted: true, color: UIColor.white), animated: true)
|
self.microphoneNode.update(state: VoiceChatMicrophoneNode.State(muted: self.currentIsMuted, color: UIColor.white), animated: true)
|
||||||
|
|
||||||
self.titleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing, y: verticalOrigin + floor((contentHeight - titleSize.height) / 2.0)), size: titleSize)
|
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.subtitleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize)
|
||||||
|
|
||||||
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height))
|
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 7.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,6 +287,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
private var callStateDisposable: Disposable?
|
private var callStateDisposable: Disposable?
|
||||||
|
|
||||||
private var pushingToTalk = false
|
private var pushingToTalk = false
|
||||||
|
private let hapticFeedback = HapticFeedback()
|
||||||
|
|
||||||
private var callState: PresentationGroupCallState?
|
private var callState: PresentationGroupCallState?
|
||||||
|
|
||||||
@ -488,7 +489,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
let subtitle = strongSelf.presentationData.strings.Conversation_StatusMembers(Int32(callMembers.totalCount))
|
let subtitle = strongSelf.presentationData.strings.Conversation_StatusMembers(Int32(max(1, callMembers.totalCount)))
|
||||||
if let titleView = strongSelf.controller?.navigationItem.titleView as? VoiceChatControllerTitleView {
|
if let titleView = strongSelf.controller?.navigationItem.titleView as? VoiceChatControllerTitleView {
|
||||||
titleView.set(title: "Voice Chat", subtitle: subtitle)
|
titleView.set(title: "Voice Chat", subtitle: subtitle)
|
||||||
}
|
}
|
||||||
@ -523,6 +524,14 @@ public final class VoiceChatController: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
|
||||||
|
if !(channel.addressName ?? "").isEmpty || (channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers)) {
|
||||||
|
strongSelf.optionsButton.isHidden = false
|
||||||
|
} else {
|
||||||
|
strongSelf.optionsButton.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !strongSelf.didSetDataReady {
|
if !strongSelf.didSetDataReady {
|
||||||
strongSelf.didSetDataReady = true
|
strongSelf.didSetDataReady = true
|
||||||
strongSelf.controller?.dataReady.set(true)
|
strongSelf.controller?.dataReady.set(true)
|
||||||
@ -750,7 +759,14 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc private func actionButtonPressed() {
|
@objc private func actionButtonPressed() {
|
||||||
self.call.toggleIsMuted()
|
if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hapticFeedback.error()
|
||||||
|
self.actionButton.layer.addShakeAnimation()
|
||||||
|
// self.call.toggleIsMuted()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func audioOutputPressed() {
|
@objc private func audioOutputPressed() {
|
||||||
@ -996,7 +1012,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (backgroundView, foregroundView) = sourcePanel.rightButtonSnapshotViews() {
|
if let (backgroundView, foregroundView) = sourcePanel.rightButtonSnapshotViews(), !self.optionsButton.isHidden {
|
||||||
self.view.addSubview(backgroundView)
|
self.view.addSubview(backgroundView)
|
||||||
self.view.addSubview(foregroundView)
|
self.view.addSubview(foregroundView)
|
||||||
|
|
||||||
@ -1034,7 +1050,7 @@ public final class VoiceChatController: ViewController {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.contentContainer.layer.animate(from: self.presentationData.theme.rootController.navigationBar.backgroundColor.cgColor, to: UIColor.black.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration - 0.1)
|
self.contentContainer.layer.animate(from: self.presentationData.theme.rootController.navigationBar.backgroundColor.cgColor, to: UIColor.black.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: duration - 0.25)
|
||||||
|
|
||||||
self.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
self.listNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||||
self.actionButton.layer.animateScale(from: 0.1, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
self.actionButton.layer.animateScale(from: 0.1, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
|
@ -652,36 +652,26 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let callAndStateSignal: Signal<(PresentationCall, PresentationCallState)?, NoError> = .single(nil)
|
let callSignal: Signal<PresentationCall?, NoError> = .single(nil)
|
||||||
|> then(
|
|> then(
|
||||||
callManager.currentCallSignal
|
callManager.currentCallSignal
|
||||||
|> mapToSignal { call in
|
|
||||||
if let call = call {
|
|
||||||
return call.state
|
|
||||||
|> map { state in
|
|
||||||
return (call, state)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return .single(nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
let groupCallAndStateSignal: Signal<PresentationGroupCall?, NoError> = .single(nil)
|
let groupCallSignal: Signal<PresentationGroupCall?, NoError> = .single(nil)
|
||||||
|> then(
|
|> then(
|
||||||
callManager.currentGroupCallSignal
|
callManager.currentGroupCallSignal
|
||||||
)
|
)
|
||||||
|
|
||||||
self.callStateDisposable = combineLatest(queue: .mainQueue(),
|
self.callStateDisposable = combineLatest(queue: .mainQueue(),
|
||||||
callAndStateSignal,
|
callSignal,
|
||||||
groupCallAndStateSignal
|
groupCallSignal
|
||||||
).start(next: { [weak self] callAndState, groupCall in
|
).start(next: { [weak self] call, groupCall in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let statusBarContent: CallStatusBarNodeImpl.Content?
|
let statusBarContent: CallStatusBarNodeImpl.Content?
|
||||||
|
|
||||||
if let (call, state) = callAndState {
|
if let call = call {
|
||||||
statusBarContent = .call(call)
|
statusBarContent = .call(strongSelf, call.account, call)
|
||||||
} else if let groupCall = groupCall {
|
} else if let groupCall = groupCall {
|
||||||
statusBarContent = .groupCall(groupCall)
|
statusBarContent = .groupCall(strongSelf, groupCall.account, groupCall)
|
||||||
} else {
|
} else {
|
||||||
statusBarContent = nil
|
statusBarContent = nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user