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
5f6f1de1d3
@ -961,7 +961,6 @@ private final class NotificationServiceHandler {
|
||||
|
||||
if let locKey = payloadJson["loc-key"] as? String, (locKey == "CONF_CALL_REQUEST" || locKey == "CONF_CALL_MISSED"), let callIdString = payloadJson["call_id"] as? String {
|
||||
if let callId = Int64(callIdString) {
|
||||
|
||||
if let updates = payloadJson["updates"] as? String {
|
||||
var updateString = updates
|
||||
updateString = updateString.replacingOccurrences(of: "-", with: "+")
|
||||
|
@ -487,6 +487,7 @@ public protocol PresentationGroupCall: AnyObject {
|
||||
func updateTitle(_ title: String)
|
||||
|
||||
func invitePeer(_ peerId: EnginePeer.Id, isVideo: Bool) -> Bool
|
||||
func kickPeer(id: EnginePeer.Id)
|
||||
func removedPeer(_ peerId: EnginePeer.Id)
|
||||
var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get }
|
||||
|
||||
|
@ -217,6 +217,12 @@ public final class SharedCallAudioContext {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func switchToSpeakerIfBuiltin() {
|
||||
if case .builtin = self.currentAudioOutputValue {
|
||||
self.setCurrentAudioOutput(.speaker)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class PresentationCallImpl: PresentationCall {
|
||||
@ -1032,6 +1038,8 @@ public final class PresentationCallImpl: PresentationCall {
|
||||
self.conferenceCallImpl = conferenceCall
|
||||
conferenceCall.upgradedConferenceCall = self
|
||||
|
||||
self.sharedAudioContext?.switchToSpeakerIfBuiltin()
|
||||
|
||||
for (peerId, isVideo) in self.pendingInviteToConferencePeerIds {
|
||||
let _ = conferenceCall.invitePeer(peerId, isVideo: isVideo)
|
||||
}
|
||||
|
@ -3986,6 +3986,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
|
||||
public func kickPeer(id: EnginePeer.Id) {
|
||||
if self.isConference {
|
||||
self.removedPeer(id)
|
||||
|
||||
self.e2eContext?.kickPeer(id: id)
|
||||
}
|
||||
}
|
||||
|
||||
public func removedPeer(_ peerId: PeerId) {
|
||||
var updatedInvitedPeers = self.invitedPeersValue
|
||||
updatedInvitedPeers.removeAll(where: { $0.id == peerId})
|
||||
|
@ -15,17 +15,20 @@ final class VideoChatListInviteComponent: Component {
|
||||
let title: String
|
||||
let icon: Icon
|
||||
let theme: PresentationTheme
|
||||
let hasNext: Bool
|
||||
let action: () -> Void
|
||||
|
||||
init(
|
||||
title: String,
|
||||
icon: Icon,
|
||||
theme: PresentationTheme,
|
||||
hasNext: Bool,
|
||||
action: @escaping () -> Void
|
||||
) {
|
||||
self.title = title
|
||||
self.icon = icon
|
||||
self.theme = theme
|
||||
self.hasNext = hasNext
|
||||
self.action = action
|
||||
}
|
||||
|
||||
@ -39,6 +42,9 @@ final class VideoChatListInviteComponent: Component {
|
||||
if lhs.theme !== rhs.theme {
|
||||
return false
|
||||
}
|
||||
if lhs.hasNext != rhs.hasNext {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -52,7 +58,11 @@ final class VideoChatListInviteComponent: Component {
|
||||
private var highlightBackgroundLayer: SimpleLayer?
|
||||
private var highlightBackgroundFrame: CGRect?
|
||||
|
||||
private let separatorLayer: SimpleLayer
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.separatorLayer = SimpleLayer()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.highligthedChanged = { [weak self] isHighlighted in
|
||||
@ -74,6 +84,15 @@ final class VideoChatListInviteComponent: Component {
|
||||
}
|
||||
highlightBackgroundLayer.frame = highlightBackgroundFrame
|
||||
highlightBackgroundLayer.opacity = 1.0
|
||||
if component.hasNext {
|
||||
highlightBackgroundLayer.maskedCorners = []
|
||||
highlightBackgroundLayer.masksToBounds = false
|
||||
highlightBackgroundLayer.cornerRadius = 0.0
|
||||
} else {
|
||||
highlightBackgroundLayer.maskedCorners = [.layerMinXMaxYCorner, .layerMaxXMaxYCorner]
|
||||
highlightBackgroundLayer.masksToBounds = true
|
||||
highlightBackgroundLayer.cornerRadius = 10.0
|
||||
}
|
||||
} else {
|
||||
if let highlightBackgroundLayer = self.highlightBackgroundLayer {
|
||||
self.highlightBackgroundLayer = nil
|
||||
@ -152,7 +171,14 @@ final class VideoChatListInviteComponent: Component {
|
||||
transition.setFrame(view: iconView, frame: iconFrame)
|
||||
}
|
||||
|
||||
//self.highlightBackgroundFrame = CGRect(origin: CGPoint(), size: size)
|
||||
self.highlightBackgroundFrame = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
if self.separatorLayer.superlayer == nil {
|
||||
self.layer.addSublayer(self.separatorLayer)
|
||||
}
|
||||
self.separatorLayer.backgroundColor = component.theme.list.itemBlocksSeparatorColor.cgColor
|
||||
transition.setFrame(layer: self.separatorLayer, frame: CGRect(origin: CGPoint(x: 62.0, y: size.height), size: CGSize(width: size.width - 62.0, height: UIScreenPixel)))
|
||||
self.separatorLayer.isHidden = !component.hasNext
|
||||
|
||||
return size
|
||||
}
|
||||
|
@ -149,6 +149,7 @@ final class VideoChatParticipantsComponent: Component {
|
||||
let safeInsets: UIEdgeInsets
|
||||
let interfaceOrientation: UIInterfaceOrientation
|
||||
let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
|
||||
let openInvitedParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
|
||||
let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void
|
||||
let updateIsMainParticipantPinned: (Bool) -> Void
|
||||
let updateIsExpandedUIHidden: (Bool) -> Void
|
||||
@ -169,6 +170,7 @@ final class VideoChatParticipantsComponent: Component {
|
||||
safeInsets: UIEdgeInsets,
|
||||
interfaceOrientation: UIInterfaceOrientation,
|
||||
openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
|
||||
openInvitedParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
|
||||
updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void,
|
||||
updateIsMainParticipantPinned: @escaping (Bool) -> Void,
|
||||
updateIsExpandedUIHidden: @escaping (Bool) -> Void,
|
||||
@ -188,6 +190,7 @@ final class VideoChatParticipantsComponent: Component {
|
||||
self.safeInsets = safeInsets
|
||||
self.interfaceOrientation = interfaceOrientation
|
||||
self.openParticipantContextMenu = openParticipantContextMenu
|
||||
self.openInvitedParticipantContextMenu = openInvitedParticipantContextMenu
|
||||
self.updateMainParticipant = updateMainParticipant
|
||||
self.updateIsMainParticipantPinned = updateIsMainParticipantPinned
|
||||
self.updateIsExpandedUIHidden = updateIsExpandedUIHidden
|
||||
@ -1317,8 +1320,18 @@ final class VideoChatParticipantsComponent: Component {
|
||||
inset: 2.0,
|
||||
background: UIColor(white: 0.1, alpha: 1.0)
|
||||
),
|
||||
action: nil,
|
||||
contextAction: nil
|
||||
action: { [weak self] peer, _, itemView in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.openInvitedParticipantContextMenu(peer.id, itemView.extractedContainerView, nil)
|
||||
},
|
||||
contextAction: { [weak self] peer, sourceView, gesture in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.openInvitedParticipantContextMenu(peer.id, sourceView, gesture)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -1760,74 +1773,6 @@ final class VideoChatParticipantsComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let measureListItemSize = self.measureListItemView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PeerListItemComponent(
|
||||
context: component.call.accountContext,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
style: .generic,
|
||||
sideInset: 0.0,
|
||||
title: "AAA",
|
||||
peer: nil,
|
||||
subtitle: PeerListItemComponent.Subtitle(text: "bbb", color: .neutral),
|
||||
subtitleAccessory: .none,
|
||||
presence: nil,
|
||||
selectionState: .none,
|
||||
hasNext: true,
|
||||
action: { _, _, _ in
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: 1000.0)
|
||||
)
|
||||
|
||||
var inviteListItemSizes: [CGSize] = []
|
||||
for (inviteOption) in component.participants?.inviteOptions ?? [] {
|
||||
let inviteText: String
|
||||
let iconType: VideoChatListInviteComponent.Icon
|
||||
switch inviteOption.type {
|
||||
case let .invite(isMultiple):
|
||||
//TODO:localize
|
||||
if isMultiple {
|
||||
inviteText = component.strings.VoiceChat_InviteMember
|
||||
} else {
|
||||
inviteText = "Add Member"
|
||||
}
|
||||
iconType = .addUser
|
||||
case .shareLink:
|
||||
inviteText = component.strings.VoiceChat_Share
|
||||
iconType = .link
|
||||
}
|
||||
|
||||
let inviteListItemView: ComponentView<Empty>
|
||||
var inviteListItemTransition = transition
|
||||
if let current = self.inviteListItemViews[inviteOption.id] {
|
||||
inviteListItemView = current
|
||||
} else {
|
||||
inviteListItemView = ComponentView()
|
||||
self.inviteListItemViews[inviteOption.id] = inviteListItemView
|
||||
inviteListItemTransition = inviteListItemTransition.withAnimation(.none)
|
||||
}
|
||||
|
||||
inviteListItemSizes.append(inviteListItemView.update(
|
||||
transition: inviteListItemTransition,
|
||||
component: AnyComponent(VideoChatListInviteComponent(
|
||||
title: inviteText,
|
||||
icon: iconType,
|
||||
theme: component.theme,
|
||||
action: { [weak self] in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.openInviteMembers(inviteOption.type)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: 1000.0)
|
||||
))
|
||||
}
|
||||
|
||||
var gridParticipants: [VideoParticipant] = []
|
||||
var listParticipants: [GroupCallParticipantsContext.Participant] = []
|
||||
if let participants = component.participants {
|
||||
@ -1868,6 +1813,90 @@ final class VideoChatParticipantsComponent: Component {
|
||||
self.gridParticipants = gridParticipants
|
||||
self.listParticipants = listParticipants
|
||||
|
||||
let measureListItemSize = self.measureListItemView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PeerListItemComponent(
|
||||
context: component.call.accountContext,
|
||||
theme: component.theme,
|
||||
strings: component.strings,
|
||||
style: .generic,
|
||||
sideInset: 0.0,
|
||||
title: "AAA",
|
||||
peer: nil,
|
||||
subtitle: PeerListItemComponent.Subtitle(text: "bbb", color: .neutral),
|
||||
subtitleAccessory: .none,
|
||||
presence: nil,
|
||||
selectionState: .none,
|
||||
hasNext: true,
|
||||
action: { _, _, _ in
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: 1000.0)
|
||||
)
|
||||
|
||||
var inviteListItemSizes: [CGSize] = []
|
||||
if let participants = component.participants {
|
||||
let tempItemLayout = ItemLayout(
|
||||
containerSize: availableSize,
|
||||
layout: component.layout,
|
||||
isUIHidden: component.expandedVideoState?.isUIHidden ?? false,
|
||||
expandedInsets: component.expandedInsets,
|
||||
safeInsets: component.safeInsets,
|
||||
gridItemCount: gridParticipants.count,
|
||||
listItemCount: listParticipants.count + component.invitedPeers.count,
|
||||
listItemHeight: measureListItemSize.height,
|
||||
listTrailingItemHeights: []
|
||||
)
|
||||
|
||||
for i in 0 ..< participants.inviteOptions.count {
|
||||
let inviteOption = participants.inviteOptions[i]
|
||||
let inviteText: String
|
||||
let iconType: VideoChatListInviteComponent.Icon
|
||||
switch inviteOption.type {
|
||||
case let .invite(isMultiple):
|
||||
//TODO:localize
|
||||
if isMultiple {
|
||||
inviteText = component.strings.VoiceChat_InviteMember
|
||||
} else {
|
||||
inviteText = "Add Member"
|
||||
}
|
||||
iconType = .addUser
|
||||
case .shareLink:
|
||||
inviteText = component.strings.VoiceChat_Share
|
||||
iconType = .link
|
||||
}
|
||||
|
||||
let inviteListItemView: ComponentView<Empty>
|
||||
var inviteListItemTransition = transition
|
||||
if let current = self.inviteListItemViews[inviteOption.id] {
|
||||
inviteListItemView = current
|
||||
} else {
|
||||
inviteListItemView = ComponentView()
|
||||
self.inviteListItemViews[inviteOption.id] = inviteListItemView
|
||||
inviteListItemTransition = inviteListItemTransition.withAnimation(.none)
|
||||
}
|
||||
|
||||
inviteListItemSizes.append(inviteListItemView.update(
|
||||
transition: inviteListItemTransition,
|
||||
component: AnyComponent(VideoChatListInviteComponent(
|
||||
title: inviteText,
|
||||
icon: iconType,
|
||||
theme: component.theme,
|
||||
hasNext: i != participants.inviteOptions.count - 1,
|
||||
action: { [weak self] in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.openInviteMembers(inviteOption.type)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - tempItemLayout.list.sideInset * 2.0, height: 1000.0)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
let itemLayout = ItemLayout(
|
||||
containerSize: availableSize,
|
||||
layout: component.layout,
|
||||
|
@ -2329,6 +2329,12 @@ final class VideoChatScreenComponent: Component {
|
||||
}
|
||||
self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
|
||||
},
|
||||
openInvitedParticipantContextMenu: { [weak self] id, sourceView, gesture in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openInvitedParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
|
||||
},
|
||||
updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in
|
||||
guard let self else {
|
||||
return
|
||||
|
@ -299,7 +299,11 @@ extension VideoChatScreenComponent.View {
|
||||
}
|
||||
|
||||
let _ = groupCall.accountContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: groupCall.accountContext.engine, peerId: callPeerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start()
|
||||
groupCall.removedPeer(peer.id)
|
||||
if groupCall.isConference {
|
||||
groupCall.kickPeer(id: peer.id)
|
||||
} else {
|
||||
groupCall.removedPeer(peer.id)
|
||||
}
|
||||
|
||||
self.presentUndoOverlay(content: .banned(text: environment.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: environment.strings, displayOrder: nameDisplayOrder)).string), action: { _ in return false })
|
||||
}))
|
||||
@ -347,6 +351,62 @@ extension VideoChatScreenComponent.View {
|
||||
environment.controller()?.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
func openInvitedParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) {
|
||||
guard let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
guard let currentCall = self.currentCall else {
|
||||
return
|
||||
}
|
||||
guard case .group = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
||||
let itemsForEntry: () -> [ContextMenuItem] = { [weak self] in
|
||||
guard let self, let environment = self.environment else {
|
||||
return []
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: environment.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c?.dismiss(result: .dismissWithoutContent, completion: nil)
|
||||
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
||||
groupCall.kickPeer(id: id)
|
||||
})))
|
||||
return items
|
||||
}
|
||||
|
||||
let items = itemsForEntry()
|
||||
|
||||
let presentationData = currentCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
let contextController = ContextController(
|
||||
presentationData: presentationData,
|
||||
source: .extracted(ParticipantExtractedContentSource(contentView: sourceView)),
|
||||
items: .single(ContextController.Items(content: .list(items))),
|
||||
recognizer: nil,
|
||||
gesture: gesture
|
||||
)
|
||||
|
||||
environment.controller()?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismiss()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
environment.controller()?.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
|
||||
guard let currentCall = self.currentCall else {
|
||||
return
|
||||
|
@ -1301,6 +1301,70 @@ public final class AccountViewTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public func refreshInlineGroupCallsForMessageIds(messageIds: Set<MessageId>) {
|
||||
self.queue.async {
|
||||
var addedMessageIds: [MessageId] = []
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent())
|
||||
for messageId in messageIds {
|
||||
let messageTimestamp = self.updatedUnsupportedMediaMessageIdsAndTimestamps[MessageAndThreadId(messageId: messageId, threadId: nil)]
|
||||
var refresh = false
|
||||
if let messageTimestamp = messageTimestamp {
|
||||
refresh = messageTimestamp < timestamp - 60
|
||||
} else {
|
||||
refresh = true
|
||||
}
|
||||
|
||||
if refresh {
|
||||
self.updatedUnsupportedMediaMessageIdsAndTimestamps[MessageAndThreadId(messageId: messageId, threadId: nil)] = timestamp
|
||||
addedMessageIds.append(messageId)
|
||||
}
|
||||
}
|
||||
if !addedMessageIds.isEmpty {
|
||||
for (_, messageIds) in messagesIdsGroupedByPeerId(Set(addedMessageIds)) {
|
||||
let disposableId = self.nextUpdatedUnsupportedMediaDisposableId
|
||||
self.nextUpdatedUnsupportedMediaDisposableId += 1
|
||||
|
||||
if let account = self.account {
|
||||
let signal = account.postbox.transaction { transaction -> [MessageId] in
|
||||
var result: [MessageId] = []
|
||||
for id in messageIds {
|
||||
if let message = transaction.getMessage(id) {
|
||||
for media in message.media {
|
||||
if let _ = media as? TelegramMediaAction {
|
||||
result.append(id)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|> mapToSignal { ids -> Signal<Never, NoError> in
|
||||
guard !ids.isEmpty else {
|
||||
return .complete()
|
||||
}
|
||||
|
||||
var requests: [Signal<Never, NoError>] = []
|
||||
|
||||
for id in ids {
|
||||
requests.append(_internal_refreshInlineGroupCall(account: account, messageId: id))
|
||||
}
|
||||
|
||||
return combineLatest(requests)
|
||||
|> ignoreValues
|
||||
}
|
||||
|> afterDisposed { [weak self] in
|
||||
self?.queue.async {
|
||||
self?.updatedUnsupportedMediaDisposables.set(nil, forKey: disposableId)
|
||||
}
|
||||
}
|
||||
self.updatedUnsupportedMediaDisposables.set(signal.start(), forKey: disposableId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func refreshStoryStatsForPeerIds(peerIds: [PeerId]) {
|
||||
self.queue.async {
|
||||
self.pendingRefreshStoriesForPeerIds.append(contentsOf: peerIds)
|
||||
|
@ -52,6 +52,8 @@ public final class ConferenceCallE2EContext {
|
||||
private var scheduledSynchronizeRemovedParticipantsAfterPoll: Bool = false
|
||||
private var synchronizeRemovedParticipantsDisposable: Disposable?
|
||||
private var synchronizeRemovedParticipantsTimer: Foundation.Timer?
|
||||
|
||||
private var pendingKickPeers: [EnginePeer.Id] = []
|
||||
|
||||
init(queue: Queue, engine: TelegramEngine, callId: Int64, accessHash: Int64, userId: Int64, reference: InternalGroupCallReference, state: Atomic<ContextStateHolder>, initializeState: @escaping (TelegramKeyPair, Int64, Data) -> ConferenceCallE2EContextState?, keyPair: TelegramKeyPair) {
|
||||
precondition(queue.isCurrent())
|
||||
@ -91,37 +93,53 @@ public final class ConferenceCallE2EContext {
|
||||
}
|
||||
|
||||
func addChainBlocksUpdate(subChainId: Int, blocks: [Data], nextOffset: Int) {
|
||||
var processBlock = true
|
||||
let updateBaseOffset = nextOffset - blocks.count
|
||||
if subChainId == 0 {
|
||||
if let e2ePoll0Offset = self.e2ePoll0Offset {
|
||||
if e2ePoll0Offset == updateBaseOffset {
|
||||
self.e2ePoll0Offset = nextOffset
|
||||
} else if e2ePoll0Offset < updateBaseOffset {
|
||||
self.e2ePoll(subChainId: subChainId)
|
||||
} else {
|
||||
processBlock = false
|
||||
var blocksToProcess: [Data] = []
|
||||
var shouldPoll = false
|
||||
for i in 0 ..< blocks.count {
|
||||
let blockOffset = updateBaseOffset + i
|
||||
if subChainId == 0 {
|
||||
if var e2ePoll0Offset = self.e2ePoll0Offset {
|
||||
if blockOffset == e2ePoll0Offset {
|
||||
e2ePoll0Offset += 1
|
||||
self.e2ePoll0Offset = e2ePoll0Offset
|
||||
blocksToProcess.append(blocks[i])
|
||||
} else if blockOffset > e2ePoll0Offset {
|
||||
shouldPoll = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processBlock = false
|
||||
}
|
||||
} else if subChainId == 1 {
|
||||
if let e2ePoll1Offset = self.e2ePoll1Offset {
|
||||
if e2ePoll1Offset == updateBaseOffset {
|
||||
self.e2ePoll1Offset = nextOffset
|
||||
} else if e2ePoll1Offset < updateBaseOffset {
|
||||
self.e2ePoll(subChainId: subChainId)
|
||||
} else {
|
||||
processBlock = false
|
||||
} else if subChainId == 1 {
|
||||
if var e2ePoll1Offset = self.e2ePoll1Offset {
|
||||
if blockOffset == e2ePoll1Offset {
|
||||
e2ePoll1Offset += 1
|
||||
self.e2ePoll1Offset = e2ePoll1Offset
|
||||
blocksToProcess.append(blocks[i])
|
||||
} else if blockOffset > e2ePoll1Offset {
|
||||
shouldPoll = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
processBlock = false
|
||||
}
|
||||
} else {
|
||||
processBlock = false
|
||||
}
|
||||
if processBlock {
|
||||
self.addE2EBlocks(blocks: blocks, subChainId: subChainId)
|
||||
|
||||
if !blocksToProcess.isEmpty {
|
||||
if subChainId == 0 {
|
||||
if self.e2ePoll0Disposable != nil {
|
||||
self.e2ePoll0Disposable?.dispose()
|
||||
self.e2ePoll0Disposable = nil
|
||||
shouldPoll = true
|
||||
}
|
||||
} else if subChainId == 1 {
|
||||
if self.e2ePoll1Disposable != nil {
|
||||
self.e2ePoll1Disposable?.dispose()
|
||||
self.e2ePoll1Disposable = nil
|
||||
shouldPoll = true
|
||||
}
|
||||
}
|
||||
self.addE2EBlocks(blocks: blocksToProcess, subChainId: subChainId)
|
||||
}
|
||||
|
||||
if shouldPoll {
|
||||
self.e2ePoll(subChainId: subChainId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,6 +204,14 @@ public final class ConferenceCallE2EContext {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if subChainId == 0 {
|
||||
self.e2ePoll0Disposable?.dispose()
|
||||
self.e2ePoll0Disposable = nil
|
||||
} else if subChainId == 1 {
|
||||
self.e2ePoll1Disposable?.dispose()
|
||||
self.e2ePoll1Disposable = nil
|
||||
}
|
||||
|
||||
var delayPoll = true
|
||||
if let result {
|
||||
@ -247,71 +273,139 @@ public final class ConferenceCallE2EContext {
|
||||
let callId = self.callId
|
||||
let accessHash = self.accessHash
|
||||
|
||||
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
||||
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants(
|
||||
account: self.engine.account,
|
||||
reference: self.reference,
|
||||
offset: "",
|
||||
ssrcs: [],
|
||||
limit: 100,
|
||||
sortAscending: true
|
||||
)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
guard let result else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
let blockchainPeerIds = state.with { state -> [Int64] in
|
||||
guard let state = state.state else {
|
||||
return []
|
||||
}
|
||||
return state.getParticipantIds()
|
||||
}
|
||||
|
||||
// Peer ids that are in the blockchain but not in the server list
|
||||
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
|
||||
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
|
||||
}
|
||||
if !self.pendingKickPeers.isEmpty {
|
||||
let pendingKickPeers = self.pendingKickPeers
|
||||
self.pendingKickPeers.removeAll()
|
||||
|
||||
if removedPeerIds.isEmpty {
|
||||
return .single(false)
|
||||
}
|
||||
guard let removeBlock = state.with({ state -> Data? in
|
||||
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
||||
|
||||
let removeBlock = state.with({ state -> Data? in
|
||||
guard let state = state.state else {
|
||||
return nil
|
||||
}
|
||||
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds)
|
||||
}) else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|
||||
|> map { result -> Bool in
|
||||
switch result {
|
||||
case .success:
|
||||
return true
|
||||
case .pollBlocksAndRetry:
|
||||
return false
|
||||
let currentIds = state.getParticipantIds()
|
||||
let remainingIds = pendingKickPeers.filter({ currentIds.contains($0.id._internalGetInt64Value()) })
|
||||
if remainingIds.isEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
return state.generateRemoveParticipantsBlock(participantIds: remainingIds.map { $0.id._internalGetInt64Value() })
|
||||
})
|
||||
if let removeBlock {
|
||||
self.synchronizeRemovedParticipantsDisposable = (engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .kick, participantIds: pendingKickPeers.map { $0.id._internalGetInt64Value() }, block: removeBlock)
|
||||
|> map { result -> Bool in
|
||||
switch result {
|
||||
case .success:
|
||||
return true
|
||||
case .pollBlocksAndRetry:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] shouldRetry in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if shouldRetry {
|
||||
for id in pendingKickPeers {
|
||||
if !self.pendingKickPeers.contains(id) {
|
||||
self.pendingKickPeers.append(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.isSynchronizingRemovedParticipants = false
|
||||
if self.scheduledSynchronizeRemovedParticipants {
|
||||
self.scheduledSynchronizeRemovedParticipants = false
|
||||
self.synchronizeRemovedParticipants()
|
||||
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
||||
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
||||
self.e2ePoll(subChainId: 0)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.isSynchronizingRemovedParticipants = false
|
||||
if self.scheduledSynchronizeRemovedParticipants {
|
||||
self.scheduledSynchronizeRemovedParticipants = false
|
||||
self.synchronizeRemovedParticipants()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.synchronizeRemovedParticipantsDisposable?.dispose()
|
||||
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants(
|
||||
account: self.engine.account,
|
||||
reference: self.reference,
|
||||
offset: "",
|
||||
ssrcs: [],
|
||||
limit: 100,
|
||||
sortAscending: true
|
||||
)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Bool, NoError> in
|
||||
guard let result else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
let blockchainPeerIds = state.with { state -> [Int64] in
|
||||
guard let state = state.state else {
|
||||
return []
|
||||
}
|
||||
return state.getParticipantIds()
|
||||
}
|
||||
|
||||
// Peer ids that are in the blockchain but not in the server list
|
||||
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
|
||||
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
|
||||
}
|
||||
|
||||
if removedPeerIds.isEmpty {
|
||||
return .single(false)
|
||||
}
|
||||
guard let removeBlock = state.with({ state -> Data? in
|
||||
guard let state = state.state else {
|
||||
return nil
|
||||
}
|
||||
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds)
|
||||
}) else {
|
||||
return .single(false)
|
||||
}
|
||||
|
||||
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|
||||
|> map { result -> Bool in
|
||||
switch result {
|
||||
case .success:
|
||||
return true
|
||||
case .pollBlocksAndRetry:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isSynchronizingRemovedParticipants = false
|
||||
if self.scheduledSynchronizeRemovedParticipants {
|
||||
self.scheduledSynchronizeRemovedParticipants = false
|
||||
self.synchronizeRemovedParticipants()
|
||||
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
||||
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
||||
self.e2ePoll(subChainId: 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func kickPeer(id: EnginePeer.Id) {
|
||||
//TODO:release
|
||||
if !self.pendingKickPeers.contains(id) {
|
||||
self.pendingKickPeers.append(id)
|
||||
|
||||
self.synchronizeRemovedParticipants()
|
||||
}
|
||||
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isSynchronizingRemovedParticipants = false
|
||||
if self.scheduledSynchronizeRemovedParticipants {
|
||||
self.scheduledSynchronizeRemovedParticipants = false
|
||||
self.synchronizeRemovedParticipants()
|
||||
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
|
||||
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
|
||||
self.e2ePoll(subChainId: 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,4 +443,10 @@ public final class ConferenceCallE2EContext {
|
||||
impl.synchronizeRemovedParticipants()
|
||||
}
|
||||
}
|
||||
|
||||
public func kickPeer(id: EnginePeer.Id) {
|
||||
self.impl.with { impl in
|
||||
impl.kickPeer(id: id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,6 +241,53 @@ func _internal_getCurrentGroupCall(account: Account, reference: InternalGroupCal
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_getCurrentGroupCallInfo(account: Account, reference: InternalGroupCallReference) -> Signal<(participants: [PeerId], duration: Int32?)?, NoError> {
|
||||
let accountPeerId = account.peerId
|
||||
let inputCall: Api.InputGroupCall
|
||||
switch reference {
|
||||
case let .id(id, accessHash):
|
||||
inputCall = .inputGroupCall(id: id, accessHash: accessHash)
|
||||
case let .link(slug):
|
||||
inputCall = .inputGroupCallSlug(slug: slug)
|
||||
case let .message(id):
|
||||
if id.peerId.namespace != Namespaces.Peer.CloudUser {
|
||||
return .single(nil)
|
||||
}
|
||||
if id.namespace != Namespaces.Message.Cloud {
|
||||
return .single(nil)
|
||||
}
|
||||
inputCall = .inputGroupCallInviteMessage(msgId: id.id)
|
||||
}
|
||||
return account.network.request(Api.functions.phone.getGroupCall(call: inputCall, limit: 4))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.phone.GroupCall?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<(participants: [PeerId], duration: Int32?)?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
switch result {
|
||||
case let .groupCall(call, participants, _, chats, users):
|
||||
return account.postbox.transaction { transaction -> (participants: [PeerId], duration: Int32?)? in
|
||||
if case let .groupCallDiscarded(_, _, duration) = call {
|
||||
return ([], duration)
|
||||
}
|
||||
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
|
||||
let parsedParticipants = participants.compactMap { GroupCallParticipantsContext.Participant($0, transaction: transaction) }
|
||||
return (
|
||||
parsedParticipants.map(\.peer.id),
|
||||
nil
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum CreateGroupCallError {
|
||||
case generic
|
||||
case anonymousNotAllowed
|
||||
@ -3050,3 +3097,59 @@ func _internal_sendConferenceCallBroadcast(account: Account, callId: Int64, acce
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_refreshInlineGroupCall(account: Account, messageId: MessageId) -> Signal<Never, NoError> {
|
||||
return _internal_getCurrentGroupCallInfo(account: account, reference: .message(id: messageId))
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
var updatedMedia = currentMessage.media
|
||||
|
||||
for i in 0 ..< updatedMedia.count {
|
||||
if let action = updatedMedia[i] as? TelegramMediaAction, case let .conferenceCall(conferenceCall) = action.action {
|
||||
var otherParticipants: [PeerId] = []
|
||||
var duration: Int32? = conferenceCall.duration
|
||||
if let result {
|
||||
for id in result.participants {
|
||||
if id != account.peerId {
|
||||
otherParticipants.append(id)
|
||||
}
|
||||
}
|
||||
duration = result.duration
|
||||
} else {
|
||||
duration = nil
|
||||
}
|
||||
|
||||
updatedMedia[i] = TelegramMediaAction(action: .conferenceCall(TelegramMediaActionType.ConferenceCall(
|
||||
callId: conferenceCall.callId,
|
||||
duration: duration,
|
||||
flags: conferenceCall.flags,
|
||||
otherParticipants: otherParticipants
|
||||
)))
|
||||
}
|
||||
}
|
||||
return .update(StoreMessage(
|
||||
id: currentMessage.id,
|
||||
globallyUniqueId: currentMessage.globallyUniqueId,
|
||||
groupingKey: currentMessage.groupingKey,
|
||||
threadId: currentMessage.threadId,
|
||||
timestamp: currentMessage.timestamp,
|
||||
flags: StoreMessageFlags(currentMessage.flags),
|
||||
tags: currentMessage.tags,
|
||||
globalTags: currentMessage.globalTags,
|
||||
localTags: currentMessage.localTags,
|
||||
forwardInfo: storeForwardInfo,
|
||||
authorId: currentMessage.author?.id,
|
||||
text: currentMessage.text,
|
||||
attributes: currentMessage.attributes,
|
||||
media: updatedMedia
|
||||
))
|
||||
})
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,9 @@ public class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
#else
|
||||
missedTimeout = 30
|
||||
#endif
|
||||
if conferenceCall.duration != nil {
|
||||
hasCallButton = false
|
||||
}
|
||||
let currentTime = Int32(Date().timeIntervalSince1970)
|
||||
if conferenceCall.flags.contains(.isMissed) {
|
||||
titleString = "Declined Group Call"
|
||||
@ -149,7 +152,6 @@ public class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
titleString = "Missed Group Call"
|
||||
} else if conferenceCall.duration != nil {
|
||||
titleString = "Cancelled Group Call"
|
||||
hasCallButton = true
|
||||
} else {
|
||||
if incoming {
|
||||
titleString = "Incoming Group Call"
|
||||
|
@ -586,6 +586,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
private let translationProcessingManager = ChatMessageThrottledProcessingManager(submitInterval: 1.0)
|
||||
private let refreshStoriesProcessingManager = ChatMessageThrottledProcessingManager()
|
||||
private let factCheckProcessingManager = ChatMessageThrottledProcessingManager(submitInterval: 1.0)
|
||||
private let inlineGroupCallsProcessingManager = ChatMessageThrottledProcessingManager(submitInterval: 1.0)
|
||||
|
||||
let prefetchManager: InChatPrefetchManager
|
||||
private var currentEarlierPrefetchMessages: [(Message, Media)] = []
|
||||
@ -978,6 +979,10 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
strongSelf.context.account.viewTracker.updatedExtendedMediaForMessageIds(messageIds: Set(messageIds.map(\.messageId)))
|
||||
}
|
||||
|
||||
self.inlineGroupCallsProcessingManager.process = { [weak context] messageIds in
|
||||
context?.account.viewTracker.refreshInlineGroupCallsForMessageIds(messageIds: Set(messageIds.map(\.messageId)))
|
||||
}
|
||||
|
||||
self.preloadPages = false
|
||||
|
||||
self.beginChatHistoryTransitions(resetScrolling: false)
|
||||
@ -2728,6 +2733,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
var messageIdsWithUnseenPersonalMention: [MessageId] = []
|
||||
var messageIdsWithUnseenReactions: [MessageId] = []
|
||||
var messageIdsWithInactiveExtendedMedia = Set<MessageId>()
|
||||
var messageIdsWithGroupCalls: [MessageId] = []
|
||||
var downloadableResourceIds: [(messageId: MessageId, resourceId: String)] = []
|
||||
var allVisibleAnchorMessageIds: [(MessageId, Int)] = []
|
||||
var visibleAdOpaqueIds: [Data] = []
|
||||
@ -2826,6 +2832,13 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
storiesRequiredValidation = true
|
||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.story {
|
||||
storiesRequiredValidation = true
|
||||
} else if let media = media as? TelegramMediaAction {
|
||||
if case let .conferenceCall(conferenceCall) = media.action {
|
||||
if conferenceCall.duration != nil {
|
||||
} else {
|
||||
messageIdsWithGroupCalls.append(message.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if contentRequiredValidation {
|
||||
@ -3083,6 +3096,9 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
if !peerIdsWithRefreshStories.isEmpty {
|
||||
self.context.account.viewTracker.refreshStoryStatsForPeerIds(peerIds: peerIdsWithRefreshStories)
|
||||
}
|
||||
if !messageIdsWithGroupCalls.isEmpty {
|
||||
self.inlineGroupCallsProcessingManager.add(messageIdsWithGroupCalls.map { MessageAndThreadId(messageId: $0, threadId: nil) })
|
||||
}
|
||||
|
||||
self.currentEarlierPrefetchMessages = toEarlierMediaMessages
|
||||
self.currentLaterPrefetchMessages = toLaterMediaMessages
|
||||
|
60
third-party/td/TdBinding/Sources/TdBinding.mm
vendored
60
third-party/td/TdBinding/Sources/TdBinding.mm
vendored
@ -83,6 +83,13 @@ static NSString *hexStringFromData(NSData *data) {
|
||||
if (self != nil) {
|
||||
_callId = callId;
|
||||
_keyPair = keyPair;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
#if DEBUG
|
||||
tde2e_api::set_log_verbosity_level(4);
|
||||
#endif
|
||||
});
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -130,7 +137,17 @@ static NSString *hexStringFromData(NSData *data) {
|
||||
#if DEBUG
|
||||
auto describeResult = tde2e_api::call_describe_message(it);
|
||||
if (describeResult.is_ok()) {
|
||||
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: block %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
||||
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||
if (utf8String) {
|
||||
NSLog(@"TdCall.call_pull_outbound_messages block: %@", utf8String);
|
||||
} else {
|
||||
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||
if (lossyString) {
|
||||
NSLog(@"TdCall.call_pull_outbound_messages block (lossy conversion): %@", lossyString);
|
||||
} else {
|
||||
NSLog(@"TdCall.call_pull_outbound_messages block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: describe block failed");
|
||||
}
|
||||
@ -178,7 +195,17 @@ static NSString *hexStringFromData(NSData *data) {
|
||||
#if DEBUG
|
||||
auto describeResult = tde2e_api::call_describe_block(mappedBlock);
|
||||
if (describeResult.is_ok()) {
|
||||
NSLog(@"TdCall.applyBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
||||
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||
if (utf8String) {
|
||||
NSLog(@"TdCall.applyBlock block: %@", utf8String);
|
||||
} else {
|
||||
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||
if (lossyString) {
|
||||
NSLog(@"TdCall.applyBlock block (lossy conversion): %@", lossyString);
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBlock block: describe block failed");
|
||||
}
|
||||
@ -196,7 +223,17 @@ static NSString *hexStringFromData(NSData *data) {
|
||||
#if DEBUG
|
||||
auto describeResult = tde2e_api::call_describe_message(mappedBlock);
|
||||
if (describeResult.is_ok()) {
|
||||
NSLog(@"TdCall.applyBroadcastBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]);
|
||||
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||
if (utf8String) {
|
||||
NSLog(@"TdCall.applyBroadcastBlock block: %@", utf8String);
|
||||
} else {
|
||||
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||
if (lossyString) {
|
||||
NSLog(@"TdCall.applyBroadcastBlock block (lossy conversion): %@", lossyString);
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBroadcastBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBroadcastBlock block: describe block failed");
|
||||
}
|
||||
@ -206,6 +243,23 @@ static NSString *hexStringFromData(NSData *data) {
|
||||
if (!result.is_ok()) {
|
||||
return;
|
||||
}
|
||||
|
||||
describeResult = tde2e_api::call_describe(_callId);
|
||||
if (describeResult.is_ok()) {
|
||||
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
|
||||
if (utf8String) {
|
||||
NSLog(@"TdCall.applyBroadcastBlock call after apply: %@", utf8String);
|
||||
} else {
|
||||
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
|
||||
if (lossyString) {
|
||||
NSLog(@"TdCall.applyBroadcastBlock call after apply (lossy conversion): %@", lossyString);
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBroadcastBlock call after apply: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSLog(@"TdCall.applyBroadcastBlock call after apply: describe block failed");
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSData *)generateRemoveParticipantsBlock:(NSArray<NSNumber *> *)participantIds {
|
||||
|
1
third-party/td/build-td-bazel.sh
vendored
1
third-party/td/build-td-bazel.sh
vendored
@ -14,7 +14,6 @@ options=""
|
||||
options="$options -DOPENSSL_FOUND=1"
|
||||
options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
|
||||
options="$options -DOPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/src/include"
|
||||
#options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library}"
|
||||
options="$options -DCMAKE_BUILD_TYPE=Release"
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
|
Loading…
x
Reference in New Issue
Block a user