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
df5e9c7cd3
@ -12,8 +12,8 @@ public enum RequestCallResult {
|
||||
case alreadyInProgress(PeerId?)
|
||||
}
|
||||
|
||||
public enum RequestOrJoinGroupCallResult {
|
||||
case requested
|
||||
public enum JoinGroupCallManagerResult {
|
||||
case joined
|
||||
case alreadyInProgress(PeerId?)
|
||||
}
|
||||
|
||||
@ -278,5 +278,5 @@ public protocol PresentationCallManager: class {
|
||||
var currentGroupCallSignal: Signal<PresentationGroupCall?, NoError> { get }
|
||||
|
||||
func requestCall(context: AccountContext, peerId: PeerId, isVideo: Bool, endCurrentIfAny: Bool) -> RequestCallResult
|
||||
func requestOrJoinGroupCall(context: AccountContext, peerId: PeerId, initialCall: CachedChannelData.ActiveCall?, endCurrentIfAny: Bool, sourcePanel: ASDisplayNode?) -> RequestOrJoinGroupCallResult
|
||||
func joinGroupCall(context: AccountContext, peerId: PeerId, initialCall: CachedChannelData.ActiveCall, endCurrentIfAny: Bool, sourcePanel: ASDisplayNode?) -> JoinGroupCallManagerResult
|
||||
}
|
||||
|
@ -262,20 +262,19 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
|
||||
if let callManager = context.sharedContext.callManager {
|
||||
switch groupCallPanelSource {
|
||||
case .none:
|
||||
case .none, .all:
|
||||
break
|
||||
default:
|
||||
case let .peer(peerId):
|
||||
let currentGroupCall: Signal<GroupCallPanelData?, NoError> = callManager.currentGroupCallSignal
|
||||
|> distinctUntilChanged(isEqual: { lhs, rhs in
|
||||
return lhs?.internalId == rhs?.internalId
|
||||
})
|
||||
|> mapToSignal { call -> Signal<GroupCallPanelData?, NoError> in
|
||||
guard let call = call else {
|
||||
guard let call = call, call.peerId == peerId else {
|
||||
return .single(nil)
|
||||
}
|
||||
return call.summaryState
|
||||
|> filter { $0 != nil }
|
||||
|> take(1)
|
||||
|> map { summary -> GroupCallPanelData? in
|
||||
guard let summary = summary else {
|
||||
return nil
|
||||
@ -289,6 +288,13 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
groupCall: call
|
||||
)
|
||||
}
|
||||
|> take(until: { summary in
|
||||
if summary != nil {
|
||||
return SignalTakeAction(passthrough: true, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: true, complete: false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let availableGroupCall: Signal<GroupCallPanelData?, NoError>
|
||||
@ -861,7 +867,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
}
|
||||
|
||||
private func joinGroupCall(peerId: PeerId, info: GroupCallInfo, sourcePanel: GroupCallNavigationAccessoryPanel?) {
|
||||
let callResult = self.context.sharedContext.callManager?.requestOrJoinGroupCall(context: self.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash), endCurrentIfAny: false, sourcePanel: sourcePanel)
|
||||
let callResult = self.context.sharedContext.callManager?.joinGroupCall(context: self.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash), endCurrentIfAny: false, sourcePanel: sourcePanel)
|
||||
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
|
||||
if currentPeerId == peerId {
|
||||
self.context.sharedContext.navigateToCurrentCall(sourcePanel: sourcePanel)
|
||||
@ -880,7 +886,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
|
||||
if let current = current {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||
if let strongSelf = self {
|
||||
let _ = strongSelf.context.sharedContext.callManager?.requestOrJoinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash), endCurrentIfAny: true, sourcePanel: sourcePanel)
|
||||
let _ = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash), endCurrentIfAny: true, sourcePanel: sourcePanel)
|
||||
}
|
||||
})]), in: .window(.root))
|
||||
} else {
|
||||
|
@ -593,7 +593,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
}
|
||||
}
|
||||
|
||||
public func requestOrJoinGroupCall(context: AccountContext, peerId: PeerId, initialCall: CachedChannelData.ActiveCall?, endCurrentIfAny: Bool, sourcePanel: ASDisplayNode?) -> RequestOrJoinGroupCallResult {
|
||||
public func joinGroupCall(context: AccountContext, peerId: PeerId, initialCall: CachedChannelData.ActiveCall, endCurrentIfAny: Bool, sourcePanel: ASDisplayNode?) -> JoinGroupCallManagerResult {
|
||||
let begin: () -> Void = { [weak self] in
|
||||
let _ = self?.startGroupCall(accountContext: context, peerId: peerId, initialCall: initialCall, sourcePanel: sourcePanel).start()
|
||||
}
|
||||
@ -612,13 +612,13 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
} else {
|
||||
begin()
|
||||
}
|
||||
return .requested
|
||||
return .joined
|
||||
}
|
||||
|
||||
private func startGroupCall(
|
||||
accountContext: AccountContext,
|
||||
peerId: PeerId,
|
||||
initialCall: CachedChannelData.ActiveCall?,
|
||||
initialCall: CachedChannelData.ActiveCall,
|
||||
internalId: CallSessionInternalId = CallSessionInternalId(),
|
||||
sourcePanel: ASDisplayNode?
|
||||
) -> Signal<Bool, NoError> {
|
||||
|
@ -142,7 +142,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
|
||||
private let getDeviceAccessData: () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void)
|
||||
|
||||
private let initialCall: CachedChannelData.ActiveCall?
|
||||
private var initialCall: CachedChannelData.ActiveCall?
|
||||
public let internalId: CallSessionInternalId
|
||||
public let peerId: PeerId
|
||||
public let peer: Peer?
|
||||
@ -374,12 +374,26 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
var removedSsrc: [UInt32] = []
|
||||
for (callId, update) in updates {
|
||||
if callId == callInfo.id {
|
||||
for participantUpdate in update.participantUpdates {
|
||||
if participantUpdate.isRemoved {
|
||||
removedSsrc.append(participantUpdate.ssrc)
|
||||
switch update {
|
||||
case let .state(update):
|
||||
for participantUpdate in update.participantUpdates {
|
||||
if participantUpdate.isRemoved {
|
||||
removedSsrc.append(participantUpdate.ssrc)
|
||||
|
||||
if participantUpdate.peerId == strongSelf.accountContext.account.peerId {
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}
|
||||
} else if participantUpdate.peerId == strongSelf.accountContext.account.peerId {
|
||||
if case let .estabilished(_, _, ssrc, _) = strongSelf.internalState, ssrc != participantUpdate.ssrc {
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .call(isTerminated):
|
||||
if isTerminated {
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}
|
||||
}
|
||||
strongSelf.participantsContext?.addUpdates(updates: [update])
|
||||
}
|
||||
}
|
||||
if !removedSsrc.isEmpty {
|
||||
@ -553,7 +567,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if case let .estabilished(callInfo, clientParams, _, initialState) = internalState {
|
||||
self.summaryInfoState.set(.single(SummaryInfoState(info: callInfo)))
|
||||
|
||||
self.stateValue.canManageCall = initialState.isCreator
|
||||
self.stateValue.canManageCall = initialState.isCreator || initialState.adminIds.contains(self.accountContext.account.peerId)
|
||||
|
||||
self.ssrcMapping.removeAll()
|
||||
var ssrcs: [UInt32] = []
|
||||
@ -780,7 +794,6 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|
||||
let account = self.account
|
||||
let peerId = self.peerId
|
||||
|
||||
let currentCall: Signal<GroupCallInfo?, CallError>
|
||||
if let initialCall = self.initialCall {
|
||||
@ -796,36 +809,27 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|
||||
let currentOrRequestedCall = currentCall
|
||||
|> mapToSignal { callInfo -> Signal<GroupCallInfo, CallError> in
|
||||
|> mapToSignal { callInfo -> Signal<GroupCallInfo?, CallError> in
|
||||
if let callInfo = callInfo {
|
||||
return .single(callInfo)
|
||||
} else {
|
||||
return createGroupCall(account: account, peerId: peerId)
|
||||
|> mapError { _ -> CallError in
|
||||
return .generic
|
||||
}
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
/*let restartedCall = currentOrRequestedCall
|
||||
|> mapToSignal { value -> Signal<GroupCallInfo, CallError> in
|
||||
let stopped: Signal<GroupCallInfo, CallError> = stopGroupCall(account: account, callId: value.id, accessHash: value.accessHash)
|
||||
|> mapError { _ -> CallError in
|
||||
return .generic
|
||||
}
|
||||
|> map { _ -> GroupCallInfo in
|
||||
}
|
||||
|
||||
return stopped
|
||||
|> then(currentOrRequestedCall)
|
||||
}*/
|
||||
|
||||
self.requestDisposable.set((currentOrRequestedCall
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl)
|
||||
|
||||
if let value = value {
|
||||
strongSelf.initialCall = CachedChannelData.ActiveCall(id: value.id, accessHash: value.accessHash)
|
||||
|
||||
strongSelf.updateSessionState(internalState: .active(value), audioSessionControl: strongSelf.audioSessionControl)
|
||||
} else {
|
||||
strongSelf._canBeRemoved.set(.single(true))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
@ -868,7 +872,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if shouldBeSendingTyping != strongSelf.isSendingTyping {
|
||||
strongSelf.isSendingTyping = shouldBeSendingTyping
|
||||
if shouldBeSendingTyping {
|
||||
strongSelf.typingDisposable.set(strongSelf.accountContext.account.acquireLocalInputActivity(peerId: PeerActivitySpace(peerId: strongSelf.peerId, category: .voiceChat), activity: .speakingInGroupCall))
|
||||
strongSelf.typingDisposable.set(strongSelf.accountContext.account.acquireLocalInputActivity(peerId: PeerActivitySpace(peerId: strongSelf.peerId, category: .voiceChat), activity: .speakingInGroupCall(timestamp: 0)))
|
||||
strongSelf.restartMyAudioLevelTimer()
|
||||
} else {
|
||||
strongSelf.typingDisposable.set(nil)
|
||||
|
@ -223,7 +223,7 @@ public final class VoiceChatController: ViewController {
|
||||
} else {
|
||||
microphoneColor = UIColor(rgb: 0x979797)
|
||||
}
|
||||
icon = .microphone(true, microphoneColor)
|
||||
icon = .microphone(self.muteState != nil, microphoneColor)
|
||||
case .speaking:
|
||||
text = .text(presentationData.strings.VoiceChat_StatusSpeaking, .constructive)
|
||||
icon = .microphone(false, UIColor(rgb: 0x34c759))
|
||||
@ -411,37 +411,38 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme))
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: peer, chatPeer: peer, action: .removeFromGroup, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.VoiceChat_RemovePeerRemove, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
if let callState = strongSelf.callState, (callState.canManageCall && !callState.adminIds.contains(strongSelf.context.account.peerId)) {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.dismissWithoutContent)
|
||||
|
||||
|
||||
}))
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme))
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: peer, chatPeer: peer, action: .removeFromGroup, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.VoiceChat_RemovePeerRemove, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
])
|
||||
strongSelf.controller?.present(actionSheet, in: .window(.root))
|
||||
})))
|
||||
strongSelf.controller?.present(actionSheet, in: .window(.root))
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1139,11 +1140,13 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
var callMembers = callMembers
|
||||
|
||||
callMembers.sort()
|
||||
|
||||
for i in 0 ..< callMembers.count {
|
||||
if callMembers[i].peer.id == self.context.account.peerId {
|
||||
let member = callMembers[i]
|
||||
callMembers.remove(at: i)
|
||||
callMembers.insert(member, at: i)
|
||||
callMembers.insert(member, at: 0)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -111,6 +111,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateChatListFilter(id: Int32, filter: Api.DialogFilter?)
|
||||
case UpdateReadThread(threadMessageId: MessageId, readMaxId: Int32, isIncoming: Bool, mainChannelMessage: MessageId?)
|
||||
case UpdateGroupCallParticipants(id: Int64, accessHash: Int64, participants: [Api.GroupCallParticipant], version: Int32)
|
||||
case UpdateGroupCall(call: Api.GroupCall)
|
||||
}
|
||||
|
||||
struct HoleFromPreviousState {
|
||||
@ -281,6 +282,10 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version))
|
||||
}
|
||||
|
||||
mutating func updateGroupCall(call: Api.GroupCall) {
|
||||
self.addOperation(.UpdateGroupCall(call: call))
|
||||
}
|
||||
|
||||
mutating func readGroupFeedInbox(groupId: PeerGroupId, index: MessageIndex) {
|
||||
self.addOperation(.ReadGroupFeedInbox(groupId, index))
|
||||
}
|
||||
@ -489,7 +494,7 @@ struct AccountMutableState {
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateMessagesPinned:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned:
|
||||
break
|
||||
case let .AddMessages(messages, location):
|
||||
for message in messages {
|
||||
@ -607,7 +612,7 @@ struct AccountReplayedFinalState {
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let addedCallSignalingData: [(Int64, Data)]
|
||||
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.StateUpdate)]
|
||||
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)]
|
||||
let updatedPeersNearby: [PeerNearby]?
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let delayNotificatonsUntil: Int32?
|
||||
@ -623,7 +628,7 @@ struct AccountFinalStateEvents {
|
||||
let updatedWebpages: [MediaId: TelegramMediaWebpage]
|
||||
let updatedCalls: [Api.PhoneCall]
|
||||
let addedCallSignalingData: [(Int64, Data)]
|
||||
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.StateUpdate)]
|
||||
let updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)]
|
||||
let updatedPeersNearby: [PeerNearby]?
|
||||
let isContactUpdates: [(PeerId, Bool)]
|
||||
let displayAlerts: [(text: String, isDropAuth: Bool)]
|
||||
@ -639,7 +644,7 @@ struct AccountFinalStateEvents {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.StateUpdate)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||
self.deletedMessageIds = deletedMessageIds
|
||||
|
@ -1221,7 +1221,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
updatedState.readSecretOutbox(peerId: PeerId(namespace: Namespaces.Peer.SecretChat, id: chatId), timestamp: maxDate, actionTimestamp: date)
|
||||
case let .updateUserTyping(userId, type):
|
||||
if let date = updatesDate, date + 60 > serverTime {
|
||||
let activity = PeerInputActivity(apiType: type)
|
||||
let activity = PeerInputActivity(apiType: type, timestamp: date)
|
||||
var category: PeerActivitySpace.Category = .global
|
||||
if case .speakingInGroupCall = activity {
|
||||
category = .voiceChat
|
||||
@ -1231,7 +1231,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
}
|
||||
case let .updateChatUserTyping(chatId, userId, type):
|
||||
if let date = updatesDate, date + 60 > serverTime {
|
||||
let activity = PeerInputActivity(apiType: type)
|
||||
let activity = PeerInputActivity(apiType: type, timestamp: date)
|
||||
var category: PeerActivitySpace.Category = .global
|
||||
if case .speakingInGroupCall = activity {
|
||||
category = .voiceChat
|
||||
@ -1244,7 +1244,7 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
let channelPeerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
|
||||
let threadId = topMsgId.flatMap { makeMessageThreadId(MessageId(peerId: channelPeerId, namespace: Namespaces.Message.Cloud, id: $0)) }
|
||||
|
||||
let activity = PeerInputActivity(apiType: type)
|
||||
let activity = PeerInputActivity(apiType: type, timestamp: date)
|
||||
var category: PeerActivitySpace.Category = .global
|
||||
if case .speakingInGroupCall = activity {
|
||||
category = .voiceChat
|
||||
@ -1332,6 +1332,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
|
||||
case let .inputGroupCall(id, accessHash):
|
||||
updatedState.updateGroupCallParticipants(id: id, accessHash: accessHash, participants: participants, version: version)
|
||||
}
|
||||
case let .updateGroupCall(call):
|
||||
updatedState.updateGroupCall(call: call)
|
||||
case let .updateLangPackTooLong(langCode):
|
||||
updatedState.updateLangPack(langCode: langCode, difference: nil)
|
||||
case let .updateLangPack(difference):
|
||||
@ -2135,7 +2137,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddScheduledMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -2222,7 +2224,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
var updatedWebpages: [MediaId: TelegramMediaWebpage] = [:]
|
||||
var updatedCalls: [Api.PhoneCall] = []
|
||||
var addedCallSignalingData: [(Int64, Data)] = []
|
||||
var updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.StateUpdate)] = []
|
||||
var updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = []
|
||||
var updatedPeersNearby: [PeerNearby]?
|
||||
var isContactUpdates: [(PeerId, Bool)] = []
|
||||
var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = []
|
||||
@ -2955,8 +2957,18 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
|
||||
case let .UpdateGroupCallParticipants(callId, _, participants, version):
|
||||
updatedGroupCallParticipants.append((
|
||||
callId,
|
||||
GroupCallParticipantsContext.StateUpdate(participants: participants, version: version)
|
||||
.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version))
|
||||
))
|
||||
case let .UpdateGroupCall(call):
|
||||
switch call {
|
||||
case .groupCall:
|
||||
break
|
||||
case let .groupCallDiscarded(callId, _, _):
|
||||
updatedGroupCallParticipants.append((
|
||||
callId,
|
||||
.call(isTerminated: true)
|
||||
))
|
||||
}
|
||||
case let .UpdateLangPack(langCode, difference):
|
||||
if let difference = difference {
|
||||
if langPackDifferences[langCode] == nil {
|
||||
|
@ -148,8 +148,8 @@ public final class AccountStateManager {
|
||||
return self.threadReadStateUpdatesPipe.signal()
|
||||
}
|
||||
|
||||
private let groupCallParticipantUpdatesPipe = ValuePipe<[(Int64, GroupCallParticipantsContext.StateUpdate)]>()
|
||||
public var groupCallParticipantUpdates: Signal<[(Int64, GroupCallParticipantsContext.StateUpdate)], NoError> {
|
||||
private let groupCallParticipantUpdatesPipe = ValuePipe<[(Int64, GroupCallParticipantsContext.Update)]>()
|
||||
public var groupCallParticipantUpdates: Signal<[(Int64, GroupCallParticipantsContext.Update)], NoError> {
|
||||
return self.groupCallParticipantUpdatesPipe.signal()
|
||||
}
|
||||
|
||||
|
@ -467,7 +467,7 @@ private func binaryInsertionIndex(_ inputArr: [GroupCallParticipantsContext.Part
|
||||
}
|
||||
|
||||
public final class GroupCallParticipantsContext {
|
||||
public struct Participant: Equatable {
|
||||
public struct Participant: Equatable, Comparable {
|
||||
public struct MuteState: Equatable {
|
||||
public var canUnmute: Bool
|
||||
|
||||
@ -500,6 +500,24 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public static func <(lhs: Participant, rhs: Participant) -> Bool {
|
||||
if let lhsActivityTimestamp = lhs.activityTimestamp, let rhsActivityTimestamp = rhs.activityTimestamp {
|
||||
if lhsActivityTimestamp != rhsActivityTimestamp {
|
||||
return lhsActivityTimestamp > rhsActivityTimestamp
|
||||
}
|
||||
} else if lhs.activityTimestamp != nil {
|
||||
return true
|
||||
} else if rhs.activityTimestamp != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.joinTimestamp != rhs.joinTimestamp {
|
||||
return lhs.joinTimestamp > rhs.joinTimestamp
|
||||
}
|
||||
|
||||
return lhs.peer.id < rhs.peer.id
|
||||
}
|
||||
}
|
||||
|
||||
public struct State: Equatable {
|
||||
@ -542,20 +560,25 @@ public final class GroupCallParticipantsContext {
|
||||
var overlayState: OverlayState
|
||||
}
|
||||
|
||||
public struct StateUpdate {
|
||||
public struct ParticipantUpdate {
|
||||
public var peerId: PeerId
|
||||
public var ssrc: UInt32
|
||||
public var joinTimestamp: Int32
|
||||
public var activityTimestamp: Int32?
|
||||
public var muteState: Participant.MuteState?
|
||||
public var isRemoved: Bool
|
||||
public enum Update {
|
||||
public struct StateUpdate {
|
||||
public struct ParticipantUpdate {
|
||||
public var peerId: PeerId
|
||||
public var ssrc: UInt32
|
||||
public var joinTimestamp: Int32
|
||||
public var activityTimestamp: Int32?
|
||||
public var muteState: Participant.MuteState?
|
||||
public var isRemoved: Bool
|
||||
}
|
||||
|
||||
public var participantUpdates: [ParticipantUpdate]
|
||||
public var version: Int32
|
||||
|
||||
public var removePendingMuteStates: Set<PeerId>
|
||||
}
|
||||
|
||||
public var participantUpdates: [ParticipantUpdate]
|
||||
public var version: Int32
|
||||
|
||||
public var removePendingMuteStates: Set<PeerId>
|
||||
case state(update: StateUpdate)
|
||||
case call(isTerminated: Bool)
|
||||
}
|
||||
|
||||
private let account: Account
|
||||
@ -597,7 +620,7 @@ public final class GroupCallParticipantsContext {
|
||||
return self.numberOfActiveSpeakersPromise.get()
|
||||
}
|
||||
|
||||
private var updateQueue: [StateUpdate] = []
|
||||
private var updateQueue: [Update.StateUpdate] = []
|
||||
private var isProcessingUpdate: Bool = false
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
@ -616,7 +639,7 @@ public final class GroupCallParticipantsContext {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var filteredUpdates: [StateUpdate] = []
|
||||
var filteredUpdates: [Update] = []
|
||||
for (callId, update) in updates {
|
||||
if callId == id {
|
||||
filteredUpdates.append(update)
|
||||
@ -635,6 +658,53 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
strongSelf.numberOfActiveSpeakersValue = activities.count
|
||||
|
||||
var updatedParticipants = strongSelf.stateValue.state.participants
|
||||
var indexMap: [PeerId: Int] = [:]
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
indexMap[updatedParticipants[i].peer.id] = i
|
||||
}
|
||||
var updated = false
|
||||
|
||||
for (activityPeerId, activity) in activities {
|
||||
if case let .speakingInGroupCall(timestamp) = activity {
|
||||
if let index = indexMap[activityPeerId] {
|
||||
if let activityTimestamp = updatedParticipants[index].activityTimestamp {
|
||||
if activityTimestamp < timestamp {
|
||||
updatedParticipants[index].activityTimestamp = timestamp
|
||||
updated = true
|
||||
}
|
||||
} else {
|
||||
updatedParticipants[index].activityTimestamp = timestamp
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
updatedParticipants.sort()
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
if updatedParticipants[i].peer.id == strongSelf.account.peerId {
|
||||
let member = updatedParticipants[i]
|
||||
updatedParticipants.remove(at: i)
|
||||
updatedParticipants.insert(member, at: 0)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.stateValue = InternalState(
|
||||
state: State(
|
||||
participants: updatedParticipants,
|
||||
nextParticipantsFetchOffset: strongSelf.stateValue.state.nextParticipantsFetchOffset,
|
||||
adminIds: strongSelf.stateValue.state.adminIds,
|
||||
isCreator: strongSelf.stateValue.state.isCreator,
|
||||
totalCount: strongSelf.stateValue.state.totalCount,
|
||||
version: strongSelf.stateValue.state.version
|
||||
),
|
||||
overlayState: strongSelf.stateValue.overlayState
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -644,9 +714,18 @@ public final class GroupCallParticipantsContext {
|
||||
self.activitiesDisposable?.dispose()
|
||||
}
|
||||
|
||||
public func addUpdates(updates: [StateUpdate]) {
|
||||
self.updateQueue.append(contentsOf: updates)
|
||||
self.beginProcessingUpdatesIfNeeded()
|
||||
public func addUpdates(updates: [Update]) {
|
||||
var stateUpdates: [Update.StateUpdate] = []
|
||||
for update in updates {
|
||||
if case let .state(update) = update {
|
||||
stateUpdates.append(update)
|
||||
}
|
||||
}
|
||||
|
||||
if !stateUpdates.isEmpty {
|
||||
self.updateQueue.append(contentsOf: stateUpdates)
|
||||
self.beginProcessingUpdatesIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private func beginProcessingUpdatesIfNeeded() {
|
||||
@ -667,7 +746,7 @@ public final class GroupCallParticipantsContext {
|
||||
self.beginProcessingUpdatesIfNeeded()
|
||||
}
|
||||
|
||||
private func processUpdate(update: StateUpdate) {
|
||||
private func processUpdate(update: Update.StateUpdate) {
|
||||
if update.version < self.stateValue.state.version {
|
||||
for peerId in update.removePendingMuteStates {
|
||||
self.stateValue.overlayState.pendingMuteStateChanges.removeValue(forKey: peerId)
|
||||
@ -702,7 +781,7 @@ public final class GroupCallParticipantsContext {
|
||||
return
|
||||
}
|
||||
|
||||
var updatedParticipants = Array(strongSelf.stateValue.state.participants.reversed())
|
||||
var updatedParticipants = strongSelf.stateValue.state.participants
|
||||
var updatedTotalCount = strongSelf.stateValue.state.totalCount
|
||||
|
||||
for participantUpdate in update.participantUpdates {
|
||||
@ -718,20 +797,29 @@ public final class GroupCallParticipantsContext {
|
||||
assertionFailure()
|
||||
continue
|
||||
}
|
||||
var previousActivityTimestamp: Int32?
|
||||
if let index = updatedParticipants.firstIndex(where: { $0.peer.id == participantUpdate.peerId }) {
|
||||
previousActivityTimestamp = updatedParticipants[index].activityTimestamp
|
||||
updatedParticipants.remove(at: index)
|
||||
} else {
|
||||
updatedTotalCount += 1
|
||||
}
|
||||
|
||||
var activityTimestamp: Int32?
|
||||
if let previousActivityTimestamp = previousActivityTimestamp, let updatedActivityTimestamp = participantUpdate.activityTimestamp {
|
||||
activityTimestamp = max(updatedActivityTimestamp, previousActivityTimestamp)
|
||||
} else {
|
||||
activityTimestamp = participantUpdate.activityTimestamp ?? previousActivityTimestamp
|
||||
}
|
||||
|
||||
let participant = Participant(
|
||||
peer: peer,
|
||||
ssrc: participantUpdate.ssrc,
|
||||
joinTimestamp: participantUpdate.joinTimestamp,
|
||||
activityTimestamp: activityTimestamp,
|
||||
muteState: participantUpdate.muteState
|
||||
)
|
||||
let index = binaryInsertionIndex(updatedParticipants, searchItem: participant.joinTimestamp)
|
||||
updatedParticipants.insert(participant, at: index)
|
||||
updatedParticipants.append(participant)
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,9 +832,19 @@ public final class GroupCallParticipantsContext {
|
||||
let adminIds = strongSelf.stateValue.state.adminIds
|
||||
let isCreator = strongSelf.stateValue.state.isCreator
|
||||
|
||||
updatedParticipants.sort()
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
if updatedParticipants[i].peer.id == strongSelf.account.peerId {
|
||||
let member = updatedParticipants[i]
|
||||
updatedParticipants.remove(at: i)
|
||||
updatedParticipants.insert(member, at: 0)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.stateValue = InternalState(
|
||||
state: State(
|
||||
participants: Array(updatedParticipants.reversed()),
|
||||
participants: updatedParticipants,
|
||||
nextParticipantsFetchOffset: nextParticipantsFetchOffset,
|
||||
adminIds: adminIds,
|
||||
isCreator: isCreator,
|
||||
@ -782,6 +880,14 @@ public final class GroupCallParticipantsContext {
|
||||
self.stateValue.overlayState.pendingMuteStateChanges.removeValue(forKey: peerId)
|
||||
}
|
||||
|
||||
for participant in self.stateValue.state.participants {
|
||||
if participant.peer.id == peerId {
|
||||
if participant.muteState == muteState {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let disposable = MetaDisposable()
|
||||
self.stateValue.overlayState.pendingMuteStateChanges[peerId] = OverlayState.MuteStateChange(
|
||||
state: muteState,
|
||||
@ -800,7 +906,7 @@ public final class GroupCallParticipantsContext {
|
||||
return .single(nil)
|
||||
}
|
||||
var flags: Int32 = 0
|
||||
if let muteState = muteState, !muteState.canUnmute {
|
||||
if let muteState = muteState, (!muteState.canUnmute || peerId == account.peerId) {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
|
||||
@ -818,7 +924,7 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
if let updates = updates {
|
||||
var stateUpdates: [GroupCallParticipantsContext.StateUpdate] = []
|
||||
var stateUpdates: [GroupCallParticipantsContext.Update] = []
|
||||
|
||||
loop: for update in updates.allUpdates {
|
||||
switch update {
|
||||
@ -829,7 +935,7 @@ public final class GroupCallParticipantsContext {
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
stateUpdates.append(GroupCallParticipantsContext.StateUpdate(participants: participants, version: version, removePendingMuteStates: [peerId]))
|
||||
stateUpdates.append(.state(update: GroupCallParticipantsContext.Update.StateUpdate(participants: participants, version: version, removePendingMuteStates: [peerId])))
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -845,9 +951,9 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
}
|
||||
|
||||
extension GroupCallParticipantsContext.StateUpdate {
|
||||
extension GroupCallParticipantsContext.Update.StateUpdate {
|
||||
init(participants: [Api.GroupCallParticipant], version: Int32, removePendingMuteStates: Set<PeerId> = Set()) {
|
||||
var participantUpdates: [GroupCallParticipantsContext.StateUpdate.ParticipantUpdate] = []
|
||||
var participantUpdates: [GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate] = []
|
||||
for participant in participants {
|
||||
switch participant {
|
||||
case let .groupCallParticipant(flags, userId, date, activeDate, source):
|
||||
@ -859,7 +965,7 @@ extension GroupCallParticipantsContext.StateUpdate {
|
||||
muteState = GroupCallParticipantsContext.Participant.MuteState(canUnmute: canUnmute)
|
||||
}
|
||||
let isRemoved = (flags & (1 << 1)) != 0
|
||||
participantUpdates.append(GroupCallParticipantsContext.StateUpdate.ParticipantUpdate(
|
||||
participantUpdates.append(GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate(
|
||||
peerId: peerId,
|
||||
ssrc: ssrc,
|
||||
joinTimestamp: date,
|
||||
|
@ -10,7 +10,7 @@ public enum PeerInputActivity: Comparable {
|
||||
case playingGame
|
||||
case recordingInstantVideo
|
||||
case uploadingInstantVideo(progress: Int32)
|
||||
case speakingInGroupCall
|
||||
case speakingInGroupCall(timestamp: Int32)
|
||||
|
||||
public var key: Int32 {
|
||||
switch self {
|
||||
@ -41,7 +41,7 @@ public enum PeerInputActivity: Comparable {
|
||||
}
|
||||
|
||||
extension PeerInputActivity {
|
||||
init?(apiType: Api.SendMessageAction) {
|
||||
init?(apiType: Api.SendMessageAction, timestamp: Int32) {
|
||||
switch apiType {
|
||||
case .sendMessageCancelAction, .sendMessageChooseContactAction, .sendMessageGeoLocationAction, .sendMessageRecordVideoAction:
|
||||
return nil
|
||||
@ -62,7 +62,7 @@ extension PeerInputActivity {
|
||||
case let .sendMessageUploadRoundAction(progress):
|
||||
self = .uploadingInstantVideo(progress: progress)
|
||||
case .speakingInGroupCallAction:
|
||||
self = .speakingInGroupCall
|
||||
self = .speakingInGroupCall(timestamp: timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,9 +408,9 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
//TODO:localize
|
||||
let titleString: String
|
||||
if let duration = duration {
|
||||
titleString = "Group Call \(duration)s"
|
||||
titleString = "Voice chat ended (\(duration)s)"
|
||||
} else {
|
||||
titleString = "Group Call"
|
||||
titleString = "Voice chat started"
|
||||
}
|
||||
attributedString = NSAttributedString(string: titleString, font: titleFont, textColor: primaryTextColor)
|
||||
case let .customText(text, entities):
|
||||
|
@ -5986,7 +5986,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return
|
||||
}
|
||||
let callResult = strongSelf.context.sharedContext.callManager?.requestOrJoinGroupCall(context: strongSelf.context, peerId: peer.id, initialCall: activeCall, endCurrentIfAny: false, sourcePanel: nil)
|
||||
let callResult = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peer.id, initialCall: activeCall, endCurrentIfAny: false, sourcePanel: nil)
|
||||
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
|
||||
if currentPeerId == peer.id {
|
||||
strongSelf.context.sharedContext.navigateToCurrentCall(sourcePanel: nil)
|
||||
@ -5999,7 +5999,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let strongSelf = self, let current = current {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||
if let strongSelf = self {
|
||||
let _ = strongSelf.context.sharedContext.callManager?.requestOrJoinGroupCall(context: strongSelf.context, peerId: peer.id, initialCall: activeCall, endCurrentIfAny: true, sourcePanel: nil)
|
||||
let _ = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peer.id, initialCall: activeCall, endCurrentIfAny: true, sourcePanel: nil)
|
||||
}
|
||||
})]), in: .window(.root))
|
||||
} else {
|
||||
|
@ -949,7 +949,6 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
||||
displayLeave = false
|
||||
if channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers) {
|
||||
result.append(.addMember)
|
||||
result.append(.call)
|
||||
}
|
||||
}
|
||||
switch channel.participationStatus {
|
||||
|
@ -2966,6 +2966,16 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if case .group = channel.info, !channel.flags.contains(.hasVoiceChat) {
|
||||
if channel.flags.contains(.isCreator) || channel.hasPermission(.manageCalls) {
|
||||
//TODO:localize
|
||||
items.append(ActionSheetButtonItem(title: "Create Voice Chat", color: .accent, action: { [weak self] in
|
||||
dismissAction()
|
||||
self?.requestCall(isVideo: false)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
if let cachedData = self.data?.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) {
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.ChannelInfo_Stats, color: .accent, action: { [weak self] in
|
||||
dismissAction()
|
||||
@ -3169,7 +3179,41 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
guard let cachedChannelData = self.data?.cachedData as? CachedChannelData else {
|
||||
return
|
||||
}
|
||||
let _ = self.context.sharedContext.callManager?.requestOrJoinGroupCall(context: self.context, peerId: peer.id, initialCall: cachedChannelData.activeCall, endCurrentIfAny: false, sourcePanel: nil)
|
||||
|
||||
if let activeCall = cachedChannelData.activeCall {
|
||||
let _ = self.context.sharedContext.callManager?.joinGroupCall(context: self.context, peerId: peer.id, initialCall: activeCall, endCurrentIfAny: false, sourcePanel: nil)
|
||||
} else {
|
||||
var dismissStatus: (() -> Void)?
|
||||
let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: {
|
||||
dismissStatus?()
|
||||
}))
|
||||
dismissStatus = { [weak self, weak statusController] in
|
||||
self?.activeActionDisposable.set(nil)
|
||||
statusController?.dismiss()
|
||||
}
|
||||
self.controller?.present(statusController, in: .window(.root))
|
||||
self.activeActionDisposable.set((createGroupCall(account: self.context.account, peerId: peer.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] info in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peer.id, initialCall: CachedChannelData.ActiveCall(id: info.id, accessHash: info.accessHash), endCurrentIfAny: false, sourcePanel: nil)
|
||||
}, error: { [weak self] _ in
|
||||
dismissStatus?()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel)
|
||||
}, completed: { [weak self] in
|
||||
dismissStatus?()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.cancel)
|
||||
}))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 353184e3e5c5e560a59cb836ca8de496c0cc95bb
|
||||
Subproject commit 7f2022780754c0b3a23f8ce8a940042101120077
|
Loading…
x
Reference in New Issue
Block a user