mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 03:09:56 +00:00
Group member search actions
This commit is contained in:
parent
2bea22c23b
commit
4881f49bf1
@ -473,7 +473,7 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon
|
||||
}
|
||||
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
@ -669,6 +669,8 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon
|
||||
presentControllerImpl?(channelAdminController(account: account, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
|
||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
}, present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -311,7 +311,7 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
@ -477,6 +477,8 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View
|
||||
arguments.openPeerInfo(rendered.peer)
|
||||
}
|
||||
}
|
||||
}, present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -379,9 +379,29 @@ private final class ChannelMemberSingleCategoryListContext: ChannelMemberCategor
|
||||
}
|
||||
}
|
||||
case let .recentSearch(query):
|
||||
break
|
||||
default:
|
||||
break
|
||||
if let updated = updated, isParticipantMember(updated.participant), updated.peer.indexName.matchesByTokens(query) {
|
||||
var found = false
|
||||
loop: for i in 0 ..< list.count {
|
||||
if list[i].peer.id == updated.peer.id {
|
||||
list[i] = updated
|
||||
found = true
|
||||
updatedList = true
|
||||
break loop
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
list.insert(updated, at: 0)
|
||||
updatedList = true
|
||||
}
|
||||
} else if let previous = previous, isParticipantMember(previous) {
|
||||
loop: for i in 0 ..< list.count {
|
||||
if list[i].peer.id == previous.peerId {
|
||||
list.remove(at: i)
|
||||
updatedList = true
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if updatedList {
|
||||
|
||||
@ -310,7 +310,7 @@ public func channelMembersController(account: Account, peerId: PeerId) -> ViewCo
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
@ -444,6 +444,8 @@ public func channelMembersController(account: Account, peerId: PeerId) -> ViewCo
|
||||
pushControllerImpl?(infoController)
|
||||
// arguments.pushController(infoController)
|
||||
}
|
||||
}, present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ private enum ChannelMembersSearchSection {
|
||||
|
||||
private enum ChannelMembersSearchContent: Equatable {
|
||||
case peer(Peer)
|
||||
case participant(participant: RenderedChannelParticipant, label: String?, revealActions: [ParticipantRevealAction], enabled: Bool)
|
||||
case participant(participant: RenderedChannelParticipant, label: String?, revealActions: [ParticipantRevealAction], revealed: Bool, enabled: Bool)
|
||||
|
||||
static func ==(lhs: ChannelMembersSearchContent, rhs: ChannelMembersSearchContent) -> Bool {
|
||||
switch lhs {
|
||||
@ -45,8 +45,8 @@ private enum ChannelMembersSearchContent: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .participant(participant, label, revealActions, enabled):
|
||||
if case .participant(participant, label, revealActions, enabled) = rhs {
|
||||
case let .participant(participant, label, revealActions, revealed, enabled):
|
||||
if case .participant(participant, label, revealActions, revealed, enabled) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -58,12 +58,28 @@ private enum ChannelMembersSearchContent: Equatable {
|
||||
switch self {
|
||||
case let .peer(peer):
|
||||
return peer.id
|
||||
case let .participant(participant, _, _, _):
|
||||
case let .participant(participant, _, _, _, _):
|
||||
return participant.peer.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChannelMembersSearchContainerInteraction {
|
||||
let peerSelected: (Peer, RenderedChannelParticipant?) -> Void
|
||||
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
||||
let promotePeer: (RenderedChannelParticipant) -> Void
|
||||
let restrictPeer: (RenderedChannelParticipant) -> Void
|
||||
let removePeer: (PeerId) -> Void
|
||||
|
||||
init(peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, promotePeer: @escaping (RenderedChannelParticipant) -> Void, restrictPeer: @escaping (RenderedChannelParticipant) -> Void, removePeer: @escaping (PeerId) -> Void) {
|
||||
self.peerSelected = peerSelected
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.promotePeer = promotePeer
|
||||
self.restrictPeer = restrictPeer
|
||||
self.removePeer = removePeer
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
let index: Int
|
||||
let content: ChannelMembersSearchContent
|
||||
@ -87,31 +103,40 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ListViewItem {
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchContainerInteraction) -> ListViewItem {
|
||||
switch self.content {
|
||||
case let .peer(peer):
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
peerSelected(peer, nil)
|
||||
interaction.peerSelected(peer, nil)
|
||||
})
|
||||
case let .participant(participant, label, revealActions, enabled):
|
||||
case let .participant(participant, label, revealActions, revealed, enabled):
|
||||
let status: ContactsPeerItemStatus
|
||||
if let label = label {
|
||||
status = .custom(label)
|
||||
} else {
|
||||
status = .none
|
||||
}
|
||||
|
||||
var options: [ItemListPeerItemRevealOption] = []
|
||||
for action in revealActions {
|
||||
options.append(ItemListPeerItemRevealOption(type: action.type, title: action.title, action: {
|
||||
switch action.action {
|
||||
case .promote:
|
||||
//arguments.promotePeer(participant)
|
||||
interaction.promotePeer(participant)
|
||||
break
|
||||
case .restrict:
|
||||
//arguments.restrictPeer(participant)
|
||||
interaction.restrictPeer(participant)
|
||||
break
|
||||
case .remove:
|
||||
//arguments.removePeer(peer.id)
|
||||
interaction.removePeer(participant.peer.id)
|
||||
break
|
||||
}
|
||||
}))
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
peerSelected(participant.peer, participant)
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: revealed), options: options, index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
interaction.peerSelected(participant.peer, participant)
|
||||
}, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
|
||||
interaction.setPeerIdWithRevealedOptions(peerId, fromPeerId)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -123,16 +148,21 @@ struct ChannelMembersSearchContainerTransition {
|
||||
let isSearching: Bool
|
||||
}
|
||||
|
||||
private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ChannelMembersSearchContainerTransition {
|
||||
private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchContainerInteraction) -> ChannelMembersSearchContainerTransition {
|
||||
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(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) }
|
||||
|
||||
return ChannelMembersSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching)
|
||||
}
|
||||
|
||||
private struct ChannelMembersSearchContainerState: Equatable {
|
||||
var revealedPeerId: PeerId?
|
||||
var removingParticipantIds = Set<PeerId>()
|
||||
}
|
||||
|
||||
final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
private let account: Account
|
||||
private let openPeer: (Peer, RenderedChannelParticipant?) -> Void
|
||||
@ -150,9 +180,11 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private let removeMemberDisposable = MetaDisposable()
|
||||
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)>
|
||||
|
||||
init(account: Account, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping(Bool)->Void) {
|
||||
init(account: Account, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, updateActivity: @escaping (Bool) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.account = account
|
||||
self.openPeer = openPeer
|
||||
self.mode = mode
|
||||
@ -173,194 +205,323 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
self.addSubnode(self.dimNode)
|
||||
self.addSubnode(self.listNode)
|
||||
|
||||
let themeAndStringsPromise = self.themeAndStringsPromise
|
||||
let foundItems = searchQuery.get()
|
||||
|> mapToSignal { query -> Signal<[ChannelMembersSearchEntry]?, NoError> in
|
||||
updateActivity(true)
|
||||
if let query = query, !query.isEmpty {
|
||||
let foundGroupMembers: Signal<[RenderedChannelParticipant], NoError>
|
||||
let foundMembers: Signal<[RenderedChannelParticipant], NoError>
|
||||
|
||||
switch mode {
|
||||
case .searchMembers, .banAndPromoteActions:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.recent(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
case .inviteActions:
|
||||
foundGroupMembers = .single([])
|
||||
foundMembers = channelMembers(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, category: .recent(.search(query)))
|
||||
|> map { $0 ?? [] }
|
||||
case .searchAdmins:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.admins(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
} |> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
case .searchBanned:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.restrictedAndBanned(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
} |> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
let statePromise = ValuePromise(ChannelMembersSearchContainerState(), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: ChannelMembersSearchContainerState())
|
||||
let updateState: ((ChannelMembersSearchContainerState) -> ChannelMembersSearchContainerState) -> Void = { f in
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
let removeMemberDisposable = self.removeMemberDisposable
|
||||
let interaction = ChannelMembersSearchContainerInteraction(peerSelected: { peer, participant in
|
||||
openPeer(peer, participant)
|
||||
}, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
|
||||
updateState { state in
|
||||
var state = state
|
||||
if (peerId == nil && fromPeerId == state.revealedPeerId) || (peerId != nil && fromPeerId == nil) {
|
||||
state.revealedPeerId = peerId
|
||||
}
|
||||
return state
|
||||
}
|
||||
}, promotePeer: { participant in
|
||||
present(channelAdminController(account: account, peerId: peerId, adminId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, restrictPeer: { participant in
|
||||
present(channelBannedMemberController(account: account, peerId: peerId, memberId: participant.peer.id, initialParticipant: participant.participant, updated: { _ in
|
||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, removePeer: { memberId in
|
||||
let signal = account.postbox.loadedPeerWithId(memberId)
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { peer -> Signal<Bool, NoError> in
|
||||
let result = ValuePromise<Bool>()
|
||||
result.set(true)
|
||||
return result.get()
|
||||
}
|
||||
|> mapToSignal { value -> Signal<Void, NoError> in
|
||||
if value {
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.removingParticipantIds.insert(memberId)
|
||||
return state
|
||||
}
|
||||
|
||||
let foundContacts: Signal<([Peer], [PeerId: PeerPresence]), NoError>
|
||||
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer]), NoError>
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
foundContacts = account.postbox.searchContacts(query: query.lowercased())
|
||||
foundRemotePeers = .single(([], [])) |> then(searchPeers(account: account, query: query)
|
||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue()))
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
foundContacts = .single(([], [:]))
|
||||
foundRemotePeers = .single(([], []))
|
||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
return account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(account: account, peerId: peerId, memberId: memberId, bannedRights: TelegramChannelBannedRights(flags: [.banReadMessages], untilDate: Int32.max))
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.removingParticipantIds.remove(memberId)
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(foundGroupMembers, foundMembers, foundContacts, foundRemotePeers, themeAndStringsPromise.get())
|
||||
|> map { foundGroupMembers, foundMembers, foundContacts, foundRemotePeers, themeAndStrings -> [ChannelMembersSearchEntry]? in
|
||||
var entries: [ChannelMembersSearchEntry] = []
|
||||
|
||||
var existingPeerIds = Set<PeerId>()
|
||||
for filter in filters {
|
||||
switch filter {
|
||||
case let .exclude(ids):
|
||||
existingPeerIds = existingPeerIds.union(ids)
|
||||
case .disable:
|
||||
break
|
||||
}
|
||||
}
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
existingPeerIds.insert(account.peerId)
|
||||
case .searchMembers, .searchAdmins, .searchBanned:
|
||||
break
|
||||
}
|
||||
|
||||
var index = 0
|
||||
|
||||
for participant in foundGroupMembers {
|
||||
if !existingPeerIds.contains(participant.peer.id) {
|
||||
existingPeerIds.insert(participant.peer.id)
|
||||
let section: ChannelMembersSearchSection
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
section = .members
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
section = .none
|
||||
}
|
||||
|
||||
var label: String?
|
||||
var enabled = true
|
||||
if case .banAndPromoteActions = mode {
|
||||
if case .creator = participant.participant {
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
switch mode {
|
||||
case .searchAdmins:
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
case let .member(_, _, adminInfo, _):
|
||||
if let adminInfo = adminInfo {
|
||||
if let peer = participant.peers[adminInfo.promotedBy] {
|
||||
label = themeAndStrings.1.Channel_Management_PromotedBy(peer.displayTitle).0
|
||||
}
|
||||
}
|
||||
}
|
||||
case .searchBanned:
|
||||
switch participant.participant {
|
||||
case let .member(_, _, _, banInfo):
|
||||
if let banInfo = banInfo, let peer = participant.peers[banInfo.restrictedBy] {
|
||||
label = themeAndStrings.1.Channel_Management_RestrictedBy(peer.displayTitle).0
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant: participant, label: label, revealActions: [], enabled: enabled), section: section))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for participant in foundMembers {
|
||||
if !existingPeerIds.contains(participant.peer.id) {
|
||||
existingPeerIds.insert(participant.peer.id)
|
||||
let section: ChannelMembersSearchSection
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
section = .members
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
section = .none
|
||||
}
|
||||
|
||||
var label: String?
|
||||
var enabled = true
|
||||
if case .banAndPromoteActions = mode {
|
||||
if case .creator = participant.participant {
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant: participant, label: label, revealActions: [], enabled: enabled), section: section))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for peer in foundContacts.0 {
|
||||
if !existingPeerIds.contains(peer.id) {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .contacts))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for foundPeer in foundRemotePeers.0 {
|
||||
let peer = foundPeer.peer
|
||||
if !existingPeerIds.contains(peer.id) && peer is TelegramUser {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .global))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for foundPeer in foundRemotePeers.1 {
|
||||
let peer = foundPeer.peer
|
||||
if !existingPeerIds.contains(peer.id) && peer is TelegramUser {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .global))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
return removePeerMember(account: account, peerId: peerId, memberId: memberId)
|
||||
|> deliverOnMainQueue
|
||||
|> afterDisposed {
|
||||
updateState { state in
|
||||
var state = state
|
||||
state.removingParticipantIds.remove(memberId)
|
||||
return state
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
removeMemberDisposable.set(signal.start())
|
||||
})
|
||||
|
||||
let themeAndStringsPromise = self.themeAndStringsPromise
|
||||
let foundItems = combineLatest(searchQuery.get(), account.postbox.multiplePeersView([peerId]) |> take(1))
|
||||
|> mapToSignal { query, peerView -> Signal<[ChannelMembersSearchEntry]?, NoError> in
|
||||
guard let channel = peerView.peers[peerId] as? TelegramChannel else {
|
||||
return .single(nil)
|
||||
}
|
||||
updateActivity(true)
|
||||
if let query = query, !query.isEmpty {
|
||||
let foundGroupMembers: Signal<[RenderedChannelParticipant], NoError>
|
||||
let foundMembers: Signal<[RenderedChannelParticipant], NoError>
|
||||
|
||||
switch mode {
|
||||
case .searchMembers, .banAndPromoteActions:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.recent(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
case .inviteActions:
|
||||
foundGroupMembers = .single([])
|
||||
foundMembers = channelMembers(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, category: .recent(.search(query)))
|
||||
|> map { $0 ?? [] }
|
||||
case .searchAdmins:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.admins(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
} |> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
case .searchBanned:
|
||||
foundGroupMembers = Signal { subscriber in
|
||||
let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.restrictedAndBanned(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in
|
||||
if case .ready = state.loadingState {
|
||||
subscriber.putNext(state.list)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
})
|
||||
return disposable
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
foundMembers = .single([])
|
||||
}
|
||||
|
||||
let foundContacts: Signal<([Peer], [PeerId: PeerPresence]), NoError>
|
||||
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer]), NoError>
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
foundContacts = account.postbox.searchContacts(query: query.lowercased())
|
||||
foundRemotePeers = .single(([], [])) |> then(searchPeers(account: account, query: query)
|
||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue()))
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
foundContacts = .single(([], [:]))
|
||||
foundRemotePeers = .single(([], []))
|
||||
}
|
||||
|
||||
return combineLatest(foundGroupMembers, foundMembers, foundContacts, foundRemotePeers, themeAndStringsPromise.get(), statePromise.get())
|
||||
|> map { foundGroupMembers, foundMembers, foundContacts, foundRemotePeers, themeAndStrings, state -> [ChannelMembersSearchEntry]? in
|
||||
var entries: [ChannelMembersSearchEntry] = []
|
||||
|
||||
var existingPeerIds = Set<PeerId>()
|
||||
for filter in filters {
|
||||
switch filter {
|
||||
case let .exclude(ids):
|
||||
existingPeerIds = existingPeerIds.union(ids)
|
||||
case .disable:
|
||||
break
|
||||
}
|
||||
}
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
existingPeerIds.insert(account.peerId)
|
||||
case .searchMembers, .searchAdmins, .searchBanned:
|
||||
break
|
||||
}
|
||||
|
||||
var index = 0
|
||||
|
||||
for participant in foundGroupMembers {
|
||||
if !existingPeerIds.contains(participant.peer.id) {
|
||||
existingPeerIds.insert(participant.peer.id)
|
||||
let section: ChannelMembersSearchSection
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
section = .members
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
section = .none
|
||||
}
|
||||
|
||||
var canPromote: Bool
|
||||
var canRestrict: Bool
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
canPromote = false
|
||||
canRestrict = false
|
||||
case let .member(_, _, adminRights, bannedRights):
|
||||
if channel.hasAdminRights([.canAddAdmins]) {
|
||||
canPromote = true
|
||||
} else {
|
||||
canPromote = false
|
||||
}
|
||||
if channel.hasAdminRights([.canBanUsers]) {
|
||||
canRestrict = true
|
||||
} else {
|
||||
canRestrict = false
|
||||
}
|
||||
if canPromote {
|
||||
if let bannedRights = bannedRights {
|
||||
if bannedRights.restrictedBy != account.peerId && !channel.flags.contains(.isCreator) {
|
||||
canPromote = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if canRestrict {
|
||||
if let adminRights = adminRights {
|
||||
if adminRights.promotedBy != account.peerId && !channel.flags.contains(.isCreator) {
|
||||
canRestrict = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var label: String?
|
||||
var enabled = true
|
||||
if case .banAndPromoteActions = mode {
|
||||
if case .creator = participant.participant {
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
enabled = false
|
||||
}
|
||||
} else if case .searchMembers = mode {
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
case let .member(member):
|
||||
if member.adminInfo != nil {
|
||||
label = themeAndStrings.1.Channel_Management_LabelEditor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state.removingParticipantIds.contains(participant.peer.id) {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
var peerActions: [ParticipantRevealAction] = []
|
||||
if case .searchMembers = mode {
|
||||
if canPromote {
|
||||
peerActions.append(ParticipantRevealAction(type: .neutral, title: themeAndStrings.1.GroupInfo_ActionPromote, action: .promote))
|
||||
}
|
||||
if canRestrict {
|
||||
peerActions.append(ParticipantRevealAction(type: .warning, title: themeAndStrings.1.GroupInfo_ActionRestrict, action: .restrict))
|
||||
peerActions.append(ParticipantRevealAction(type: .destructive, title: themeAndStrings.1.Common_Delete, action: .remove))
|
||||
}
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .searchAdmins:
|
||||
switch participant.participant {
|
||||
case .creator:
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
case let .member(_, _, adminInfo, _):
|
||||
if let adminInfo = adminInfo {
|
||||
if let peer = participant.peers[adminInfo.promotedBy] {
|
||||
label = themeAndStrings.1.Channel_Management_PromotedBy(peer.displayTitle).0
|
||||
}
|
||||
}
|
||||
}
|
||||
case .searchBanned:
|
||||
switch participant.participant {
|
||||
case let .member(_, _, _, banInfo):
|
||||
if let banInfo = banInfo, let peer = participant.peers[banInfo.restrictedBy] {
|
||||
label = themeAndStrings.1.Channel_Management_RestrictedBy(peer.displayTitle).0
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant: participant, label: label, revealActions: peerActions, revealed: state.revealedPeerId == participant.peer.id, enabled: enabled), section: section))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for participant in foundMembers {
|
||||
if !existingPeerIds.contains(participant.peer.id) {
|
||||
existingPeerIds.insert(participant.peer.id)
|
||||
let section: ChannelMembersSearchSection
|
||||
switch mode {
|
||||
case .inviteActions, .banAndPromoteActions:
|
||||
section = .members
|
||||
case .searchMembers, .searchBanned, .searchAdmins:
|
||||
section = .none
|
||||
}
|
||||
|
||||
var label: String?
|
||||
var enabled = true
|
||||
if case .banAndPromoteActions = mode {
|
||||
if case .creator = participant.participant {
|
||||
label = themeAndStrings.1.Channel_Management_LabelCreator
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant: participant, label: label, revealActions: [], revealed: false, enabled: enabled), section: section))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for peer in foundContacts.0 {
|
||||
if !existingPeerIds.contains(peer.id) {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .contacts))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for foundPeer in foundRemotePeers.0 {
|
||||
let peer = foundPeer.peer
|
||||
if !existingPeerIds.contains(peer.id) && peer is TelegramUser {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .global))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
for foundPeer in foundRemotePeers.1 {
|
||||
let peer = foundPeer.peer
|
||||
if !existingPeerIds.contains(peer.id) && peer is TelegramUser {
|
||||
existingPeerIds.insert(peer.id)
|
||||
entries.append(ChannelMembersSearchEntry(index: index, content: .peer(peer), section: .global))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
let previousSearchItems = Atomic<[ChannelMembersSearchEntry]?>(value: nil)
|
||||
@ -371,24 +532,24 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
let previousEntries = previousSearchItems.swap(entries)
|
||||
updateActivity(false)
|
||||
let firstTime = previousEntries == nil
|
||||
let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, peerSelected: openPeer)
|
||||
let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, interaction: interaction)
|
||||
strongSelf.enqueueTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
}))
|
||||
|
||||
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
let previousStrings = strongSelf.presentationData.strings
|
||||
|
||||
strongSelf.presentationData = presentationData
|
||||
|
||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||
strongSelf.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
let previousStrings = strongSelf.presentationData.strings
|
||||
|
||||
strongSelf.presentationData = presentationData
|
||||
|
||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||
strongSelf.updateThemeAndStrings(theme: presentationData.theme, strings: presentationData.strings)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
self.listNode.beganInteractiveDragging = { [weak self] in
|
||||
self?.dismissInput?()
|
||||
@ -398,6 +559,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
deinit {
|
||||
self.searchDisposable.dispose()
|
||||
self.presentationDataDisposable?.dispose()
|
||||
self.removeMemberDisposable.dispose()
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
|
||||
@ -70,6 +70,9 @@ final class ChannelMembersSearchController: ViewController {
|
||||
self?.dismiss()
|
||||
self?.openPeer(peer, participant)
|
||||
}
|
||||
self.controllerNode.present = { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
@ -121,6 +121,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
||||
var requestActivateSearch: (() -> Void)?
|
||||
var requestDeactivateSearch: (() -> Void)?
|
||||
var requestOpenPeerFromSearch: ((Peer, RenderedChannelParticipant?) -> Void)?
|
||||
var present: ((ViewController, Any?) -> Void)?
|
||||
|
||||
var themeAndStrings: (PresentationTheme, PresentationStrings)
|
||||
|
||||
@ -292,6 +293,8 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
||||
self?.requestOpenPeerFromSearch?(peer, participant)
|
||||
}, updateActivity: { value in
|
||||
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present?(c, a)
|
||||
}), cancel: { [weak self] in
|
||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
|
||||
@ -115,6 +115,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
let enabled: Bool
|
||||
let selection: ContactsPeerItemSelection
|
||||
let editing: ContactsPeerItemEditing
|
||||
let options: [ItemListPeerItemRevealOption]
|
||||
let action: (ContactsPeerItemPeer) -> Void
|
||||
let setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)?
|
||||
let deletePeer: ((PeerId) -> Void)?
|
||||
@ -125,7 +126,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.sortOrder = sortOrder
|
||||
@ -138,6 +139,7 @@ class ContactsPeerItem: ListViewItem {
|
||||
self.enabled = enabled
|
||||
self.selection = selection
|
||||
self.editing = editing
|
||||
self.options = options
|
||||
self.action = action
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.deletePeer = deletePeer
|
||||
@ -562,6 +564,32 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
titleFrame = CGRect(origin: CGPoint(x: leftInset, y: 13.0), size: titleLayout.size)
|
||||
}
|
||||
|
||||
let peerRevealOptions: [ItemListRevealOption]
|
||||
if item.enabled {
|
||||
var mappedOptions: [ItemListRevealOption] = []
|
||||
var index: Int32 = 0
|
||||
for option in item.options {
|
||||
let color: UIColor
|
||||
let textColor: UIColor
|
||||
switch option.type {
|
||||
case .neutral:
|
||||
color = item.theme.list.itemDisclosureActions.constructive.fillColor
|
||||
textColor = item.theme.list.itemDisclosureActions.constructive.foregroundColor
|
||||
case .warning:
|
||||
color = item.theme.list.itemDisclosureActions.warning.fillColor
|
||||
textColor = item.theme.list.itemDisclosureActions.warning.foregroundColor
|
||||
case .destructive:
|
||||
color = item.theme.list.itemDisclosureActions.destructive.fillColor
|
||||
textColor = item.theme.list.itemDisclosureActions.destructive.foregroundColor
|
||||
}
|
||||
mappedOptions.append(ItemListRevealOption(key: index, title: option.title, icon: .none, color: color, textColor: textColor))
|
||||
index += 1
|
||||
}
|
||||
peerRevealOptions = mappedOptions
|
||||
} else {
|
||||
peerRevealOptions = []
|
||||
}
|
||||
|
||||
return (nodeLayout, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
return (.complete(), { [weak strongSelf] animated, synchronousLoads in
|
||||
@ -710,12 +738,12 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
strongSelf.updateLayout(size: nodeLayout.contentSize, leftInset: params.leftInset, rightInset: params.rightInset)
|
||||
|
||||
|
||||
if item.editing.editable {
|
||||
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.strings.Common_Delete, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
|
||||
strongSelf.setRevealOptionsOpened(item.editing.revealed, animated: animated)
|
||||
strongSelf.setRevealOptions((left: [], right: [ItemListRevealOption(key: 0, title: item.strings.Common_Delete, icon: .none, color: item.theme.list.itemDisclosureActions.destructive.fillColor, textColor: item.theme.list.itemDisclosureActions.destructive.foregroundColor)]))
|
||||
strongSelf.setRevealOptionsOpened(item.editing.revealed, animated: animated)
|
||||
} else {
|
||||
strongSelf.setRevealOptions((left: [], right: []))
|
||||
strongSelf.setRevealOptions((left: [], right: peerRevealOptions))
|
||||
strongSelf.setRevealOptionsOpened(item.editing.revealed, animated: animated)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -800,13 +828,17 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
override func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
|
||||
if let item = self.item {
|
||||
switch item.peer {
|
||||
case let .peer(peer, chatPeer):
|
||||
if let peer = chatPeer ?? peer {
|
||||
item.deletePeer?(peer.id)
|
||||
}
|
||||
case .deviceContact:
|
||||
break
|
||||
if item.editing.editable {
|
||||
switch item.peer {
|
||||
case let .peer(peer, chatPeer):
|
||||
if let peer = chatPeer ?? peer {
|
||||
item.deletePeer?(peer.id)
|
||||
}
|
||||
case .deviceContact:
|
||||
break
|
||||
}
|
||||
} else {
|
||||
item.options[Int(option.key)].action()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1780,6 +1780,8 @@ public func groupInfoController(account: Account, peerId: PeerId) -> ViewControl
|
||||
if let infoController = peerInfoController(account: account, peer: peer) {
|
||||
arguments.pushController(infoController)
|
||||
}
|
||||
}, present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -10,15 +10,19 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
||||
let peerId: PeerId
|
||||
let cancel: () -> Void
|
||||
let openPeer: (Peer, RenderedChannelParticipant?) -> Void
|
||||
let present: (ViewController, Any?) -> Void
|
||||
let searchMode: ChannelMembersSearchMode
|
||||
|
||||
private var updateActivity: ((Bool) -> Void)?
|
||||
private var activity: ValuePromise<Bool> = ValuePromise(ignoreRepeated: false)
|
||||
private let activityDisposable = MetaDisposable()
|
||||
init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void) {
|
||||
|
||||
init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
self.cancel = cancel
|
||||
self.openPeer = openPeer
|
||||
self.present = present
|
||||
self.searchMode = searchMode
|
||||
activityDisposable.set((activity.get() |> mapToSignal { value -> Signal<Bool, NoError> in
|
||||
if value {
|
||||
@ -32,7 +36,7 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
||||
}
|
||||
|
||||
deinit {
|
||||
activityDisposable.dispose()
|
||||
self.activityDisposable.dispose()
|
||||
}
|
||||
|
||||
func isEqual(to: ItemListControllerSearch) -> Bool {
|
||||
@ -63,6 +67,8 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
||||
func node(current: ItemListControllerSearchNode?) -> ItemListControllerSearchNode {
|
||||
return ChannelMembersSearchItemNode(account: self.account, peerId: self.peerId, searchMode: self.searchMode, openPeer: self.openPeer, cancel: self.cancel, updateActivity: { [weak self] value in
|
||||
self?.activity.set(value)
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, a)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -70,10 +76,10 @@ final class ChannelMembersSearchItem: ItemListControllerSearch {
|
||||
private final class ChannelMembersSearchItemNode: ItemListControllerSearchNode {
|
||||
private let containerNode: ChannelMembersSearchContainerNode
|
||||
|
||||
init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool)->Void) {
|
||||
init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, present: @escaping (ViewController, Any?) -> Void) {
|
||||
self.containerNode = ChannelMembersSearchContainerNode(account: account, peerId: peerId, mode: searchMode, filters: [], openPeer: { peer, participant in
|
||||
openPeer(peer, participant)
|
||||
}, updateActivity: updateActivity)
|
||||
}, updateActivity: updateActivity, present: present)
|
||||
self.containerNode.cancel = {
|
||||
cancel()
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user