diff --git a/submodules/AccountContext/Sources/PresentationCallManager.swift b/submodules/AccountContext/Sources/PresentationCallManager.swift index ea702ea805..77db807fc1 100644 --- a/submodules/AccountContext/Sources/PresentationCallManager.swift +++ b/submodules/AccountContext/Sources/PresentationCallManager.swift @@ -227,7 +227,11 @@ public protocol PresentationGroupCall: class { func toggleIsMuted() func setIsMuted(_ value: Bool) func setCurrentAudioOutput(_ output: AudioSessionOutput) + func updateMuteState(peerId: PeerId, isMuted: Bool) + + func invitePeer(_ peerId: PeerId) + var invitedPeers: Signal, NoError> { get } } public protocol PresentationCallManager: class { diff --git a/submodules/FFMpegBinding/Public/FFMpegBinding/FFMpegBinding.h b/submodules/FFMpegBinding/Public/FFMpegBinding/FFMpegBinding.h index 565c6c170a..f6ae7d835e 100644 --- a/submodules/FFMpegBinding/Public/FFMpegBinding/FFMpegBinding.h +++ b/submodules/FFMpegBinding/Public/FFMpegBinding/FFMpegBinding.h @@ -1,4 +1,4 @@ -#import +#import #import #import diff --git a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift index a6be0700ae..14c0330554 100644 --- a/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift +++ b/submodules/MediaPlayer/Sources/FFMpegMediaVideoFrameDecoder.swift @@ -1,3 +1,4 @@ +import UIKit import CoreMedia import Accelerate import FFMpegBinding diff --git a/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift index 2f558786f0..a39362849d 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerFramePreview.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import SwiftSignalKit import Postbox import TelegramCore diff --git a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift index de74237eac..e76e15b0b5 100644 --- a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift +++ b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import SwiftSignalKit import Postbox import TelegramCore diff --git a/submodules/Postbox/Sources/MessageHistoryView.swift b/submodules/Postbox/Sources/MessageHistoryView.swift index 1753b2764b..71b6869b36 100644 --- a/submodules/Postbox/Sources/MessageHistoryView.swift +++ b/submodules/Postbox/Sources/MessageHistoryView.swift @@ -667,8 +667,12 @@ final class MutableMessageHistoryView { var updatedCachedPeerDataMessages = false var currentCachedPeerData: CachedPeerData? - for i in 0 ..< self.additionalDatas.count { - switch self.additionalDatas[i] { + + let additionalDatas = self.additionalDatas + var updated = self.additionalDatas + + for i in 0 ..< additionalDatas.count { + switch additionalDatas[i] { case let .cachedPeerData(peerId, currentData): currentCachedPeerData = currentData if let updatedData = transaction.currentUpdatedCachedPeerData[peerId] { @@ -676,7 +680,7 @@ final class MutableMessageHistoryView { updatedCachedPeerDataMessages = true } currentCachedPeerData = updatedData - self.additionalDatas[i] = .cachedPeerData(peerId, updatedData) + updated[i] = .cachedPeerData(peerId, updatedData) hasChanges = true } case .cachedPeerDataMessages: @@ -729,13 +733,13 @@ final class MutableMessageHistoryView { } if updateMessage { let messages = postbox.getMessageGroup(at: id) ?? [] - self.additionalDatas[i] = .message(id, messages) + updated[i] = .message(id, messages) hasChanges = true } } case let .peerChatState(peerId, _): if transaction.currentUpdatedPeerChatStates.contains(peerId) { - self.additionalDatas[i] = .peerChatState(peerId, postbox.peerChatStateTable.get(peerId) as? PeerChatState) + updated[i] = .peerChatState(peerId, postbox.peerChatStateTable.get(peerId) as? PeerChatState) hasChanges = true } case .totalUnreadState: @@ -744,7 +748,7 @@ final class MutableMessageHistoryView { break case let .cacheEntry(entryId, _): if transaction.updatedCacheEntryKeys.contains(entryId) { - self.additionalDatas[i] = .cacheEntry(entryId, postbox.retrieveItemCacheEntry(id: entryId)) + updated[i] = .cacheEntry(entryId, postbox.retrieveItemCacheEntry(id: entryId)) hasChanges = true } case .preferencesEntry: @@ -759,20 +763,20 @@ final class MutableMessageHistoryView { } if value != updatedValue { - self.additionalDatas[i] = .peerIsContact(peerId, value) + updated[i] = .peerIsContact(peerId, value) hasChanges = true } } case let .peer(peerId, _): if let peer = transaction.currentUpdatedPeers[peerId] { - self.additionalDatas[i] = .peer(peerId, peer) + updated[i] = .peer(peerId, peer) hasChanges = true } } } if let cachedData = currentCachedPeerData, !cachedData.messageIds.isEmpty { - for i in 0 ..< self.additionalDatas.count { - switch self.additionalDatas[i] { + for i in 0 ..< additionalDatas.count { + switch additionalDatas[i] { case .cachedPeerDataMessages(_, _): outer: for operationSet in operations { for operation in operationSet { @@ -802,8 +806,8 @@ final class MutableMessageHistoryView { if updatedCachedPeerDataMessages { hasChanges = true - for i in 0 ..< self.additionalDatas.count { - switch self.additionalDatas[i] { + for i in 0 ..< additionalDatas.count { + switch additionalDatas[i] { case let .cachedPeerDataMessages(peerId, _): var messages: [MessageId: Message] = [:] if let cachedData = currentCachedPeerData { @@ -813,13 +817,15 @@ final class MutableMessageHistoryView { } } } - self.additionalDatas[i] = .cachedPeerDataMessages(peerId, messages) + updated[i] = .cachedPeerDataMessages(peerId, messages) default: break } } } + self.additionalDatas = updated + if !transaction.currentPeerHoleOperations.isEmpty { var holePeerIdsSet: [PeerId] = [] switch self.peerIds { diff --git a/submodules/SyncCore/Sources/TelegramMediaAction.swift b/submodules/SyncCore/Sources/TelegramMediaAction.swift index 517f672dbd..ee07f97508 100644 --- a/submodules/SyncCore/Sources/TelegramMediaAction.swift +++ b/submodules/SyncCore/Sources/TelegramMediaAction.swift @@ -207,7 +207,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { encoder.encodeInt32(23, forKey: "_rawValue") encoder.encodeInt64(callId, forKey: "callId") encoder.encodeInt64(accessHash, forKey: "accessHash") - encoder.encodeInt64(peerId.toInt64(), forKey: "peerIdId") + encoder.encodeInt64(peerId.toInt64(), forKey: "peerId") } } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 74cd2d8671..1d65729a5c 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -158,6 +158,18 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { return self.membersPromise.get() } + private var invitedPeersValue: Set = Set() { + didSet { + if self.invitedPeersValue != oldValue { + self.inivitedPeersPromise.set(self.invitedPeersValue) + } + } + } + private let inivitedPeersPromise = ValuePromise>(Set()) + public var invitedPeers: Signal, NoError> { + return self.inivitedPeersPromise.get() + } + private let requestDisposable = MetaDisposable() private var groupCallParticipantUpdatesDisposable: Disposable? @@ -641,4 +653,16 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl) })) } + + public func invitePeer(_ peerId: PeerId) { + guard case let .estabilished(callInfo, _, _, _) = self.internalState, !self.invitedPeersValue.contains(peerId) else { + return + } + + var updatedInvitedPeers = self.invitedPeersValue + updatedInvitedPeers.insert(peerId) + self.invitedPeersValue = updatedInvitedPeers + + let _ = inviteToGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, peerId: peerId).start() + } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index af8f5ec34d..970cec0cea 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -88,11 +88,11 @@ private final class Blob { } } - var currentShape: CGPath? + var currentShape: UIBezierPath? private var transition: CGFloat = 0 { didSet { if let currentPoints = self.currentPoints { - self.currentShape = UIBezierPath.smoothCurve(through: currentPoints, length: size.width, smoothness: smoothness).cgPath + self.currentShape = UIBezierPath.smoothCurve(through: currentPoints, length: size.width, smoothness: smoothness) } } } @@ -450,7 +450,6 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode { let buttonSize = CGSize(width: 144.0, height: 144.0) let radius = buttonSize.width / 2.0 - let blue = UIColor(rgb: 0x0078ff) let lightBlue = UIColor(rgb: 0x59c7f8) let green = UIColor(rgb: 0x33c659) @@ -511,8 +510,7 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode { context.saveGState() if let blobsState = parameters.state as? VoiceChatActionButtonBackgroundNodeBlobState { for blob in blobsState.blobs { - if let path = blob.currentShape { - let uiPath = UIBezierPath(cgPath: path) + if let path = blob.currentShape, let uiPath = path.copy() as? UIBezierPath { let toOrigin = CGAffineTransform(translationX: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0) let fromOrigin = CGAffineTransform(translationX: bounds.size.width / 2.0, y: bounds.size.height / 2.0) diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index ce94f1f31d..743b4b8b96 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -142,6 +142,7 @@ public final class VoiceChatController: ViewController { var activityTimestamp: Int32 var state: State var muteState: GroupCallParticipantsContext.Participant.MuteState? + var invited: Bool var stableId: PeerId { return self.peer.id @@ -163,6 +164,9 @@ public final class VoiceChatController: ViewController { if lhs.muteState != rhs.muteState { return false } + if lhs.invited != rhs.invited { + return false + } return true } @@ -181,7 +185,7 @@ public final class VoiceChatController: ViewController { switch self.state { case .inactive: text = .presence - icon = .invite + icon = .invite(self.invited) case .listening: text = .text(presentationData.strings.VoiceChat_StatusListening, .accent) let microphoneColor: UIColor @@ -241,6 +245,7 @@ public final class VoiceChatController: ViewController { private var currentMembers: [RenderedChannelParticipant]? private var currentMemberStates: [PeerId: PresentationGroupCallMemberState]? + private var currentInvitedPeers: Set? private var currentEntries: [PeerEntry] = [] private var peersDisposable: Disposable? @@ -261,6 +266,7 @@ public final class VoiceChatController: ViewController { private var audioLevelsDisposable: Disposable? private var myAudioLevelDisposable: Disposable? private var memberStatesDisposable: Disposable? + private var invitedPeersDisposable: Disposable? private var itemInteraction: Interaction? @@ -295,6 +301,10 @@ public final class VoiceChatController: ViewController { return } + if let invitedPeers = strongSelf.currentInvitedPeers, invitedPeers.contains(peer.id) { + return + } + strongSelf.controller?.present( UndoOverlayController( presentationData: strongSelf.presentationData, @@ -310,6 +320,7 @@ public final class VoiceChatController: ViewController { ), in: .current ) + strongSelf.call.invitePeer(peer.id) } self.itemInteraction = Interaction( @@ -327,12 +338,15 @@ public final class VoiceChatController: ViewController { var items: [ContextMenuItem] = [] switch entry.state { case .inactive: - items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_InvitePeer, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.actionSheet.primaryTextColor) - }, action: { _, f in - invitePeer(peer) - f(.default) - }))) + if let invitedPeers = strongSelf.currentInvitedPeers, invitedPeers.contains(peer.id) { + } else { + items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_InvitePeer, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.actionSheet.primaryTextColor) + }, action: { _, f in + invitePeer(peer) + f(.default) + }))) + } default: if entry.muteState == nil { items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_MutePeer, icon: { theme in @@ -389,6 +403,10 @@ public final class VoiceChatController: ViewController { }))) } } + + guard !items.isEmpty else { + return + } let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme), source: .extracted(VoiceChatContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(items), reactionItems: [], gesture: gesture) strongSelf.controller?.presentInGlobalOverlay(contextController) @@ -406,7 +424,7 @@ public final class VoiceChatController: ViewController { guard let strongSelf = self else { return } - strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: state.list, memberStates: strongSelf.currentMemberStates ?? [:]) + strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: state.list, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } }) @@ -416,12 +434,24 @@ public final class VoiceChatController: ViewController { return } if let members = strongSelf.currentMembers { - strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: members, memberStates: memberStates) + strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: members, memberStates: memberStates, invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } else { strongSelf.currentMemberStates = memberStates } }) + self.invitedPeersDisposable = (self.call.invitedPeers + |> deliverOnMainQueue).start(next: { [weak self] invitedPeers in + guard let strongSelf = self else { + return + } + if let members = strongSelf.currentMembers { + strongSelf.updateMembers(isMuted: strongSelf.callState?.isMuted ?? true, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: invitedPeers) + } else { + strongSelf.currentInvitedPeers = invitedPeers + } + }) + self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in guard let strongSelf = self else { return @@ -470,7 +500,7 @@ public final class VoiceChatController: ViewController { strongSelf.callState = state if wasMuted != state.isMuted, let members = strongSelf.currentMembers { - strongSelf.updateMembers(isMuted: state.isMuted, members: members, memberStates: strongSelf.currentMemberStates ?? [:]) + strongSelf.updateMembers(isMuted: state.isMuted, members: members, memberStates: strongSelf.currentMemberStates ?? [:], invitedPeers: strongSelf.currentInvitedPeers ?? Set()) } if let (layout, navigationHeight) = strongSelf.validLayout { @@ -568,6 +598,7 @@ public final class VoiceChatController: ViewController { self.callStateDisposable?.dispose() self.audioOutputStateDisposable?.dispose() self.memberStatesDisposable?.dispose() + self.invitedPeersDisposable?.dispose() self.audioLevelsDisposable?.dispose() self.myAudioLevelDisposable?.dispose() } @@ -576,7 +607,7 @@ public final class VoiceChatController: ViewController { super.didLoad() let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:))) - longTapRecognizer.minimumPressDuration = 0.01 + longTapRecognizer.minimumPressDuration = 0.1 self.actionButton.view.addGestureRecognizer(longTapRecognizer) let panRecognizer = CallPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))) @@ -716,6 +747,7 @@ public final class VoiceChatController: ViewController { let actionButtonTitle: String let actionButtonSubtitle: String let audioButtonAppearance: CallControllerButtonItemNode.Content.Appearance + var actionButtonEnabled = true if let callState = callState { isMicOn = !callState.isMuted @@ -725,6 +757,7 @@ public final class VoiceChatController: ViewController { actionButtonTitle = self.presentationData.strings.VoiceChat_Connecting actionButtonSubtitle = "" audioButtonAppearance = .color(.custom(0x1c1c1e)) + actionButtonEnabled = false case .connected: actionButtonState = .active(state: isMicOn ? .on : .muted) if isMicOn { @@ -742,8 +775,10 @@ public final class VoiceChatController: ViewController { actionButtonTitle = self.presentationData.strings.VoiceChat_Connecting actionButtonSubtitle = "" audioButtonAppearance = .color(.custom(0x1c1c1e)) + actionButtonEnabled = false } + self.actionButton.isUserInteractionEnabled = actionButtonEnabled self.actionButton.update(size: centralButtonSize, buttonSize: CGSize(width: 144.0, height: 144.0), state: actionButtonState, title: actionButtonTitle, subtitle: actionButtonSubtitle, animated: true) transition.updateFrame(node: self.actionButton, frame: actionButtonFrame) @@ -780,7 +815,7 @@ public final class VoiceChatController: ViewController { soundImage = .speaker case .speaker: soundImage = .speaker -// soundAppearance = .blurred(isFilled: false) + soundAppearance = .blurred(isFilled: true) case .headphones: soundImage = .bluetooth case let .bluetooth(type): @@ -881,7 +916,7 @@ public final class VoiceChatController: ViewController { }) } - private func updateMembers(isMuted: Bool, members: [RenderedChannelParticipant], memberStates: [PeerId: PresentationGroupCallMemberState]) { + private func updateMembers(isMuted: Bool, members: [RenderedChannelParticipant], memberStates: [PeerId: PresentationGroupCallMemberState], invitedPeers: Set) { var members = members members.sort(by: { lhs, rhs in if lhs.peer.id == self.context.account.peerId { @@ -903,6 +938,7 @@ public final class VoiceChatController: ViewController { self.currentMembers = members self.currentMemberStates = memberStates + self.currentInvitedPeers = invitedPeers let previousEntries = self.currentEntries var entries: [PeerEntry] = [] @@ -931,9 +967,11 @@ public final class VoiceChatController: ViewController { entries.append(PeerEntry( peer: member.peer, + presence: member.presences[member.peer.id] as? TelegramUserPresence, activityTimestamp: Int32.max - 1 - index, state: memberState, - muteState: memberMuteState + muteState: memberMuteState, + invited: invitedPeers.contains(member.peer.id) )) index += 1 } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index f89f08cc08..3f4715c540 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -34,7 +34,7 @@ public final class VoiceChatParticipantItem: ListViewItem { public enum Icon { case none case microphone(Bool, UIColor) - case invite + case invite(Bool) } let presentationData: ItemListPresentationData @@ -134,7 +134,8 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { private let actionContainerNode: ASDisplayNode private var animationNode: VoiceChatMicrophoneNode? - private var actionButtonNode: HighlightableButtonNode? + private var iconNode: ASImageNode? + private var actionButtonNode: HighlightTrackingButtonNode private var audioLevelView: VoiceBlobView? private let audioLevelDisposable = MetaDisposable() @@ -181,6 +182,7 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { self.statusNode.contentsScale = UIScreen.main.scale self.actionContainerNode = ASDisplayNode() + self.actionButtonNode = HighlightTrackingButtonNode() self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode.isLayerBacked = true @@ -199,8 +201,11 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { self.offsetContainerNode.addSubnode(self.titleNode) self.offsetContainerNode.addSubnode(self.statusNode) self.offsetContainerNode.addSubnode(self.actionContainerNode) + self.actionContainerNode.addSubnode(self.actionButtonNode) self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode + self.actionButtonNode.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside) + self.peerPresenceManager = PeerPresenceStatusManager(update: { [weak self] in if let strongSelf = self, let layoutParams = strongSelf.layoutParams { let (_, apply) = strongSelf.asyncLayout()(layoutParams.0, layoutParams.1, layoutParams.2, layoutParams.3) @@ -212,7 +217,7 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { guard let strongSelf = self else { return false } - if let actionButtonNode = strongSelf.actionButtonNode, actionButtonNode.frame.contains(location) { + if strongSelf.actionButtonNode.frame.contains(location) { return false } return true @@ -345,8 +350,8 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { let verticalOffset: CGFloat = 0.0 let avatarSize: CGFloat = 40.0 - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) - let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 25.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 25.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let insets = UIEdgeInsets() @@ -547,7 +552,7 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { } else { animationNode = VoiceChatMicrophoneNode() strongSelf.animationNode = animationNode - strongSelf.actionContainerNode.addSubnode(animationNode) + strongSelf.actionButtonNode.addSubnode(animationNode) } animationNode.update(state: VoiceChatMicrophoneNode.State(muted: muted, color: color), animated: true) } else if let animationNode = strongSelf.animationNode { @@ -557,29 +562,34 @@ public class VoiceChatParticipantItemNode: ListViewItemNode { }) } - if case .invite = item.icon { - let actionButtonNode: HighlightableButtonNode - if let current = strongSelf.actionButtonNode { - actionButtonNode = current + if case let .invite(invited) = item.icon { + let iconNode: ASImageNode + if let current = strongSelf.iconNode { + iconNode = current } else { - actionButtonNode = HighlightableButtonNode() - actionButtonNode.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: item.presentationData.theme.list.itemAccentColor), for: .normal) - actionButtonNode.addTarget(strongSelf, action: #selector(strongSelf.actionButtonPressed), forControlEvents: .touchUpInside) - - strongSelf.actionButtonNode = actionButtonNode - strongSelf.actionContainerNode.addSubnode(actionButtonNode) + iconNode = ASImageNode() + iconNode.contentMode = .center + strongSelf.iconNode = iconNode + strongSelf.actionButtonNode.addSubnode(iconNode) } - } else if let actionButtonNode = strongSelf.actionButtonNode { - strongSelf.actionButtonNode = nil - actionButtonNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak actionButtonNode] _ in - actionButtonNode?.removeFromSupernode() + + if invited { + iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Call/Context Menu/Invited"), color: UIColor(rgb: 0x979797)) + } else { + iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: item.presentationData.theme.list.itemAccentColor) + } + } else if let iconNode = strongSelf.iconNode { + strongSelf.iconNode = nil + iconNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak iconNode] _ in + iconNode?.removeFromSupernode() }) } let animationSize = CGSize(width: 36.0, height: 36.0) - strongSelf.animationNode?.frame = CGRect(x: params.width - animationSize.width - 6.0, y: floor((layout.contentSize.height - animationSize.height) / 2.0) + 1.0, width: animationSize.width, height: animationSize.height) + strongSelf.iconNode?.frame = CGRect(origin: CGPoint(), size: animationSize) + strongSelf.animationNode?.frame = CGRect(origin: CGPoint(), size: animationSize) - strongSelf.actionButtonNode?.frame = CGRect(x: params.width - animationSize.width - 6.0, y: floor((layout.contentSize.height - animationSize.height) / 2.0) + 1.0, width: animationSize.width, height: animationSize.height) + strongSelf.actionButtonNode.frame = CGRect(x: params.width - animationSize.width - 6.0, y: floor((layout.contentSize.height - animationSize.height) / 2.0) + 1.0, width: animationSize.width, height: animationSize.height) if let presence = item.presence as? TelegramUserPresence { strongSelf.peerPresenceManager?.reset(presence: presence) diff --git a/submodules/TelegramCore/Sources/Holes.swift b/submodules/TelegramCore/Sources/Holes.swift index beca7c99ba..22b6be9ed8 100644 --- a/submodules/TelegramCore/Sources/Holes.swift +++ b/submodules/TelegramCore/Sources/Holes.swift @@ -614,7 +614,7 @@ func fetchChatListHole(postbox: Postbox, network: Network, accountPeerId: PeerId for peerId in fetchedChats.chatPeerIds { if let peer = transaction.getPeer(peerId) { - transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: nil, minTimestamp: minTimestampForPeerInclusion(peer))) + transaction.updatePeerChatListInclusion(peerId, inclusion: .ifHasMessagesOrOneOf(groupId: groupId, pinningIndex: transaction.getPeerChatListIndex(peerId)?.1.pinningIndex, minTimestamp: minTimestampForPeerInclusion(peer))) } else { assertionFailure() } diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index b245c575f3..aeaa63b502 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit b245c575f350e13186d34b9ae38f6af555c6fe14 +Subproject commit aeaa63b502a1ee88feef282af739980001138993