From 22b4c3077491c2534c204132410ebaa153ab2591 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 11 Apr 2025 14:41:49 +0400 Subject: [PATCH] Conference updates --- .../Telegram-iOS/en.lproj/Localizable.strings | 4 +- .../Sources/CallListControllerNode.swift | 4 +- .../Sources/InviteLinkInviteController.swift | 2 +- .../Sources/PresentationGroupCall.swift | 6 ++- .../VideoChatEncryptionKeyComponent.swift | 2 +- .../State/ConferenceCallE2EContext.swift | 13 ++++-- .../TelegramEngine/Calls/GroupCalls.swift | 42 ++++++++++++++++-- .../Resources/PresentationResourceKey.swift | 2 + .../PresentationResourcesRootController.swift | 6 +++ .../NewCallListIcon.imageset/Contents.json | 12 +++++ .../NewCallListIcon.imageset/newcall_30.pdf | Bin 0 -> 4933 bytes 11 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/newcall_30.pdf diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index f6e9611518..ab0406233a 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14179,4 +14179,6 @@ Sorry for the inconvenience."; "Call.IncomingGroupCallTitle.Single" = "%@"; "Call.IncomingGroupCallTitle.Multiple_1" = "{} and 1 other"; -"Call.IncomingGroupCallTitle.Multiple_any" = "{} and %d others"; \ No newline at end of file +"Call.IncomingGroupCallTitle.Multiple_any" = "{} and %d others"; + +"GroupCall.RevokeLinkText" = "Are you sure you want to revoke this link? Once you do, no one will be able to join the call using it."; diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index 204dffbf3f..dfb1a324e2 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -126,7 +126,7 @@ private func mappedInsertEntries(context: AccountContext, presentationData: Item case let .displayTabInfo(_, text): return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) case .openNewCall: - let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.navigationCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { + let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { nodeInteraction.openNewCall() }) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) @@ -150,7 +150,7 @@ private func mappedUpdateEntries(context: AccountContext, presentationData: Item case let .displayTabInfo(_, text): return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) case .openNewCall: - let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.navigationCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { + let item = ItemListPeerActionItem(presentationData: presentationData, style: showSettings ? .blocks : .plain, icon: PresentationResourcesRootController.callListCallIcon(presentationData.theme), title: presentationData.strings.CallList_NewCall, hasSeparator: false, sectionId: 1, height: .generic, noInsets: true, editing: false, action: { nodeInteraction.openNewCall() }) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift b/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift index 153bcc6d57..34a52902e2 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkInviteController.swift @@ -494,7 +494,7 @@ public final class InviteLinkInviteController: ViewController { } controller.setItemGroups([ ActionSheetItemGroup(items: [ - ActionSheetTextItem(title: presentationData.strings.VideoChat_RevokeLink), + ActionSheetTextItem(title: presentationData.strings.GroupCall_RevokeLinkText), ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: { [weak self] in dismissAction() diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index bb7957c770..3b8178798e 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -2003,7 +2003,11 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.updateSessionState(internalState: .established(info: joinCallResult.callInfo, connectionMode: joinCallResult.connectionMode, clientParams: clientParams, localSsrc: ssrc, initialState: joinCallResult.state), audioSessionControl: self.audioSessionControl) - self.e2eContext?.begin() + if let e2eState = joinCallResult.e2eState { + self.e2eContext?.begin(initialState: e2eState) + } else { + self.e2eContext?.begin(initialState: nil) + } }, error: { [weak self] error in guard let self else { return diff --git a/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift index 02cfbd82ca..83abd095f9 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatEncryptionKeyComponent.swift @@ -550,7 +550,7 @@ final class VideoChatEncryptionKeyComponent: Component { self.isUpdating = false } - #if DEBUG && true +#if DEBUG && false if self.component == nil { self.mockStateTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { [weak self] _ in guard let self else { diff --git a/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift b/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift index 07471dfedb..5914833d9b 100644 --- a/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift +++ b/submodules/TelegramCore/Sources/State/ConferenceCallE2EContext.swift @@ -79,7 +79,7 @@ public final class ConferenceCallE2EContext { self.synchronizeRemovedParticipantsTimer?.invalidate() } - func begin() { + func begin(initialState: JoinGroupCallResult.E2EState?) { self.scheduledSynchronizeRemovedParticipantsAfterPoll = true self.synchronizeRemovedParticipantsTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true, block: { [weak self] _ in guard let self else { @@ -88,6 +88,13 @@ public final class ConferenceCallE2EContext { self.synchronizeRemovedParticipants() }) + if let initialState { + self.e2ePoll0Offset = initialState.subChain0.offset + self.e2ePoll1Offset = initialState.subChain1.offset + self.addE2EBlocks(blocks: initialState.subChain0.blocks, subChainId: 0) + self.addE2EBlocks(blocks: initialState.subChain1.blocks, subChainId: 1) + } + self.e2ePoll(subChainId: 0) self.e2ePoll(subChainId: 1) } @@ -424,9 +431,9 @@ public final class ConferenceCallE2EContext { }) } - public func begin() { + public func begin(initialState: JoinGroupCallResult.E2EState?) { self.impl.with { impl in - impl.begin() + impl.begin(initialState: initialState) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift index 46b0773315..755d84711b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift @@ -587,11 +587,22 @@ public struct JoinGroupCallResult { case rtc case broadcast(isExternalStream: Bool) } + + public struct E2EState { + public let subChain0: (offset: Int, blocks: [Data]) + public let subChain1: (offset: Int, blocks: [Data]) + + public init(subChain0: (offset: Int, blocks: [Data]), subChain1: (offset: Int, blocks: [Data])) { + self.subChain0 = subChain0 + self.subChain1 = subChain1 + } + } public var callInfo: GroupCallInfo public var state: GroupCallParticipantsContext.State public var connectionMode: ConnectionMode public var jsonParams: String + public var e2eState: E2EState? } public class JoinGroupCallE2E { @@ -791,7 +802,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, connectionMode = .broadcast(isExternalStream: false) } - return account.postbox.transaction { transaction -> JoinGroupCallResult in + return account.postbox.transaction { transaction -> Signal in if let peerId { transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in if let cachedData = cachedData as? CachedChannelData { @@ -806,6 +817,9 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, var state = state + var e2eSubChain1State: (offset: Int, blocks: [Data])? + var e2eSubChain0State: (offset: Int, blocks: [Data])? + for update in updates.allUpdates { switch update { case let .updateGroupCallParticipants(_, participants, _): @@ -852,21 +866,41 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?, } } } + case let .updateGroupCallChainBlocks(_, subChainId, blocks, nextOffset): + if subChainId == 0 { + e2eSubChain0State = (offset: Int(nextOffset), blocks: blocks.map { $0.makeData() }) + } else { + e2eSubChain1State = (offset: Int(nextOffset), blocks: blocks.map { $0.makeData() }) + } default: break } } + + var e2eState: JoinGroupCallResult.E2EState? + if let e2eSubChain0State, let e2eSubChain1State { + e2eState = JoinGroupCallResult.E2EState( + subChain0: e2eSubChain0State, + subChain1: e2eSubChain1State + ) + } + + if generateE2E != nil && e2eState == nil { + return .fail(.error(.generic)) + } state.participants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: state.sortAscending) }) - return JoinGroupCallResult( + return .single(JoinGroupCallResult( callInfo: parsedCall, state: state, connectionMode: connectionMode, - jsonParams: parsedClientParams - ) + jsonParams: parsedClientParams, + e2eState: e2eState + )) } |> castError(InternalJoinError.self) + |> switchToLatest } } } diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 6afe54e1d7..2dea72f9a3 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -336,6 +336,8 @@ public enum PresentationResourceKey: Int32 { case peerStatusLockedImage case expandDownArrowImage case expandSmallDownArrowImage + + case callListCallIcon } public enum ChatExpiredStoryIndicatorType: Hashable { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift index 0e4915686b..d486af773d 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesRootController.swift @@ -199,4 +199,10 @@ public struct PresentationResourcesRootController { return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white) }) } + + public static func callListCallIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.callListCallIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Call List/NewCallListIcon"), color: theme.rootController.navigationBar.accentTextColor) + }) + } } diff --git a/submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/Contents.json new file mode 100644 index 0000000000..91489efbe6 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "newcall_30.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/newcall_30.pdf b/submodules/TelegramUI/Images.xcassets/Call List/NewCallListIcon.imageset/newcall_30.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4a915649db0efeb51e765796c4158a3cb242e125 GIT binary patch literal 4933 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 Brvm^0 literal 0 HcmV?d00001