no message

This commit is contained in:
overtake
2018-09-06 00:43:45 +01:00
parent a56b570d0f
commit 7e6cff6a16
10 changed files with 245 additions and 73 deletions

View File

@@ -275,7 +275,8 @@ private struct ChannelAdminsControllerState: Equatable {
let removingPeerId: PeerId? let removingPeerId: PeerId?
let removedPeerIds: Set<PeerId> let removedPeerIds: Set<PeerId>
let temporaryAdmins: [RenderedChannelParticipant] let temporaryAdmins: [RenderedChannelParticipant]
let searchingMembers: Bool
init() { init() {
self.selectedType = nil self.selectedType = nil
self.editing = false self.editing = false
@@ -283,15 +284,17 @@ private struct ChannelAdminsControllerState: Equatable {
self.removingPeerId = nil self.removingPeerId = nil
self.removedPeerIds = Set() self.removedPeerIds = Set()
self.temporaryAdmins = [] self.temporaryAdmins = []
self.searchingMembers = false
} }
init(selectedType: CurrentAdministrationType?, editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?, removedPeerIds: Set<PeerId>, temporaryAdmins: [RenderedChannelParticipant]) { init(selectedType: CurrentAdministrationType?, editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?, removedPeerIds: Set<PeerId>, temporaryAdmins: [RenderedChannelParticipant], searchingMembers: Bool) {
self.selectedType = selectedType self.selectedType = selectedType
self.editing = editing self.editing = editing
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
self.removingPeerId = removingPeerId self.removingPeerId = removingPeerId
self.removedPeerIds = removedPeerIds self.removedPeerIds = removedPeerIds
self.temporaryAdmins = temporaryAdmins self.temporaryAdmins = temporaryAdmins
self.searchingMembers = searchingMembers
} }
static func ==(lhs: ChannelAdminsControllerState, rhs: ChannelAdminsControllerState) -> Bool { static func ==(lhs: ChannelAdminsControllerState, rhs: ChannelAdminsControllerState) -> Bool {
@@ -313,32 +316,39 @@ private struct ChannelAdminsControllerState: Equatable {
if lhs.temporaryAdmins != rhs.temporaryAdmins { if lhs.temporaryAdmins != rhs.temporaryAdmins {
return false return false
} }
if lhs.searchingMembers != rhs.searchingMembers {
return false
}
return true return true
} }
func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: searchingMembers)
}
func withUpdatedSelectedType(_ selectedType: CurrentAdministrationType?) -> ChannelAdminsControllerState { func withUpdatedSelectedType(_ selectedType: CurrentAdministrationType?) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins) return ChannelAdminsControllerState(selectedType: selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: self.searchingMembers)
} }
func withUpdatedEditing(_ editing: Bool) -> ChannelAdminsControllerState { func withUpdatedEditing(_ editing: Bool) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins) return ChannelAdminsControllerState(selectedType: self.selectedType, editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: self.searchingMembers)
} }
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelAdminsControllerState { func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins) return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: self.searchingMembers)
} }
func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelAdminsControllerState { func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins) return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: self.searchingMembers)
} }
func withUpdatedRemovedPeerIds(_ removedPeerIds: Set<PeerId>) -> ChannelAdminsControllerState { func withUpdatedRemovedPeerIds(_ removedPeerIds: Set<PeerId>) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: removedPeerIds, temporaryAdmins: self.temporaryAdmins) return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: removedPeerIds, temporaryAdmins: self.temporaryAdmins, searchingMembers: self.searchingMembers)
} }
func withUpdatedTemporaryAdmins(_ temporaryAdmins: [RenderedChannelParticipant]) -> ChannelAdminsControllerState { func withUpdatedTemporaryAdmins(_ temporaryAdmins: [RenderedChannelParticipant]) -> ChannelAdminsControllerState {
return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: temporaryAdmins) return ChannelAdminsControllerState(selectedType: self.selectedType, editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, removedPeerIds: self.removedPeerIds, temporaryAdmins: temporaryAdmins, searchingMembers: self.searchingMembers)
} }
} }
@@ -593,6 +603,7 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, view, admins -> (ItemListControllerState, (ItemListNodeState<ChannelAdminsEntry>, ChannelAdminsEntry.ItemGenerationArguments)) in |> map { presentationData, state, view, admins -> (ItemListControllerState, (ItemListNodeState<ChannelAdminsEntry>, ChannelAdminsEntry.ItemGenerationArguments)) in
var rightNavigationButton: ItemListNavigationButton? var rightNavigationButton: ItemListNavigationButton?
var secondaryRightNavigationButton: ItemListNavigationButton?
if let admins = admins, admins.count > 1 { if let admins = admins, admins.count > 1 {
if state.editing { if state.editing {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: { rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
@@ -606,6 +617,22 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon
return state.withUpdatedEditing(true) return state.withUpdatedEditing(true)
} }
}) })
}
if !state.editing {
if rightNavigationButton == nil {
rightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
updateState { state in
return state.withUpdatedSearchingMembers(true)
}
})
} else {
secondaryRightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
updateState { state in
return state.withUpdatedSearchingMembers(true)
}
})
}
} }
} }
@@ -617,8 +644,22 @@ public func channelAdminsController(account: Account, peerId: PeerId) -> ViewCon
isGroup = false isGroup = false
} }
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(isGroup ? presentationData.strings.ChatAdmins_Title : presentationData.strings.Channel_Management_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) var searchItem: ItemListControllerSearch?
let listState = ItemListNodeState(entries: channelAdminsControllerEntries(presentationData: presentationData, accountPeerId: account.peerId, view: view, state: state, participants: admins), style: .blocks, animateChanges: previous != nil && admins != nil && previous!.count >= admins!.count) if state.searchingMembers {
searchItem = ChannelMembersSearchItem(account: account, peerId: peerId, searchMode: .searchAdmins, cancel: {
updateState { state in
return state.withUpdatedSearchingMembers(false)
}
}, openPeer: { _, participant in
if let participant = participant?.participant, case .member = participant {
presentControllerImpl?(channelAdminController(account: account, peerId: peerId, adminId: participant.peerId, initialParticipant: participant, updated: { _ in
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
})
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(isGroup ? presentationData.strings.ChatAdmins_Title : presentationData.strings.Channel_Management_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, secondaryRightNavigationButton: secondaryRightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: channelAdminsControllerEntries(presentationData: presentationData, accountPeerId: account.peerId, view: view, state: state, participants: admins), style: .blocks, searchItem: searchItem, animateChanges: previous != nil && admins != nil && previous!.count >= admins!.count)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@@ -210,17 +210,20 @@ private struct ChannelBlacklistControllerState: Equatable {
let editing: Bool let editing: Bool
let peerIdWithRevealedOptions: PeerId? let peerIdWithRevealedOptions: PeerId?
let removingPeerId: PeerId? let removingPeerId: PeerId?
let searchingMembers: Bool
init() { init() {
self.editing = false self.editing = false
self.peerIdWithRevealedOptions = nil self.peerIdWithRevealedOptions = nil
self.removingPeerId = nil self.removingPeerId = nil
self.searchingMembers = false
} }
init(editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?) { init(editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?, searchingMembers: Bool) {
self.editing = editing self.editing = editing
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
self.removingPeerId = removingPeerId self.removingPeerId = removingPeerId
self.searchingMembers = searchingMembers
} }
static func ==(lhs: ChannelBlacklistControllerState, rhs: ChannelBlacklistControllerState) -> Bool { static func ==(lhs: ChannelBlacklistControllerState, rhs: ChannelBlacklistControllerState) -> Bool {
@@ -233,20 +236,28 @@ private struct ChannelBlacklistControllerState: Equatable {
if lhs.removingPeerId != rhs.removingPeerId { if lhs.removingPeerId != rhs.removingPeerId {
return false return false
} }
if lhs.searchingMembers != rhs.searchingMembers {
return false
}
return true return true
} }
func withUpdatedEditing(_ editing: Bool) -> ChannelBlacklistControllerState { func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> ChannelBlacklistControllerState {
return ChannelBlacklistControllerState(editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId) return ChannelBlacklistControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: searchingMembers)
} }
func withUpdatedEditing(_ editing: Bool) -> ChannelBlacklistControllerState {
return ChannelBlacklistControllerState(editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: self.searchingMembers)
}
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelBlacklistControllerState { func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelBlacklistControllerState {
return ChannelBlacklistControllerState(editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId) return ChannelBlacklistControllerState(editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: self.searchingMembers)
} }
func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelBlacklistControllerState { func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelBlacklistControllerState {
return ChannelBlacklistControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId) return ChannelBlacklistControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId, searchingMembers: self.searchingMembers)
} }
} }
@@ -406,6 +417,7 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, state, view, blacklist -> (ItemListControllerState, (ItemListNodeState<ChannelBlacklistEntry>, ChannelBlacklistEntry.ItemGenerationArguments)) in |> map { presentationData, state, view, blacklist -> (ItemListControllerState, (ItemListNodeState<ChannelBlacklistEntry>, ChannelBlacklistEntry.ItemGenerationArguments)) in
var rightNavigationButton: ItemListNavigationButton? var rightNavigationButton: ItemListNavigationButton?
var secondaryRightNavigationButton: ItemListNavigationButton?
if let blacklist = blacklist, !blacklist.isEmpty { if let blacklist = blacklist, !blacklist.isEmpty {
if state.editing { if state.editing {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: { rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
@@ -414,12 +426,28 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View
} }
}) })
} else { } else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: {
updateState { state in updateState { state in
return state.withUpdatedEditing(true) return state.withUpdatedEditing(true)
} }
}) })
} }
if !state.editing {
if rightNavigationButton == nil {
rightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
updateState { state in
return state.withUpdatedSearchingMembers(true)
}
})
} else {
secondaryRightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
updateState { state in
return state.withUpdatedSearchingMembers(true)
}
})
}
}
} }
var emptyStateItem: ItemListControllerEmptyStateItem? var emptyStateItem: ItemListControllerEmptyStateItem?
@@ -430,8 +458,22 @@ public func channelBlacklistController(account: Account, peerId: PeerId) -> View
let previous = previousBlacklist let previous = previousBlacklist
previousBlacklist = blacklist previousBlacklist = blacklist
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_BlackList_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) var searchItem: ItemListControllerSearch?
let listState = ItemListNodeState(entries: channelBlacklistControllerEntries(presentationData: presentationData, view: view, state: state, blacklist: blacklist), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: previous != nil && blacklist != nil && (previous!.restricted.count + previous!.banned.count) >= (blacklist!.restricted.count + blacklist!.banned.count)) if state.searchingMembers {
searchItem = ChannelMembersSearchItem(account: account, peerId: peerId, searchMode: .searchBanned, cancel: {
updateState { state in
return state.withUpdatedSearchingMembers(false)
}
}, openPeer: { _, participant in
if let participant = participant?.participant, case .member = participant {
presentControllerImpl?(channelBannedMemberController(account: account, peerId: peerId, memberId: participant.peerId, initialParticipant: participant, updated: { _ in
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
})
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_BlackList_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, secondaryRightNavigationButton: secondaryRightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: channelBlacklistControllerEntries(presentationData: presentationData, view: view, state: state, blacklist: blacklist), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, animateChanges: previous != nil && blacklist != nil && (previous!.restricted.count + previous!.banned.count) >= (blacklist!.restricted.count + blacklist!.banned.count))
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@@ -105,11 +105,11 @@ private enum ChannelInfoEntry: ItemListNodeEntry {
switch self { switch self {
case .info: case .info:
return 0 return 0
case .addressName:
return 1
case .about:
return 2
case .channelPhotoSetup: case .channelPhotoSetup:
return 1
case .addressName:
return 2
case .about:
return 3 return 3
case .channelTypeSetup: case .channelTypeSetup:
return 4 return 4
@@ -454,7 +454,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation
entries.append(.channelTypeSetup(theme: presentationData.theme, text: presentationData.strings.Channel_Edit_LinkItem, value: linkText)) entries.append(.channelTypeSetup(theme: presentationData.theme, text: presentationData.strings.Channel_Edit_LinkItem, value: linkText))
} else if let username = peer.username, !username.isEmpty { } else if let username = peer.username, !username.isEmpty, state.editingState == nil {
entries.append(.addressName(theme: presentationData.theme, text: presentationData.strings.Channel_LinkItem, value: username)) entries.append(.addressName(theme: presentationData.theme, text: presentationData.strings.Channel_LinkItem, value: username))
} }

View File

@@ -49,9 +49,9 @@ struct ChannelMemberListState {
enum ChannelMemberListCategory { enum ChannelMemberListCategory {
case recent case recent
case recentSearch(String) case recentSearch(String)
case admins case admins(String?)
case restricted case restricted(String?)
case banned case banned(String?)
} }
private protocol ChannelMemberCategoryListContext { private protocol ChannelMemberCategoryListContext {
@@ -153,19 +153,31 @@ private final class ChannelMemberSingleCategoryListContext: ChannelMemberCategor
private func loadSignal(offset: Int32, count: Int32, hash: Int32) -> Signal<[RenderedChannelParticipant]?, NoError> { private func loadSignal(offset: Int32, count: Int32, hash: Int32) -> Signal<[RenderedChannelParticipant]?, NoError> {
let requestCategory: ChannelMembersCategory let requestCategory: ChannelMembersCategory
var adminQuery: String? = nil
switch self.category { switch self.category {
case .recent: case .recent:
requestCategory = .recent(.all) requestCategory = .recent(.all)
case let .recentSearch(query): case let .recentSearch(query):
requestCategory = .recent(.search(query)) requestCategory = .recent(.search(query))
case .admins: case let .admins(query):
requestCategory = .admins requestCategory = .admins
case .restricted: adminQuery = query
requestCategory = .restricted(.all) case let .restricted(query):
case .banned: requestCategory = .restricted(query != nil ? .search(query!) : .all)
requestCategory = .banned(.all) case let .banned(query):
requestCategory = .banned(query != nil ? .search(query!) : .all)
}
return channelMembers(postbox: self.postbox, network: self.network, peerId: self.peerId, category: requestCategory, offset: offset, limit: count, hash: hash) |> map { members in
switch requestCategory {
case .admins:
if let query = adminQuery {
return members?.filter({$0.peer.displayTitle.lowercased().components(separatedBy: " ").contains(where: {$0.hasPrefix(query.lowercased())})})
}
default:
break
}
return members
} }
return channelMembers(postbox: self.postbox, network: self.network, peerId: self.peerId, category: requestCategory, offset: offset, limit: count, hash: hash)
} }
private func loadMoreSignal(count: Int32) -> Signal<[RenderedChannelParticipant], NoError> { private func loadMoreSignal(count: Int32) -> Signal<[RenderedChannelParticipant], NoError> {
@@ -561,14 +573,14 @@ final class PeerChannelMemberCategoriesContext {
mappedCategory = .recent mappedCategory = .recent
case let .recentSearch(query): case let .recentSearch(query):
mappedCategory = .recentSearch(query) mappedCategory = .recentSearch(query)
case .admins: case let .admins(query):
mappedCategory = .admins mappedCategory = .admins(query)
default: default:
mappedCategory = .recent mappedCategory = .recent
} }
context = ChannelMemberSingleCategoryListContext(postbox: self.postbox, network: self.network, peerId: self.peerId, category: mappedCategory) context = ChannelMemberSingleCategoryListContext(postbox: self.postbox, network: self.network, peerId: self.peerId, category: mappedCategory)
case .restrictedAndBanned: case let .restrictedAndBanned(query):
context = ChannelMemberMultiCategoryListContext(postbox: self.postbox, network: self.network, peerId: self.peerId, categories: [.restricted, .banned]) context = ChannelMemberMultiCategoryListContext(postbox: self.postbox, network: self.network, peerId: self.peerId, categories: [.restricted(query), .banned(query)])
} }
let contextWithSubscribers = PeerChannelMemberContextWithSubscribers(context: context, becameEmpty: { [weak self] in let contextWithSubscribers = PeerChannelMemberContextWithSubscribers(context: context, becameEmpty: { [weak self] in
assert(Queue.mainQueue().isCurrent()) assert(Queue.mainQueue().isCurrent())

View File

@@ -190,17 +190,20 @@ private struct ChannelMembersControllerState: Equatable {
let editing: Bool let editing: Bool
let peerIdWithRevealedOptions: PeerId? let peerIdWithRevealedOptions: PeerId?
let removingPeerId: PeerId? let removingPeerId: PeerId?
let searchingMembers: Bool
init() { init() {
self.editing = false self.editing = false
self.peerIdWithRevealedOptions = nil self.peerIdWithRevealedOptions = nil
self.removingPeerId = nil self.removingPeerId = nil
self.searchingMembers = false
} }
init(editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?) { init(editing: Bool, peerIdWithRevealedOptions: PeerId?, removingPeerId: PeerId?, searchingMembers: Bool) {
self.editing = editing self.editing = editing
self.peerIdWithRevealedOptions = peerIdWithRevealedOptions self.peerIdWithRevealedOptions = peerIdWithRevealedOptions
self.removingPeerId = removingPeerId self.removingPeerId = removingPeerId
self.searchingMembers = searchingMembers
} }
static func ==(lhs: ChannelMembersControllerState, rhs: ChannelMembersControllerState) -> Bool { static func ==(lhs: ChannelMembersControllerState, rhs: ChannelMembersControllerState) -> Bool {
@@ -213,20 +216,26 @@ private struct ChannelMembersControllerState: Equatable {
if lhs.removingPeerId != rhs.removingPeerId { if lhs.removingPeerId != rhs.removingPeerId {
return false return false
} }
if lhs.searchingMembers != rhs.searchingMembers {
return false
}
return true return true
} }
func withUpdatedSearchingMembers(_ searchingMembers: Bool) -> ChannelMembersControllerState {
return ChannelMembersControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: searchingMembers)
}
func withUpdatedEditing(_ editing: Bool) -> ChannelMembersControllerState { func withUpdatedEditing(_ editing: Bool) -> ChannelMembersControllerState {
return ChannelMembersControllerState(editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId) return ChannelMembersControllerState(editing: editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: self.searchingMembers)
} }
func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelMembersControllerState { func withUpdatedPeerIdWithRevealedOptions(_ peerIdWithRevealedOptions: PeerId?) -> ChannelMembersControllerState {
return ChannelMembersControllerState(editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId) return ChannelMembersControllerState(editing: self.editing, peerIdWithRevealedOptions: peerIdWithRevealedOptions, removingPeerId: self.removingPeerId, searchingMembers: self.searchingMembers)
} }
func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelMembersControllerState { func withUpdatedRemovingPeerId(_ removingPeerId: PeerId?) -> ChannelMembersControllerState {
return ChannelMembersControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId) return ChannelMembersControllerState(editing: self.editing, peerIdWithRevealedOptions: self.peerIdWithRevealedOptions, removingPeerId: removingPeerId, searchingMembers: self.searchingMembers)
} }
} }
@@ -472,14 +481,31 @@ public func channelMembersController(account: Account, peerId: PeerId) -> ViewCo
return state.withUpdatedEditing(true) return state.withUpdatedEditing(true)
} }
}) })
secondaryRightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: { if let cachedData = view.cachedData as? CachedChannelData, cachedData.participantsSummary.memberCount ?? 0 >= 200 {
// updateState { state in secondaryRightNavigationButton = ItemListNavigationButton(content: .icon(.search), style: .regular, enabled: true, action: {
// return state.withUpdatedSearchingMembers(true) updateState { state in
// } return state.withUpdatedSearchingMembers(true)
}) }
})
}
} }
} }
var searchItem: ItemListControllerSearch?
if state.searchingMembers {
searchItem = ChannelMembersSearchItem(account: account, peerId: peerId, cancel: {
updateState { state in
return state.withUpdatedSearchingMembers(false)
}
}, openPeer: { peer, _ in
if let infoController = peerInfoController(account: account, peer: peer) {
pushControllerImpl?(infoController)
// arguments.pushController(infoController)
}
})
}
var emptyStateItem: ItemListControllerEmptyStateItem? var emptyStateItem: ItemListControllerEmptyStateItem?
if peers == nil { if peers == nil {
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme) emptyStateItem = ItemListLoadingIndicatorEmptyStateItem(theme: presentationData.theme)
@@ -488,8 +514,8 @@ public func channelMembersController(account: Account, peerId: PeerId) -> ViewCo
let previous = previousPeers let previous = previousPeers
previousPeers = peers previousPeers = peers
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_Subscribers_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Channel_Subscribers_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, secondaryRightNavigationButton: secondaryRightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(entries: ChannelMembersControllerEntries(account: account, presentationData: presentationData, view: view, state: state, participants: peers), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: previous != nil && peers != nil && previous!.count >= peers!.count) let listState = ItemListNodeState(entries: ChannelMembersControllerEntries(account: account, presentationData: presentationData, view: view, state: state, participants: peers), style: .blocks, emptyStateItem: emptyStateItem, searchItem: searchItem, animateChanges: previous != nil && peers != nil && previous!.count >= peers!.count)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@@ -7,6 +7,8 @@ import TelegramCore
enum ChannelMembersSearchMode { enum ChannelMembersSearchMode {
case searchMembers case searchMembers
case searchAdmins
case searchBanned
case banAndPromoteActions case banAndPromoteActions
case inviteActions case inviteActions
} }
@@ -184,6 +186,28 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
foundGroupMembers = .single([]) foundGroupMembers = .single([])
foundMembers = channelMembers(postbox: account.postbox, network: account.network, peerId: peerId, category: .recent(.search(query))) foundMembers = channelMembers(postbox: account.postbox, network: account.network, peerId: peerId, category: .recent(.search(query)))
|> map { $0 ?? [] } |> map { $0 ?? [] }
case .searchAdmins:
foundGroupMembers = Signal { subscriber in
let (disposable, listControl) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.admins(postbox: account.postbox, network: account.network, 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, listControl) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.restrictedAndBanned(postbox: account.postbox, network: account.network, 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], NoError> let foundContacts: Signal<[Peer], NoError>
@@ -193,7 +217,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
foundContacts = account.postbox.searchContacts(query: query.lowercased()) foundContacts = account.postbox.searchContacts(query: query.lowercased())
foundRemotePeers = .single(([], [])) |> then(searchPeers(account: account, query: query) foundRemotePeers = .single(([], [])) |> then(searchPeers(account: account, query: query)
|> delay(0.2, queue: Queue.concurrentDefaultQueue())) |> delay(0.2, queue: Queue.concurrentDefaultQueue()))
case .searchMembers: case .searchMembers, .searchBanned, .searchAdmins:
foundContacts = .single([]) foundContacts = .single([])
foundRemotePeers = .single(([], [])) foundRemotePeers = .single(([], []))
} }
@@ -206,7 +230,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
switch mode { switch mode {
case .inviteActions, .banAndPromoteActions: case .inviteActions, .banAndPromoteActions:
existingPeerIds.insert(account.peerId) existingPeerIds.insert(account.peerId)
case .searchMembers: case .searchMembers, .searchAdmins, .searchBanned:
break break
} }
@@ -219,7 +243,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
switch mode { switch mode {
case .inviteActions, .banAndPromoteActions: case .inviteActions, .banAndPromoteActions:
section = .members section = .members
case .searchMembers: case .searchMembers, .searchBanned, .searchAdmins:
section = .none section = .none
} }
@@ -231,6 +255,30 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
enabled = false 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, label, enabled), section: section)) entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant, label, enabled), section: section))
index += 1 index += 1
} }
@@ -243,7 +291,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
switch mode { switch mode {
case .inviteActions, .banAndPromoteActions: case .inviteActions, .banAndPromoteActions:
section = .members section = .members
case .searchMembers: case .searchMembers, .searchBanned, .searchAdmins:
section = .none section = .none
} }
@@ -255,6 +303,8 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
enabled = false enabled = false
} }
} }
entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant, label, enabled), section: section)) entries.append(ChannelMembersSearchEntry(index: index, content: .participant(participant, label, enabled), section: section))
index += 1 index += 1
} }

View File

@@ -115,7 +115,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.panelButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside) self.panelButtonNode.addTarget(self, action: #selector(self.infoButtonPressed), forControlEvents: .touchUpInside)
let (adminsDisposable, _) = self.account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.admins(postbox: self.account.postbox, network: self.account.network, peerId: self.peer.id, updated: { [weak self] state in let (adminsDisposable, _) = self.account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.admins(postbox: self.account.postbox, network: self.account.network, peerId: self.peer.id, searchQuery: nil, updated: { [weak self] state in
self?.adminsState = state self?.adminsState = state
}) })
self.adminsDisposable = adminsDisposable self.adminsDisposable = adminsDisposable

View File

@@ -1639,11 +1639,11 @@ public func groupInfoController(account: Account, peerId: PeerId) -> ViewControl
var searchItem: ItemListControllerSearch? var searchItem: ItemListControllerSearch?
if state.searchingMembers { if state.searchingMembers {
searchItem = GroupInfoSearchItem(account: account, peerId: peerId, cancel: { searchItem = ChannelMembersSearchItem(account: account, peerId: peerId, cancel: {
updateState { state in updateState { state in
return state.withUpdatedSearchingMembers(false) return state.withUpdatedSearchingMembers(false)
} }
}, openPeer: { peer in }, openPeer: { peer, _ in
if let infoController = peerInfoController(account: account, peer: peer) { if let infoController = peerInfoController(account: account, peer: peer) {
arguments.pushController(infoController) arguments.pushController(infoController)
} }

View File

@@ -5,21 +5,22 @@ import Postbox
import TelegramCore import TelegramCore
import SwiftSignalKit import SwiftSignalKit
final class GroupInfoSearchItem: ItemListControllerSearch { final class ChannelMembersSearchItem: ItemListControllerSearch {
let account: Account let account: Account
let peerId: PeerId let peerId: PeerId
let cancel: () -> Void let cancel: () -> Void
let openPeer: (Peer) -> Void let openPeer: (Peer, RenderedChannelParticipant?) -> Void
let searchMode: ChannelMembersSearchMode
init(account: Account, peerId: PeerId, cancel: @escaping () -> Void, openPeer: @escaping (Peer) -> Void) { init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode = .searchMembers, cancel: @escaping () -> Void, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void) {
self.account = account self.account = account
self.peerId = peerId self.peerId = peerId
self.cancel = cancel self.cancel = cancel
self.openPeer = openPeer self.openPeer = openPeer
self.searchMode = searchMode
} }
func isEqual(to: ItemListControllerSearch) -> Bool { func isEqual(to: ItemListControllerSearch) -> Bool {
if let to = to as? GroupInfoSearchItem { if let to = to as? ChannelMembersSearchItem {
if self.account !== to.account { if self.account !== to.account {
return false return false
} }
@@ -42,16 +43,16 @@ final class GroupInfoSearchItem: ItemListControllerSearch {
} }
func node(current: ItemListControllerSearchNode?) -> ItemListControllerSearchNode { func node(current: ItemListControllerSearchNode?) -> ItemListControllerSearchNode {
return GroupInfoSearchItemNode(account: self.account, peerId: self.peerId, openPeer: self.openPeer, cancel: self.cancel) return ChannelMembersSearchItemNode(account: self.account, peerId: self.peerId, searchMode: self.searchMode, openPeer: self.openPeer, cancel: self.cancel)
} }
} }
private final class GroupInfoSearchItemNode: ItemListControllerSearchNode { private final class ChannelMembersSearchItemNode: ItemListControllerSearchNode {
private let containerNode: ChannelMembersSearchContainerNode private let containerNode: ChannelMembersSearchContainerNode
init(account: Account, peerId: PeerId, openPeer: @escaping (Peer) -> Void, cancel: @escaping () -> Void) { init(account: Account, peerId: PeerId, searchMode: ChannelMembersSearchMode, openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void, cancel: @escaping () -> Void) {
self.containerNode = ChannelMembersSearchContainerNode(account: account, peerId: peerId, mode: .searchMembers, openPeer: { peer, _ in self.containerNode = ChannelMembersSearchContainerNode(account: account, peerId: peerId, mode: searchMode, openPeer: { peer, participant in
openPeer(peer) openPeer(peer, participant)
}) })
self.containerNode.cancel = { self.containerNode.cancel = {
cancel() cancel()

View File

@@ -6,8 +6,8 @@ import SwiftSignalKit
enum PeerChannelMemberContextKey: Hashable { enum PeerChannelMemberContextKey: Hashable {
case recent case recent
case recentSearch(String) case recentSearch(String)
case admins case admins(String?)
case restrictedAndBanned case restrictedAndBanned(String?)
} }
private final class PeerChannelMemberCategoriesContextsManagerImpl { private final class PeerChannelMemberCategoriesContextsManagerImpl {
@@ -89,12 +89,12 @@ final class PeerChannelMemberCategoriesContextsManager {
return self.getContext(postbox: postbox, network: network, peerId: peerId, key: key, requestUpdate: requestUpdate, updated: updated) return self.getContext(postbox: postbox, network: network, peerId: peerId, key: key, requestUpdate: requestUpdate, updated: updated)
} }
func admins(postbox: Postbox, network: Network, peerId: PeerId, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl?) { func admins(postbox: Postbox, network: Network, peerId: PeerId, searchQuery: String? = nil, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl?) {
return self.getContext(postbox: postbox, network: network, peerId: peerId, key: .admins, requestUpdate: true, updated: updated) return self.getContext(postbox: postbox, network: network, peerId: peerId, key: .admins(searchQuery), requestUpdate: true, updated: updated)
} }
func restrictedAndBanned(postbox: Postbox, network: Network, peerId: PeerId, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl?) { func restrictedAndBanned(postbox: Postbox, network: Network, peerId: PeerId, searchQuery: String? = nil, updated: @escaping (ChannelMemberListState) -> Void) -> (Disposable, PeerChannelMemberCategoryControl?) {
return self.getContext(postbox: postbox, network: network, peerId: peerId, key: .restrictedAndBanned, requestUpdate: true, updated: updated) return self.getContext(postbox: postbox, network: network, peerId: peerId, key: .restrictedAndBanned(searchQuery), requestUpdate: true, updated: updated)
} }
func updateMemberBannedRights(account: Account, peerId: PeerId, memberId: PeerId, bannedRights: TelegramChannelBannedRights?) -> Signal<Void, NoError> { func updateMemberBannedRights(account: Account, peerId: PeerId, memberId: PeerId, bannedRights: TelegramChannelBannedRights?) -> Signal<Void, NoError> {