Conference updates

This commit is contained in:
Isaac 2025-04-11 14:41:49 +04:00
parent a1631b421a
commit 22b4c30774
11 changed files with 80 additions and 13 deletions

View File

@ -14179,4 +14179,6 @@ Sorry for the inconvenience.";
"Call.IncomingGroupCallTitle.Single" = "%@"; "Call.IncomingGroupCallTitle.Single" = "%@";
"Call.IncomingGroupCallTitle.Multiple_1" = "{} and 1 other"; "Call.IncomingGroupCallTitle.Multiple_1" = "{} and 1 other";
"Call.IncomingGroupCallTitle.Multiple_any" = "{} and %d others"; "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.";

View File

@ -126,7 +126,7 @@ private func mappedInsertEntries(context: AccountContext, presentationData: Item
case let .displayTabInfo(_, text): case let .displayTabInfo(_, text):
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint)
case .openNewCall: 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() nodeInteraction.openNewCall()
}) })
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) 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): case let .displayTabInfo(_, text):
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: 0), directionHint: entry.directionHint)
case .openNewCall: 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() nodeInteraction.openNewCall()
}) })
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)

View File

@ -494,7 +494,7 @@ public final class InviteLinkInviteController: ViewController {
} }
controller.setItemGroups([ controller.setItemGroups([
ActionSheetItemGroup(items: [ 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 ActionSheetButtonItem(title: presentationData.strings.GroupInfo_InviteLink_RevokeLink, color: .destructive, action: { [weak self] in
dismissAction() dismissAction()

View File

@ -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.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 }, error: { [weak self] error in
guard let self else { guard let self else {
return return

View File

@ -550,7 +550,7 @@ final class VideoChatEncryptionKeyComponent: Component {
self.isUpdating = false self.isUpdating = false
} }
#if DEBUG && true #if DEBUG && false
if self.component == nil { if self.component == nil {
self.mockStateTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { [weak self] _ in self.mockStateTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { [weak self] _ in
guard let self else { guard let self else {

View File

@ -79,7 +79,7 @@ public final class ConferenceCallE2EContext {
self.synchronizeRemovedParticipantsTimer?.invalidate() self.synchronizeRemovedParticipantsTimer?.invalidate()
} }
func begin() { func begin(initialState: JoinGroupCallResult.E2EState?) {
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
self.synchronizeRemovedParticipantsTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true, block: { [weak self] _ in self.synchronizeRemovedParticipantsTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true, block: { [weak self] _ in
guard let self else { guard let self else {
@ -88,6 +88,13 @@ public final class ConferenceCallE2EContext {
self.synchronizeRemovedParticipants() 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: 0)
self.e2ePoll(subChainId: 1) 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 self.impl.with { impl in
impl.begin() impl.begin(initialState: initialState)
} }
} }

View File

@ -587,11 +587,22 @@ public struct JoinGroupCallResult {
case rtc case rtc
case broadcast(isExternalStream: Bool) 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 callInfo: GroupCallInfo
public var state: GroupCallParticipantsContext.State public var state: GroupCallParticipantsContext.State
public var connectionMode: ConnectionMode public var connectionMode: ConnectionMode
public var jsonParams: String public var jsonParams: String
public var e2eState: E2EState?
} }
public class JoinGroupCallE2E { public class JoinGroupCallE2E {
@ -791,7 +802,7 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
connectionMode = .broadcast(isExternalStream: false) connectionMode = .broadcast(isExternalStream: false)
} }
return account.postbox.transaction { transaction -> JoinGroupCallResult in return account.postbox.transaction { transaction -> Signal<JoinGroupCallResult, InternalJoinError> in
if let peerId { if let peerId {
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in
if let cachedData = cachedData as? CachedChannelData { if let cachedData = cachedData as? CachedChannelData {
@ -806,6 +817,9 @@ func _internal_joinGroupCall(account: Account, peerId: PeerId?, joinAs: PeerId?,
var state = state var state = state
var e2eSubChain1State: (offset: Int, blocks: [Data])?
var e2eSubChain0State: (offset: Int, blocks: [Data])?
for update in updates.allUpdates { for update in updates.allUpdates {
switch update { switch update {
case let .updateGroupCallParticipants(_, participants, _): 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: default:
break 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) }) state.participants.sort(by: { GroupCallParticipantsContext.Participant.compare(lhs: $0, rhs: $1, sortAscending: state.sortAscending) })
return JoinGroupCallResult( return .single(JoinGroupCallResult(
callInfo: parsedCall, callInfo: parsedCall,
state: state, state: state,
connectionMode: connectionMode, connectionMode: connectionMode,
jsonParams: parsedClientParams jsonParams: parsedClientParams,
) e2eState: e2eState
))
} }
|> castError(InternalJoinError.self) |> castError(InternalJoinError.self)
|> switchToLatest
} }
} }
} }

View File

@ -336,6 +336,8 @@ public enum PresentationResourceKey: Int32 {
case peerStatusLockedImage case peerStatusLockedImage
case expandDownArrowImage case expandDownArrowImage
case expandSmallDownArrowImage case expandSmallDownArrowImage
case callListCallIcon
} }
public enum ChatExpiredStoryIndicatorType: Hashable { public enum ChatExpiredStoryIndicatorType: Hashable {

View File

@ -199,4 +199,10 @@ public struct PresentationResourcesRootController {
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white) 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)
})
}
} }

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "newcall_30.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}