mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '82ff76bb694e994f668a8c371f14167408246063'
This commit is contained in:
commit
d1d533a443
@ -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<Set<PeerId>, NoError> { get }
|
||||
}
|
||||
|
||||
public protocol PresentationCallManager: class {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import <FFMpegBinding/FFMpegGlobals.h>
|
||||
#import <FFMpegBinding/FFMpegAVCodecContext.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import UIKit
|
||||
import CoreMedia
|
||||
import Accelerate
|
||||
import FFMpegBinding
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
@ -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 {
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,6 +158,18 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
return self.membersPromise.get()
|
||||
}
|
||||
|
||||
private var invitedPeersValue: Set<PeerId> = Set() {
|
||||
didSet {
|
||||
if self.invitedPeersValue != oldValue {
|
||||
self.inivitedPeersPromise.set(self.invitedPeersValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
private let inivitedPeersPromise = ValuePromise<Set<PeerId>>(Set())
|
||||
public var invitedPeers: Signal<Set<PeerId>, 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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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<PeerId>?
|
||||
|
||||
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
|
||||
@ -390,6 +404,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<PeerId>) {
|
||||
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
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit b245c575f350e13186d34b9ae38f6af555c6fe14
|
||||
Subproject commit aeaa63b502a1ee88feef282af739980001138993
|
Loading…
x
Reference in New Issue
Block a user