Voice Chat fixes

This commit is contained in:
Ali 2020-11-29 22:01:17 +04:00
parent 2889bae353
commit e6c91a905d
15 changed files with 4569 additions and 4678 deletions

View File

@ -5933,8 +5933,23 @@ Sorry for the inconvenience.";
"VoiceChat.RemovePeerConfirmation" = "Are you sure you want to remove %@ from the group chat?";
"VoiceChat.RemovePeerRemove" = "Remove";
"VoiceChat.PanelJoin" = "Join";
"VoiceChat.Title" = "Voice Chat";
"Message.VoiceChat.Started" = "Voice chat started";
"Message.VoiceChat.Ended" = "Voice chat ended";
"VoiceChat.StatusMembersSpeaking_0" = "%@ members speaking";
"VoiceChat.StatusMembersSpeaking_1" = "1 member speaking";
"VoiceChat.StatusMembersSpeaking_2" = "2 members speaking";
"VoiceChat.StatusMembersSpeaking_3_10" = "%@ members speaking";
"VoiceChat.StatusMembersSpeaking_many" = "%@ members speaking";
"VoiceChat.StatusMembersSpeaking_any" = "%@ members speaking";
"VoiceChat.UserInvited" = "You invited **%@** to the voice chat";
"PeerInfo.CreateVoiceChat" = "Create Voice Chat";
"Notification.VoiceChatInvitation" = "%1$@ invited %2$@ to the voice chat";
"Notification.VoiceChatInvitationByYou" = "You invited %1$@ to the voice chat";
"Notification.VoiceChatInvitationForYou" = "%1$@ invited you to the voice chat";

View File

@ -390,6 +390,8 @@ open class NavigationController: UINavigationController, ContainableController,
globalScrollToTopNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: layout.size.width, height: 1.0))
}
var overlayContainerLayout = layout
if let inCallStatusBar = self.inCallStatusBar {
var inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(layout.statusBarHeight ?? 0.0, max(40.0, layout.safeInsets.top))))
if layout.deviceMetrics.hasTopNotch {
@ -541,8 +543,8 @@ open class NavigationController: UINavigationController, ContainableController,
containerTransition = transition
}
containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
overlayContainer.update(layout: layout, transition: containerTransition)
containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: overlayContainerLayout.size))
overlayContainer.update(layout: overlayContainerLayout, transition: containerTransition)
modalStyleOverlayTransitionFactor = max(modalStyleOverlayTransitionFactor, overlayContainer.controller.modalStyleOverlayTransitionFactor)
@ -586,7 +588,7 @@ open class NavigationController: UINavigationController, ContainableController,
var previousModalContainer: NavigationModalContainer?
var visibleModalCount = 0
var topModalIsFlat = false
var isLandscape = layout.orientation == .landscape
let isLandscape = layout.orientation == .landscape
var hasVisibleStandaloneModal = false
var topModalDismissProgress: CGFloat = 0.0

View File

@ -263,7 +263,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($0) }
dict[-2046916883] = { return Api.Update.parse_updateGroupCall($0) }
dict[1462009966] = { return Api.Update.parse_updateGroupCall($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }

View File

@ -6346,7 +6346,7 @@ public extension Api {
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
case updatePinnedChannelMessages(flags: Int32, channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32)
case updateGroupCallParticipants(call: Api.InputGroupCall, participants: [Api.GroupCallParticipant], version: Int32)
case updateGroupCall(call: Api.GroupCall)
case updateGroupCall(channelId: Int32, call: Api.GroupCall)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -7094,10 +7094,11 @@ public extension Api {
}
serializeInt32(version, buffer: buffer, boxed: false)
break
case .updateGroupCall(let call):
case .updateGroupCall(let channelId, let call):
if boxed {
buffer.appendInt32(-2046916883)
buffer.appendInt32(1462009966)
}
serializeInt32(channelId, buffer: buffer, boxed: false)
call.serialize(buffer, true)
break
}
@ -7277,8 +7278,8 @@ public extension Api {
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
case .updateGroupCallParticipants(let call, let participants, let version):
return ("updateGroupCallParticipants", [("call", call), ("participants", participants), ("version", version)])
case .updateGroupCall(let call):
return ("updateGroupCall", [("call", call)])
case .updateGroupCall(let channelId, let call):
return ("updateGroupCall", [("channelId", channelId), ("call", call)])
}
}
@ -8773,13 +8774,16 @@ public extension Api {
}
}
public static func parse_updateGroupCall(_ reader: BufferReader) -> Update? {
var _1: Api.GroupCall?
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.GroupCall?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.GroupCall
_2 = Api.parse(reader, signature: signature) as? Api.GroupCall
}
let _c1 = _1 != nil
if _c1 {
return Api.Update.updateGroupCall(call: _1!)
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updateGroupCall(channelId: _1!, call: _2!)
}
else {
return nil

View File

@ -211,14 +211,13 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.separatorNode.backgroundColor = presentationData.theme.chat.historyNavigation.strokeColor
self.joinButtonTitleNode.attributedText = NSAttributedString(string: presentationData.strings.Channel_JoinChannel.uppercased(), font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.actionControlForegroundColor)
self.joinButtonTitleNode.attributedText = NSAttributedString(string: presentationData.strings.VoiceChat_PanelJoin.uppercased(), font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.actionControlForegroundColor)
self.joinButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: presentationData.theme.chat.inputPanel.actionControlFillColor)
//TODO:localize
self.micButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 36.0, color: UIColor(rgb: 0x30b251))
//TODO:localize
self.titleNode.attributedText = NSAttributedString(string: "Voice Chat", font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: presentationData.strings.VoiceChat_Title, font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.primaryTextColor)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: presentationData.theme.chat.inputPanel.secondaryTextColor)
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme)
@ -253,12 +252,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
let membersText: String
let membersTextIsActive: Bool
if summaryState.numberOfActiveSpeakers != 0 {
//TODO:localize
if summaryState.numberOfActiveSpeakers == 1 {
membersText = "1 member speaking"
} else {
membersText = "\(summaryState.numberOfActiveSpeakers) members speaking"
}
membersText = strongSelf.strings.VoiceChat_StatusMembersSpeaking(Int32(summaryState.numberOfActiveSpeakers))
membersTextIsActive = true
} else {
if summaryState.participantCount == 0 {
@ -290,12 +284,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
let membersText: String
let membersTextIsActive: Bool
if data.numberOfActiveSpeakers != 0 {
//TODO:localize
if data.numberOfActiveSpeakers == 1 {
membersText = "1 member speaking"
} else {
membersText = "\(data.numberOfActiveSpeakers) members speaking"
}
membersText = self.strings.VoiceChat_StatusMembersSpeaking(Int32(data.numberOfActiveSpeakers))
membersTextIsActive = true
} else {
if data.participantCount == 0 {

View File

@ -487,10 +487,9 @@ public final class VoiceChatController: ViewController {
strongSelf.currentCallMembers = callMembers.participants
}
//TODO:localize
let subtitle = strongSelf.presentationData.strings.Conversation_StatusMembers(Int32(callMembers.totalCount))
if let titleView = strongSelf.controller?.navigationItem.titleView as? VoiceChatControllerTitleView {
titleView.set(title: "Voice Chat", subtitle: subtitle)
titleView.set(title: strongSelf.presentationData.strings.VoiceChat_Title, subtitle: subtitle)
}
})

View File

@ -111,7 +111,7 @@ enum AccountStateMutationOperation {
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
case UpdateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32)
case UpdateGroupCall(call: Api.GroupCall)
case UpdateGroupCall(peerId: PeerId, call: Api.GroupCall)
}
struct HoleFromPreviousState {
@ -282,8 +282,8 @@ struct AccountMutableState {
self.addOperation(.UpdateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version))
}
mutating func updateGroupCall(call: Api.GroupCall) {
self.addOperation(.UpdateGroupCall(call: call))
mutating func updateGroupCall(peerId: PeerId, call: Api.GroupCall) {
self.addOperation(.UpdateGroupCall(peerId: peerId, call: call))
}
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {

View File

@ -1332,8 +1332,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
case let .inputGroupCall(id, accessHash):
updatedState.updateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version)
}
case let .updateGroupCall(call):
updatedState.updateGroupCall(call: call)
case let .updateGroupCall(channelId, call):
updatedState.updateGroupCall(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), call: call)
case let .updateLangPackTooLong(langCode):
updatedState.updateLangPack(langCode: langCode, difference: nil)
case let .updateLangPack(difference):
@ -2959,15 +2959,35 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
callId,
.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version))
))
case let .UpdateGroupCall(call):
case let .UpdateGroupCall(peerId, call):
switch call {
case .groupCall:
break
if let info = GroupCallInfo(call) {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
return current.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash))
} else {
return current
}
})
}
case let .groupCallDiscarded(callId, _, _):
updatedGroupCallParticipants.append((
callId,
.call(isTerminated: true)
))
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
if let current = current as? CachedChannelData {
if let activeCall = current.activeCall, activeCall.id == callId {
return current.withUpdatedActiveCall(nil)
} else {
return current
}
} else {
return current
}
})
}
case let .UpdateLangPack(langCode, difference):
if let difference = difference {

View File

@ -28,7 +28,7 @@ public struct GroupCallSummary: Equatable {
public var topParticipants: [GroupCallParticipantsContext.Participant]
}
private extension GroupCallInfo {
extension GroupCallInfo {
init?(_ call: Api.GroupCall) {
switch call {
case let .groupCall(_, id, accessHash, participantCount, params, _):
@ -142,7 +142,7 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
var parsedCall: GroupCallInfo?
loop: for update in result.allUpdates {
switch update {
case let .updateGroupCall(call):
case let .updateGroupCall(_, call):
parsedCall = GroupCallInfo(call)
break loop
default:
@ -316,7 +316,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
var maybeParsedCall: GroupCallInfo?
loop: for update in updates.allUpdates {
switch update {
case let .updateGroupCall(call):
case let .updateGroupCall(_, call):
maybeParsedCall = GroupCallInfo(call)
break loop
default:

View File

@ -405,12 +405,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
case let .groupPhoneCall(_, _, duration):
//TODO:localize
let titleString: String
if let duration = duration {
titleString = "Voice chat ended (\(duration)s)"
titleString = strings.Message_VoiceChat_Ended
} else {
titleString = "Voice chat started"
titleString = strings.Message_VoiceChat_Started
}
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
case let .customText(text, entities):

View File

@ -1,153 +0,0 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SyncCore
import SwiftSignalKit
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
import StickerResources
import PhotoResources
import TelegramStringFormatting
import AnimatedCountLabelNode
import AnimatedNavigationStripeNode
import ContextUI
import RadialStatusNode
import AnimatedAvatarSetNode
final class ChatCallTitlePanelNode: ChatTitleAccessoryPanelNode {
private let context: AccountContext
private let tapButton: HighlightTrackingButtonNode
private let joinButton: HighlightableButtonNode
private let joinButtonTitleNode: ImmediateTextNode
private let joinButtonBackgroundNode: ASImageNode
private let titleNode: ImmediateTextNode
private let textNode: ImmediateTextNode
private let muteIconNode: ASImageNode
private let separatorNode: ASDisplayNode
private var theme: PresentationTheme?
private var currentLayout: (CGFloat, CGFloat, CGFloat)?
private var activeGroupCallInfo: ChatActiveGroupCallInfo?
private let queue = Queue()
init(context: AccountContext) {
self.context = context
self.tapButton = HighlightTrackingButtonNode()
self.joinButton = HighlightableButtonNode()
self.joinButtonTitleNode = ImmediateTextNode()
self.joinButtonBackgroundNode = ASImageNode()
self.titleNode = ImmediateTextNode()
self.textNode = ImmediateTextNode()
self.muteIconNode = ASImageNode()
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
super.init()
self.tapButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
if highlighted {
strongSelf.titleNode.layer.removeAnimation(forKey: "opacity")
strongSelf.titleNode.alpha = 0.4
strongSelf.textNode.layer.removeAnimation(forKey: "opacity")
strongSelf.textNode.alpha = 0.4
} else {
strongSelf.titleNode.alpha = 1.0
strongSelf.titleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
strongSelf.textNode.alpha = 1.0
strongSelf.textNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
}
self.addSubnode(self.titleNode)
self.addSubnode(self.textNode)
self.addSubnode(self.muteIconNode)
self.tapButton.addTarget(self, action: #selector(self.tapped), forControlEvents: [.touchUpInside])
self.addSubnode(self.tapButton)
self.joinButton.addSubnode(self.joinButtonBackgroundNode)
self.joinButton.addSubnode(self.joinButtonTitleNode)
self.addSubnode(self.joinButton)
self.joinButton.addTarget(self, action: #selector(self.tapped), forControlEvents: [.touchUpInside])
self.addSubnode(self.separatorNode)
}
deinit {
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
let panelHeight: CGFloat = 50.0
self.tapButton.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
self.activeGroupCallInfo = interfaceState.activeGroupCallInfo
if self.theme !== interfaceState.theme {
self.theme = interfaceState.theme
self.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
self.joinButtonTitleNode.attributedText = NSAttributedString(string: interfaceState.strings.Channel_JoinChannel.uppercased(), font: Font.semibold(15.0), textColor: interfaceState.theme.chat.inputPanel.actionControlForegroundColor)
self.joinButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: interfaceState.theme.chat.inputPanel.actionControlFillColor)
//TODO:localize
self.titleNode.attributedText = NSAttributedString(string: "Voice Chat", font: Font.semibold(15.0), textColor: interfaceState.theme.chat.inputPanel.primaryTextColor)
self.textNode.attributedText = NSAttributedString(string: "4 members", font: Font.regular(13.0), textColor: interfaceState.theme.chat.inputPanel.secondaryTextColor)
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(interfaceState.theme)
}
let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude))
let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0)
let joinButtonFrame = CGRect(origin: CGPoint(x: width - rightInset - 7.0 - joinButtonSize.width, y: floor((panelHeight - joinButtonSize.height) / 2.0)), size: joinButtonSize)
transition.updateFrame(node: self.joinButton, frame: joinButtonFrame)
transition.updateFrame(node: self.joinButtonBackgroundNode, frame: CGRect(origin: CGPoint(), size: joinButtonFrame.size))
transition.updateFrame(node: self.joinButtonTitleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((joinButtonFrame.width - joinButtonTitleSize.width) / 2.0), y: floorToScreenPixels((joinButtonFrame.height - joinButtonTitleSize.height) / 2.0)), size: joinButtonTitleSize))
let titleSize = self.titleNode.updateLayout(CGSize(width: width, height: .greatestFiniteMagnitude))
let textSize = self.textNode.updateLayout(CGSize(width: width, height: .greatestFiniteMagnitude))
let titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: 10.0), size: titleSize)
transition.updateFrame(node: self.titleNode, frame: titleFrame)
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((width - textSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: textSize))
if let image = self.muteIconNode.image {
transition.updateFrame(node: self.muteIconNode, frame: CGRect(origin: CGPoint(x: titleFrame.maxX + 4.0, y: titleFrame.minY + 5.0), size: image.size))
}
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
return panelHeight
}
@objc private func tapped() {
guard let interfaceInteraction = self.interfaceInteraction else {
return
}
guard let activeGroupCallInfo = self.activeGroupCallInfo else {
return
}
interfaceInteraction.joinGroupCall(activeGroupCallInfo.activeCall)
}
}

View File

@ -2968,8 +2968,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} else if let channel = peer as? TelegramChannel {
if case .group = channel.info, !channel.flags.contains(.hasVoiceChat) {
if channel.flags.contains(.isCreator) || channel.hasPermission(.manageCalls) {
//TODO:localize
items.append(ActionSheetButtonItem(title: "Create Voice Chat", color: .accent, action: { [weak self] in
items.append(ActionSheetButtonItem(title: presentationData.strings.PeerInfo_CreateVoiceChat, color: .accent, action: { [weak self] in
dismissAction()
self?.requestCall(isVideo: false)
}))

View File

@ -133,9 +133,16 @@ public final class SharedWakeupManager {
return call?.account.id == account.id
}
|> distinctUntilChanged
let isPlayingBackgroundActiveCall = combineLatest(queue: .mainQueue(), hasActiveCalls, hasActiveAudioSession)
|> map { hasActiveCalls, hasActiveAudioSession -> Bool in
return hasActiveCalls && hasActiveAudioSession
let hasActiveGroupCalls = (callManager?.currentGroupCallSignal ?? .single(nil))
|> map { call in
return call?.accountContext.account.id == account.id
}
|> distinctUntilChanged
let isPlayingBackgroundActiveCall = combineLatest(queue: .mainQueue(), hasActiveCalls, hasActiveGroupCalls, hasActiveAudioSession)
|> map { hasActiveCalls, hasActiveGroupCalls, hasActiveAudioSession -> Bool in
return (hasActiveCalls || hasActiveGroupCalls) && hasActiveAudioSession
}
|> distinctUntilChanged