mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
1d0bc9ab6f
@ -5946,6 +5946,9 @@ Sorry for the inconvenience.";
|
|||||||
"VoiceChat.RemovePeerConfirmation" = "Are you sure you want to remove %@ from the group chat?";
|
"VoiceChat.RemovePeerConfirmation" = "Are you sure you want to remove %@ from the group chat?";
|
||||||
"VoiceChat.RemovePeerRemove" = "Remove";
|
"VoiceChat.RemovePeerRemove" = "Remove";
|
||||||
|
|
||||||
|
"VoiceChat.PanelJoin" = "Join";
|
||||||
|
"VoiceChat.Title" = "Voice Chat";
|
||||||
|
|
||||||
"VoiceChat.UserInvited" = "You invited **%@** to the voice chat";
|
"VoiceChat.UserInvited" = "You invited **%@** to the voice chat";
|
||||||
|
|
||||||
"Notification.VoiceChatInvitation" = "%1$@ invited %2$@ to the voice chat";
|
"Notification.VoiceChatInvitation" = "%1$@ invited %2$@ to the voice chat";
|
||||||
|
@ -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))
|
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 {
|
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))))
|
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 {
|
if layout.deviceMetrics.hasTopNotch {
|
||||||
@ -541,8 +543,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
containerTransition = transition
|
containerTransition = transition
|
||||||
}
|
}
|
||||||
|
|
||||||
containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
|
containerTransition.updateFrame(node: overlayContainer, frame: CGRect(origin: CGPoint(), size: overlayContainerLayout.size))
|
||||||
overlayContainer.update(layout: layout, transition: containerTransition)
|
overlayContainer.update(layout: overlayContainerLayout, transition: containerTransition)
|
||||||
|
|
||||||
modalStyleOverlayTransitionFactor = max(modalStyleOverlayTransitionFactor, overlayContainer.controller.modalStyleOverlayTransitionFactor)
|
modalStyleOverlayTransitionFactor = max(modalStyleOverlayTransitionFactor, overlayContainer.controller.modalStyleOverlayTransitionFactor)
|
||||||
|
|
||||||
@ -586,7 +588,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
|||||||
var previousModalContainer: NavigationModalContainer?
|
var previousModalContainer: NavigationModalContainer?
|
||||||
var visibleModalCount = 0
|
var visibleModalCount = 0
|
||||||
var topModalIsFlat = false
|
var topModalIsFlat = false
|
||||||
var isLandscape = layout.orientation == .landscape
|
let isLandscape = layout.orientation == .landscape
|
||||||
var hasVisibleStandaloneModal = false
|
var hasVisibleStandaloneModal = false
|
||||||
var topModalDismissProgress: CGFloat = 0.0
|
var topModalDismissProgress: CGFloat = 0.0
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
|||||||
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
|
dict[-309990731] = { return Api.Update.parse_updatePinnedMessages($0) }
|
||||||
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
|
dict[-2054649973] = { return Api.Update.parse_updatePinnedChannelMessages($0) }
|
||||||
dict[-219423922] = { return Api.Update.parse_updateGroupCallParticipants($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[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
|
||||||
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
||||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||||
|
@ -6346,7 +6346,7 @@ public extension Api {
|
|||||||
case updatePinnedMessages(flags: Int32, peer: Api.Peer, messages: [Int32], pts: Int32, ptsCount: Int32)
|
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 updatePinnedChannelMessages(flags: Int32, channelId: Int32, messages: [Int32], pts: Int32, ptsCount: Int32)
|
||||||
case updateGroupCallParticipants(call: Api.InputGroupCall, participants: [Api.GroupCallParticipant], version: 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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
@ -7094,10 +7094,11 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
serializeInt32(version, buffer: buffer, boxed: false)
|
serializeInt32(version, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
case .updateGroupCall(let call):
|
case .updateGroupCall(let channelId, let call):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-2046916883)
|
buffer.appendInt32(1462009966)
|
||||||
}
|
}
|
||||||
|
serializeInt32(channelId, buffer: buffer, boxed: false)
|
||||||
call.serialize(buffer, true)
|
call.serialize(buffer, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -7277,8 +7278,8 @@ public extension Api {
|
|||||||
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
return ("updatePinnedChannelMessages", [("flags", flags), ("channelId", channelId), ("messages", messages), ("pts", pts), ("ptsCount", ptsCount)])
|
||||||
case .updateGroupCallParticipants(let call, let participants, let version):
|
case .updateGroupCallParticipants(let call, let participants, let version):
|
||||||
return ("updateGroupCallParticipants", [("call", call), ("participants", participants), ("version", version)])
|
return ("updateGroupCallParticipants", [("call", call), ("participants", participants), ("version", version)])
|
||||||
case .updateGroupCall(let call):
|
case .updateGroupCall(let channelId, let call):
|
||||||
return ("updateGroupCall", [("call", call)])
|
return ("updateGroupCall", [("channelId", channelId), ("call", call)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8773,13 +8774,16 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static func parse_updateGroupCall(_ reader: BufferReader) -> Update? {
|
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() {
|
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
|
let _c1 = _1 != nil
|
||||||
if _c1 {
|
let _c2 = _2 != nil
|
||||||
return Api.Update.updateGroupCall(call: _1!)
|
if _c1 && _c2 {
|
||||||
|
return Api.Update.updateGroupCall(channelId: _1!, call: _2!)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -32,6 +32,15 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
var presentationAudioLevel: CGFloat = 0.0
|
var presentationAudioLevel: CGFloat = 0.0
|
||||||
var phase: CGFloat = 0.0
|
var phase: CGFloat = 0.0
|
||||||
|
|
||||||
|
var transitionArguments: (Double, Double)?
|
||||||
|
var speaking = false {
|
||||||
|
didSet {
|
||||||
|
if self.speaking != oldValue {
|
||||||
|
self.transitionArguments = (CACurrentMediaTime(), 0.3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var animator: ConstantDisplayLinkAnimator?
|
private var animator: ConstantDisplayLinkAnimator?
|
||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
@ -61,7 +70,7 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
override public func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
|
||||||
return CallStatusBarBackgroundNodeDrawingState(timestamp: CACurrentMediaTime(), amplitude: self.presentationAudioLevel, phase: self.phase, speaking: false, transitionArguments: nil)
|
return CallStatusBarBackgroundNodeDrawingState(timestamp: CACurrentMediaTime(), amplitude: self.presentationAudioLevel, phase: self.phase, speaking: self.speaking, transitionArguments: self.transitionArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
@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) {
|
||||||
@ -96,7 +105,7 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
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 position: CGFloat = bounds.height - 6.0
|
||||||
let maxAmplitude: CGFloat = 8.0
|
let maxAmplitude: CGFloat = 12.0
|
||||||
|
|
||||||
let amplitude = max(0.35, parameters.amplitude)
|
let amplitude = max(0.35, parameters.amplitude)
|
||||||
|
|
||||||
@ -126,7 +135,7 @@ private class CallStatusBarBackgroundNode: ASDisplayNode {
|
|||||||
context.clip()
|
context.clip()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in (0 ..< 2).reversed() {
|
for i in (0 ..< 3).reversed() {
|
||||||
let progress = 1.0 - CGFloat(i) / 3.0
|
let progress = 1.0 - CGFloat(i) / 3.0
|
||||||
var normalizedAmplitude = (1.5 * progress - 0.8) * amplitude
|
var normalizedAmplitude = (1.5 * progress - 0.8) * amplitude
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
@ -255,7 +264,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
|
|||||||
if !strongSelf.currentIsMuted {
|
if !strongSelf.currentIsMuted {
|
||||||
effectiveLevel = level
|
effectiveLevel = level
|
||||||
}
|
}
|
||||||
strongSelf.backgroundNode.audioLevel = effectiveLevel
|
strongSelf.backgroundNode.audioLevel = max(0.0, min(1.0, effectiveLevel / 8.0))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
self.didSetupData = true
|
self.didSetupData = true
|
||||||
@ -297,6 +306,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.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.speaking = !self.currentIsMuted
|
||||||
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 7.0))
|
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 7.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,14 +211,13 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
|
|||||||
|
|
||||||
self.separatorNode.backgroundColor = presentationData.theme.chat.historyNavigation.strokeColor
|
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)
|
self.joinButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: presentationData.theme.chat.inputPanel.actionControlFillColor)
|
||||||
|
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
self.micButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 36.0, color: UIColor(rgb: 0x30b251))
|
self.micButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 36.0, color: UIColor(rgb: 0x30b251))
|
||||||
|
|
||||||
//TODO:localize
|
self.titleNode.attributedText = NSAttributedString(string: presentationData.strings.VoiceChat_Title, font: Font.semibold(15.0), textColor: presentationData.theme.chat.inputPanel.primaryTextColor)
|
||||||
self.titleNode.attributedText = NSAttributedString(string: "Voice Chat", 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.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)
|
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme)
|
||||||
|
@ -168,9 +168,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
|> map { value -> Bool in
|
|> map { value -> Bool in
|
||||||
switch value {
|
switch value {
|
||||||
case let .muted(isPushToTalkActive):
|
case let .muted(isPushToTalkActive):
|
||||||
return isPushToTalkActive
|
return !isPushToTalkActive
|
||||||
case .unmuted:
|
case .unmuted:
|
||||||
return true
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -488,10 +488,9 @@ public final class VoiceChatController: ViewController {
|
|||||||
strongSelf.currentCallMembers = callMembers.participants
|
strongSelf.currentCallMembers = callMembers.participants
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, 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: strongSelf.presentationData.strings.VoiceChat_Title, subtitle: subtitle)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -760,13 +759,12 @@ public final class VoiceChatController: ViewController {
|
|||||||
|
|
||||||
@objc private func actionButtonPressed() {
|
@objc private func actionButtonPressed() {
|
||||||
if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
|
if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
|
||||||
|
self.hapticFeedback.error()
|
||||||
|
self.actionButton.layer.addShakeAnimation()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.hapticFeedback.error()
|
self.call.toggleIsMuted()
|
||||||
self.actionButton.layer.addShakeAnimation()
|
|
||||||
// self.call.toggleIsMuted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func audioOutputPressed() {
|
@objc private func audioOutputPressed() {
|
||||||
|
@ -111,7 +111,7 @@ enum AccountStateMutationOperation {
|
|||||||
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
|
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
|
||||||
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
|
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
|
||||||
case UpdateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32)
|
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 {
|
struct HoleFromPreviousState {
|
||||||
@ -282,8 +282,8 @@ struct AccountMutableState {
|
|||||||
self.addOperation(.UpdateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version))
|
self.addOperation(.UpdateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version))
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func updateGroupCall(call: Api.GroupCall) {
|
mutating func updateGroupCall(peerId: PeerId, call: Api.GroupCall) {
|
||||||
self.addOperation(.UpdateGroupCall(call: call))
|
self.addOperation(.UpdateGroupCall(peerId: peerId, call: call))
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {
|
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {
|
||||||
|
@ -1332,8 +1332,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
|||||||
case let .inputGroupCall(id, accessHash):
|
case let .inputGroupCall(id, accessHash):
|
||||||
updatedState.updateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version)
|
updatedState.updateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version)
|
||||||
}
|
}
|
||||||
case let .updateGroupCall(call):
|
case let .updateGroupCall(channelId, call):
|
||||||
updatedState.updateGroupCall(call: call)
|
updatedState.updateGroupCall(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId), call: call)
|
||||||
case let .updateLangPackTooLong(langCode):
|
case let .updateLangPackTooLong(langCode):
|
||||||
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
||||||
case let .updateLangPack(difference):
|
case let .updateLangPack(difference):
|
||||||
@ -2959,15 +2959,35 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
|||||||
callId,
|
callId,
|
||||||
.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version))
|
.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version))
|
||||||
))
|
))
|
||||||
case let .UpdateGroupCall(call):
|
case let .UpdateGroupCall(peerId, call):
|
||||||
switch call {
|
switch call {
|
||||||
case .groupCall:
|
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, _, _):
|
case let .groupCallDiscarded(callId, _, _):
|
||||||
updatedGroupCallParticipants.append((
|
updatedGroupCallParticipants.append((
|
||||||
callId,
|
callId,
|
||||||
.call(isTerminated: true)
|
.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):
|
case let .UpdateLangPack(langCode, difference):
|
||||||
if let difference = difference {
|
if let difference = difference {
|
||||||
|
@ -28,7 +28,7 @@ public struct GroupCallSummary: Equatable {
|
|||||||
public var topParticipants: [GroupCallParticipantsContext.Participant]
|
public var topParticipants: [GroupCallParticipantsContext.Participant]
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension GroupCallInfo {
|
extension GroupCallInfo {
|
||||||
init?(_ call: Api.GroupCall) {
|
init?(_ call: Api.GroupCall) {
|
||||||
switch call {
|
switch call {
|
||||||
case let .groupCall(_, id, accessHash, participantCount, params, _):
|
case let .groupCall(_, id, accessHash, participantCount, params, _):
|
||||||
@ -142,7 +142,7 @@ public func createGroupCall(account: Account, peerId: PeerId) -> Signal<GroupCal
|
|||||||
var parsedCall: GroupCallInfo?
|
var parsedCall: GroupCallInfo?
|
||||||
loop: for update in result.allUpdates {
|
loop: for update in result.allUpdates {
|
||||||
switch update {
|
switch update {
|
||||||
case let .updateGroupCall(call):
|
case let .updateGroupCall(_, call):
|
||||||
parsedCall = GroupCallInfo(call)
|
parsedCall = GroupCallInfo(call)
|
||||||
break loop
|
break loop
|
||||||
default:
|
default:
|
||||||
@ -316,7 +316,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
|||||||
var maybeParsedCall: GroupCallInfo?
|
var maybeParsedCall: GroupCallInfo?
|
||||||
loop: for update in updates.allUpdates {
|
loop: for update in updates.allUpdates {
|
||||||
switch update {
|
switch update {
|
||||||
case let .updateGroupCall(call):
|
case let .updateGroupCall(_, call):
|
||||||
maybeParsedCall = GroupCallInfo(call)
|
maybeParsedCall = GroupCallInfo(call)
|
||||||
break loop
|
break loop
|
||||||
default:
|
default:
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -133,9 +133,16 @@ public final class SharedWakeupManager {
|
|||||||
return call?.account.id == account.id
|
return call?.account.id == account.id
|
||||||
}
|
}
|
||||||
|> distinctUntilChanged
|
|> distinctUntilChanged
|
||||||
let isPlayingBackgroundActiveCall = combineLatest(queue: .mainQueue(), hasActiveCalls, hasActiveAudioSession)
|
|
||||||
|> map { hasActiveCalls, hasActiveAudioSession -> Bool in
|
let hasActiveGroupCalls = (callManager?.currentGroupCallSignal ?? .single(nil))
|
||||||
return hasActiveCalls && hasActiveAudioSession
|
|> 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
|
|> distinctUntilChanged
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user