mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +00:00
Voice chat fixes
This commit is contained in:
parent
5f19374c9d
commit
fab42fd01d
@ -302,6 +302,8 @@ public protocol PresentationGroupCall: class {
|
||||
func invitePeer(_ peerId: PeerId) -> Bool
|
||||
func removedPeer(_ peerId: PeerId)
|
||||
var invitedPeers: Signal<[PeerId], NoError> { get }
|
||||
|
||||
func loadMoreMembers(token: String)
|
||||
}
|
||||
|
||||
public protocol PresentationCallManager: class {
|
||||
|
||||
@ -57,7 +57,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext {
|
||||
groupCall: nil
|
||||
)))
|
||||
|
||||
self.disposable = (getGroupCallParticipants(account: account, callId: call.id, accessHash: call.accessHash, offset: "", limit: 100)
|
||||
self.disposable = (getGroupCallParticipants(account: account, callId: call.id, accessHash: call.accessHash, offset: "", peerIds: [], limit: 100)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
|
||||
return .single(nil)
|
||||
@ -1476,4 +1476,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
public func updateDefaultParticipantsAreMuted(isMuted: Bool) {
|
||||
self.participantsContext?.updateDefaultParticipantsAreMuted(isMuted: isMuted)
|
||||
}
|
||||
|
||||
public func loadMoreMembers(token: String) {
|
||||
self.participantsContext?.loadMore(token: token)
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,14 +375,14 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
|
||||
private func preparedTransition(from fromEntries: [ListEntry], to toEntries: [ListEntry], isLoading: Bool, isEmpty: Bool, crossFade: Bool, animated: Bool, context: AccountContext, presentationData: PresentationData, interaction: Interaction) -> ListTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, interaction: interaction), directionHint: nil) }
|
||||
|
||||
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, animated: true)
|
||||
return ListTransition(deletions: deletions, insertions: insertions, updates: updates, isLoading: isLoading, isEmpty: isEmpty, crossFade: crossFade, count: toEntries.count, animated: animated)
|
||||
}
|
||||
|
||||
private weak var controller: VoiceChatController?
|
||||
@ -424,7 +424,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var currentTitle: String = ""
|
||||
private var currentSubtitle: String = ""
|
||||
private var currentCallMembers: [GroupCallParticipantsContext.Participant]?
|
||||
private var currentCallMembers: ([GroupCallParticipantsContext.Participant], String?)?
|
||||
private var currentInvitedPeers: [Peer]?
|
||||
private var currentSpeakingPeers: Set<PeerId>?
|
||||
private var currentContentOffset: CGFloat?
|
||||
@ -445,6 +445,8 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var callState: PresentationGroupCallState?
|
||||
|
||||
private var currentLoadToken: String?
|
||||
|
||||
private var effectiveMuteState: GroupCallParticipantsContext.Participant.MuteState? {
|
||||
if self.pushingToTalk {
|
||||
return nil
|
||||
@ -577,7 +579,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
var filters: [ChannelMembersSearchFilter] = []
|
||||
if let currentCallMembers = strongSelf.currentCallMembers {
|
||||
if let (currentCallMembers, _) = strongSelf.currentCallMembers {
|
||||
filters.append(.disable(Array(currentCallMembers.map { $0.peer.id })))
|
||||
}
|
||||
if let groupPeer = groupPeer as? TelegramChannel {
|
||||
@ -1030,7 +1032,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: callMembers?.participants ?? [], invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: (callMembers?.participants ?? [], callMembers?.loadMoreToken), invitedPeers: invitedPeers, speakingPeers: callMembers?.speakingParticipants ?? [])
|
||||
|
||||
let subtitle = strongSelf.presentationData.strings.VoiceChat_Panel_Members(Int32(max(1, callMembers?.totalCount ?? 0)))
|
||||
strongSelf.currentSubtitle = subtitle
|
||||
@ -1059,7 +1061,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
if !strongSelf.didSetDataReady {
|
||||
strongSelf.accountPeer = accountPeer
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? [], invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||
strongSelf.updateMembers(muteState: strongSelf.effectiveMuteState, callMembers: strongSelf.currentCallMembers ?? ([], nil), invitedPeers: strongSelf.currentInvitedPeers ?? [], speakingPeers: strongSelf.currentSpeakingPeers ?? Set())
|
||||
|
||||
strongSelf.didSetDataReady = true
|
||||
strongSelf.controller?.dataReady.set(true)
|
||||
@ -1223,6 +1225,18 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if case let .known(value) = offset, value < 100.0 {
|
||||
if let loadMoreToken = strongSelf.currentCallMembers?.1 {
|
||||
strongSelf.currentLoadToken = loadMoreToken
|
||||
strongSelf.call.loadMoreMembers(token: loadMoreToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.memberEventsDisposable.set((self.call.memberEvents
|
||||
|> deliverOnMainQueue).start(next: { [weak self] event in
|
||||
guard let strongSelf = self else {
|
||||
@ -1336,7 +1350,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
}
|
||||
|
||||
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
|
||||
@ -1381,7 +1395,7 @@ public final class VoiceChatController: ViewController {
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? [], invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set())
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -2030,7 +2044,12 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: [GroupCallParticipantsContext.Participant], invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
|
||||
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set<PeerId>) {
|
||||
var disableAnimation = false
|
||||
if self.currentCallMembers?.1 != callMembers.1 {
|
||||
disableAnimation = true
|
||||
}
|
||||
|
||||
self.currentCallMembers = callMembers
|
||||
self.currentSpeakingPeers = speakingPeers
|
||||
self.currentInvitedPeers = invitedPeers
|
||||
@ -2044,7 +2063,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
entries.append(.invite(self.presentationData.theme, self.presentationData.strings, self.presentationData.strings.VoiceChat_InviteMember))
|
||||
|
||||
for member in callMembers {
|
||||
for member in callMembers.0 {
|
||||
if processedPeerIds.contains(member.peer.id) {
|
||||
continue
|
||||
}
|
||||
@ -2109,7 +2128,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.currentEntries = entries
|
||||
|
||||
let presentationData = self.presentationData.withUpdated(theme: self.darkTheme)
|
||||
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
|
||||
let transition = preparedTransition(from: previousEntries, to: entries, isLoading: false, isEmpty: false, crossFade: false, animated: !disableAnimation, context: self.context, presentationData: presentationData, interaction: self.itemInteraction!)
|
||||
self.enqueueTransition(transition)
|
||||
}
|
||||
|
||||
|
||||
@ -187,8 +187,8 @@ public enum GetGroupCallParticipantsError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), ids: [], sources: [], offset: offset, limit: limit))
|
||||
public func getGroupCallParticipants(account: Account, callId: Int64, accessHash: Int64, offset: String, peerIds: [PeerId], limit: Int32) -> Signal<GroupCallParticipantsContext.State, GetGroupCallParticipantsError> {
|
||||
return account.network.request(Api.functions.phone.getGroupParticipants(call: .inputGroupCall(id: callId, accessHash: accessHash), ids: peerIds.map { $0.id }, sources: [], offset: offset, limit: limit))
|
||||
|> mapError { _ -> GetGroupCallParticipantsError in
|
||||
return .generic
|
||||
}
|
||||
@ -368,7 +368,7 @@ public func joinGroupCall(account: Account, peerId: PeerId, callId: Int64, acces
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
},
|
||||
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", limit: 100)
|
||||
getGroupCallParticipants(account: account, callId: callId, accessHash: accessHash, offset: "", peerIds: [], limit: 100)
|
||||
|> mapError { _ -> JoinGroupCallError in
|
||||
return .generic
|
||||
},
|
||||
@ -718,7 +718,7 @@ public final class GroupCallParticipantsContext {
|
||||
private let id: Int64
|
||||
private let accessHash: Int64
|
||||
|
||||
private var hasReceivedSpeackingParticipantsReport: Bool = false
|
||||
private var hasReceivedSpeakingParticipantsReport: Bool = false
|
||||
|
||||
private var stateValue: InternalState {
|
||||
didSet {
|
||||
@ -770,6 +770,10 @@ public final class GroupCallParticipantsContext {
|
||||
private let updatesDisposable = MetaDisposable()
|
||||
private var activitiesDisposable: Disposable?
|
||||
|
||||
private var isLoadingMore: Bool = false
|
||||
private var shouldResetStateFromServer: Bool = false
|
||||
private var missingPeerIds = Set<PeerId>()
|
||||
|
||||
private let updateDefaultMuteDisposable = MetaDisposable()
|
||||
|
||||
public init(account: Account, peerId: PeerId, id: Int64, accessHash: Int64, state: State) {
|
||||
@ -802,11 +806,14 @@ public final class GroupCallParticipantsContext {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.activeSpeakersValue = Set(activities.map { item -> PeerId in
|
||||
let peerIds = Set(activities.map { item -> PeerId in
|
||||
item.0
|
||||
})
|
||||
strongSelf.activeSpeakersValue = peerIds
|
||||
|
||||
if !strongSelf.hasReceivedSpeackingParticipantsReport {
|
||||
strongSelf.ensureHaveParticipants(peerIds: peerIds)
|
||||
|
||||
if !strongSelf.hasReceivedSpeakingParticipantsReport {
|
||||
var updatedParticipants = strongSelf.stateValue.state.participants
|
||||
var indexMap: [PeerId: Int] = [:]
|
||||
for i in 0 ..< updatedParticipants.count {
|
||||
@ -885,7 +892,7 @@ public final class GroupCallParticipantsContext {
|
||||
|
||||
public func reportSpeakingParticipants(ids: [PeerId]) {
|
||||
if !ids.isEmpty {
|
||||
self.hasReceivedSpeackingParticipantsReport = true
|
||||
self.hasReceivedSpeakingParticipantsReport = true
|
||||
}
|
||||
|
||||
let strongSelf = self
|
||||
@ -942,6 +949,75 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
}
|
||||
|
||||
private func ensureHaveParticipants(peerIds: Set<PeerId>) {
|
||||
var missingPeerIds = Set<PeerId>()
|
||||
|
||||
var existingParticipantIds = Set<PeerId>()
|
||||
for participant in self.stateValue.state.participants {
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
}
|
||||
|
||||
for peerId in peerIds {
|
||||
if !existingParticipantIds.contains(peerId) {
|
||||
missingPeerIds.insert(peerId)
|
||||
}
|
||||
}
|
||||
|
||||
if !missingPeerIds.isEmpty {
|
||||
self.missingPeerIds.formUnion(missingPeerIds)
|
||||
self.loadMissingPeers()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadMissingPeers() {
|
||||
if self.missingPeerIds.isEmpty {
|
||||
return
|
||||
}
|
||||
if self.isLoadingMore {
|
||||
return
|
||||
}
|
||||
self.isLoadingMore = true
|
||||
|
||||
let peerIds = self.missingPeerIds
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", peerIds: Array(peerIds), limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
|
||||
strongSelf.missingPeerIds.subtract(peerIds)
|
||||
|
||||
var updatedState = strongSelf.stateValue.state
|
||||
|
||||
var existingParticipantIds = Set<PeerId>()
|
||||
for participant in updatedState.participants {
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
}
|
||||
for participant in state.participants {
|
||||
if existingParticipantIds.contains(participant.peer.id) {
|
||||
continue
|
||||
}
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
updatedState.participants.append(participant)
|
||||
}
|
||||
|
||||
updatedState.participants.sort()
|
||||
|
||||
updatedState.totalCount = max(updatedState.totalCount, state.totalCount)
|
||||
updatedState.version = max(updatedState.version, updatedState.version)
|
||||
|
||||
strongSelf.stateValue.state = updatedState
|
||||
|
||||
if strongSelf.shouldResetStateFromServer {
|
||||
strongSelf.resetStateFromServer()
|
||||
} else {
|
||||
strongSelf.loadMissingPeers()
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func beginProcessingUpdatesIfNeeded() {
|
||||
if self.isProcessingUpdate {
|
||||
return
|
||||
@ -1080,13 +1156,22 @@ public final class GroupCallParticipantsContext {
|
||||
}
|
||||
|
||||
private func resetStateFromServer() {
|
||||
if self.isLoadingMore {
|
||||
self.shouldResetStateFromServer = true
|
||||
return
|
||||
}
|
||||
|
||||
self.isLoadingMore = true
|
||||
|
||||
self.updateQueue.removeAll()
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", limit: 100)
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: "", peerIds: [], limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
strongSelf.shouldResetStateFromServer = false
|
||||
strongSelf.stateValue.state = state
|
||||
strongSelf.endedProcessingUpdate()
|
||||
}))
|
||||
@ -1189,6 +1274,49 @@ public final class GroupCallParticipantsContext {
|
||||
strongSelf.account.stateManager.addUpdates(updates)
|
||||
}))
|
||||
}
|
||||
|
||||
public func loadMore(token: String) {
|
||||
if token != self.stateValue.state.nextParticipantsFetchOffset {
|
||||
Logger.shared.log("GroupCallParticipantsContext", "loadMore called with an invalid token \(token) (the valid one is \(String(describing: self.stateValue.state.nextParticipantsFetchOffset)))")
|
||||
return
|
||||
}
|
||||
if self.isLoadingMore {
|
||||
return
|
||||
}
|
||||
self.isLoadingMore = true
|
||||
|
||||
self.disposable.set((getGroupCallParticipants(account: self.account, callId: self.id, accessHash: self.accessHash, offset: token, peerIds: [], limit: 100)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.isLoadingMore = false
|
||||
|
||||
var updatedState = strongSelf.stateValue.state
|
||||
|
||||
var existingParticipantIds = Set<PeerId>()
|
||||
for participant in updatedState.participants {
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
}
|
||||
for participant in state.participants {
|
||||
if existingParticipantIds.contains(participant.peer.id) {
|
||||
continue
|
||||
}
|
||||
existingParticipantIds.insert(participant.peer.id)
|
||||
updatedState.participants.append(participant)
|
||||
}
|
||||
|
||||
updatedState.nextParticipantsFetchOffset = state.nextParticipantsFetchOffset
|
||||
updatedState.totalCount = max(updatedState.totalCount, state.totalCount)
|
||||
updatedState.version = max(updatedState.version, updatedState.version)
|
||||
|
||||
strongSelf.stateValue.state = updatedState
|
||||
|
||||
if strongSelf.shouldResetStateFromServer {
|
||||
strongSelf.resetStateFromServer()
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user