Various improvements

This commit is contained in:
Ilya Laktyushin 2026-02-25 13:00:12 +04:00
parent 7d65064f9b
commit c05a1dd17c
5 changed files with 373 additions and 83 deletions

View file

@ -1697,7 +1697,17 @@ public func channelAdminController(context: AccountContext, updatedPresentationD
})
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let rightNavigationButton: ItemListNavigationButton?
if state.focusedOnRank {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
rightButtonActionImpl()
})
footerItem = nil
} else {
rightNavigationButton = nil
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelAdminControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelPeer: channelPeer, adminPeer: adminPeer, adminPresence: adminPresence, initialParticipant: initialParticipant, invite: invite, canEdit: canEdit), style: .blocks, focusItemTag: nil, ensureVisibleItemTag: nil, emptyStateItem: nil, footerItem: footerItem, animateChanges: true)

View file

@ -15,6 +15,8 @@ import PresentationDataUtils
import ItemListAvatarAndNameInfoItem
import OldChannelsController
private let rankMaxLength: Int32 = 16
private final class ChannelBannedMemberControllerArguments {
let context: AccountContext
let toggleRight: (TelegramChatBannedRightsFlags, Bool) -> Void
@ -23,8 +25,12 @@ private final class ChannelBannedMemberControllerArguments {
let openTimeout: () -> Void
let delete: () -> Void
let openPeer: () -> Void
let updateRank: (String, String) -> Void
let updateFocusedOnRank: (Bool) -> Void
let dismissInput: () -> Void
let animateError: () -> Void
init(context: AccountContext, toggleRight: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, toggleRightWhileDisabled: @escaping (TelegramChatBannedRightsFlags) -> Void, toggleIsOptionExpanded: @escaping (TelegramChatBannedRightsFlags) -> Void, openTimeout: @escaping () -> Void, delete: @escaping () -> Void, openPeer: @escaping () -> Void) {
init(context: AccountContext, toggleRight: @escaping (TelegramChatBannedRightsFlags, Bool) -> Void, toggleRightWhileDisabled: @escaping (TelegramChatBannedRightsFlags) -> Void, toggleIsOptionExpanded: @escaping (TelegramChatBannedRightsFlags) -> Void, openTimeout: @escaping () -> Void, delete: @escaping () -> Void, openPeer: @escaping () -> Void, updateRank: @escaping (String, String) -> Void, updateFocusedOnRank: @escaping (Bool) -> Void, dismissInput: @escaping () -> Void, animateError: @escaping () -> Void) {
self.context = context
self.toggleRight = toggleRight
self.toggleRightWhileDisabled = toggleRightWhileDisabled
@ -32,6 +38,10 @@ private final class ChannelBannedMemberControllerArguments {
self.openTimeout = openTimeout
self.delete = delete
self.openPeer = openPeer
self.updateRank = updateRank
self.updateFocusedOnRank = updateFocusedOnRank
self.dismissInput = dismissInput
self.animateError = animateError
}
}
@ -40,6 +50,19 @@ private enum ChannelBannedMemberSection: Int32 {
case rights
case timeout
case delete
case rank
}
private enum ChannelBannedMemberEntryTag: ItemListItemTag {
case rank
func isEqual(to other: ItemListItemTag) -> Bool {
if let other = other as? ChannelBannedMemberEntryTag, self == other {
return true
} else {
return false
}
}
}
private enum ChannelBannedMemberEntryStableId: Hashable {
@ -49,6 +72,10 @@ private enum ChannelBannedMemberEntryStableId: Hashable {
case timeout
case exceptionInfo
case delete
case rankTitle
case rankPreview
case rank
case rankInfo
}
private enum ChannelBannedMemberEntry: ItemListNodeEntry {
@ -58,6 +85,10 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
case timeout(PresentationTheme, String, String)
case exceptionInfo(PresentationTheme, String)
case delete(PresentationTheme, String)
case rankTitle(PresentationTheme, String, Int32?, Int32)
case rankPreview(PresentationTheme, PresentationStrings, EnginePeer, String, Bool)
case rank(PresentationTheme, PresentationStrings, String, String, Bool)
case rankInfo(PresentationTheme, String, Bool)
var section: ItemListSectionId {
switch self {
@ -69,6 +100,8 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
return ChannelBannedMemberSection.timeout.rawValue
case .delete:
return ChannelBannedMemberSection.delete.rawValue
case .rankTitle, .rankPreview, .rank, .rankInfo:
return ChannelBannedMemberSection.rank.rawValue
}
}
@ -86,6 +119,14 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
return .exceptionInfo
case .delete:
return .delete
case .rankTitle:
return .rankTitle
case .rankPreview:
return .rankPreview
case .rank:
return .rank
case .rankInfo:
return .rankInfo
}
}
@ -167,50 +208,109 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
} else {
return false
}
case let .rankTitle(lhsTheme, lhsText, lhsCount, lhsLimit):
if case let .rankTitle(rhsTheme, rhsText, rhsCount, rhsLimit) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsCount == rhsCount, lhsLimit == rhsLimit {
return true
} else {
return false
}
case let .rankPreview(lhsTheme, lhsStrings, lhsPeer, lhsRank, lhsIsOwner):
if case let .rankPreview(rhsTheme, rhsStrings, rhsPeer, rhsRank, rhsIsOwner) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsPeer == rhsPeer, lhsRank == rhsRank, lhsIsOwner == rhsIsOwner {
return true
} else {
return false
}
case let .rank(lhsTheme, lhsStrings, lhsPlaceholder, lhsValue, lhsEnabled):
if case let .rank(rhsTheme, rhsStrings, rhsPlaceholder, rhsValue, rhsEnabled) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsPlaceholder == rhsPlaceholder, lhsValue == rhsValue, lhsEnabled == rhsEnabled {
return true
} else {
return false
}
case let .rankInfo(lhsTheme, lhsText, lhsTrimBottomInset):
if case let .rankInfo(rhsTheme, rhsText, rhsTrimBottomInset) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsTrimBottomInset == rhsTrimBottomInset {
return true
} else {
return false
}
}
}
static func <(lhs: ChannelBannedMemberEntry, rhs: ChannelBannedMemberEntry) -> Bool {
switch lhs {
case .info:
switch rhs {
case .info:
switch rhs {
case .info:
return false
default:
return true
}
case .rightsHeader:
switch rhs {
case .info, .rightsHeader:
return false
default:
return true
}
case let .rightItem(_, lhsIndex, _, _, _, _, _, _):
switch rhs {
case .info, .rightsHeader:
return false
case let .rightItem(_, rhsIndex, _, _, _, _, _, _):
return lhsIndex < rhsIndex
default:
return true
}
case .timeout:
switch rhs {
case .delete, .exceptionInfo:
return true
default:
return false
}
case .exceptionInfo:
switch rhs {
case .delete:
return true
default:
return false
}
case .delete:
return false
default:
return true
}
case .rightsHeader:
switch rhs {
case .info, .rightsHeader:
return false
default:
return true
}
case let .rightItem(_, lhsIndex, _, _, _, _, _, _):
switch rhs {
case .info, .rightsHeader:
return false
case let .rightItem(_, rhsIndex, _, _, _, _, _, _):
return lhsIndex < rhsIndex
default:
return true
}
case .timeout:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout:
return false
default:
return true
}
case .exceptionInfo:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .exceptionInfo:
return false
default:
return true
}
case .delete:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .exceptionInfo, .delete:
return false
default:
return true
}
case .rankTitle:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .delete, .rankTitle:
return false
default:
return true
}
case .rankPreview:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .delete, .rankTitle, .rankPreview:
return false
default:
return true
}
case .rank:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .delete, .rankTitle, .rankPreview, .rank:
return false
default:
return true
}
case .rankInfo:
switch rhs {
case .info, .rightsHeader, .rightItem, .timeout, .delete, .rankTitle, .rankPreview, .rank, .rankInfo:
return false
default:
return true
}
}
}
@ -269,6 +369,31 @@ private enum ChannelBannedMemberEntry: ItemListNodeEntry {
return ItemListActionItem(presentationData: presentationData, systemStyle: .glass, title: text, kind: .destructive, alignment: .center, sectionId: self.section, style: .blocks, action: {
arguments.delete()
})
case let .rankTitle(_, text, count, limit):
var accessoryText: ItemListSectionHeaderAccessoryText?
if let count = count {
accessoryText = ItemListSectionHeaderAccessoryText(value: "\(limit - count)", color: count > limit ? .destructive : .generic)
}
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: accessoryText, sectionId: self.section)
case let .rankPreview(_, _, peer, rank, _):
let globalPresentationData = arguments.context.sharedContext.currentPresentationData.with { $0 }
return arguments.context.sharedContext.makeChatRankPreviewItem(context: arguments.context, peer: peer, rank: rank, rankRole: .member, theme: presentationData.theme, strings: presentationData.strings, wallpaper: globalPresentationData.chatWallpaper, fontSize: globalPresentationData.chatFontSize, chatBubbleCorners: globalPresentationData.chatBubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, sectionId: self.section)
case let .rank(_, _, placeholder, text, enabled):
return ItemListSingleLineInputItem(presentationData: presentationData, systemStyle: .glass, title: NSAttributedString(string: "", textColor: .black), text: text, placeholder: placeholder, type: .regular(capitalization: false, autocorrection: true), spacing: 0.0, clearType: enabled ? .always : .none, enabled: enabled, tag: ChannelBannedMemberEntryTag.rank, sectionId: self.section, textUpdated: { updatedText in
arguments.updateRank(text, updatedText)
}, shouldUpdateText: { text in
if text.containsEmoji {
arguments.animateError()
return false
}
return true
}, updatedFocus: { focus in
arguments.updateFocusedOnRank(focus)
}, action: {
arguments.dismissInput()
})
case let .rankInfo(_, text, trimBottomInset):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section, additionalOuterInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: trimBottomInset ? -44.0 : 0.0, right: 0.0))
}
}
}
@ -279,6 +404,8 @@ private struct ChannelBannedMemberControllerState: Equatable {
var updatedTimeout: Int32?
var updating: Bool = false
var expandedPermissions = Set<TelegramChatBannedRightsFlags>()
var updatedRank: String?
var focusedOnRank: Bool
}
func completeRights(_ flags: TelegramChatBannedRightsFlags) -> TelegramChatBannedRightsFlags {
@ -353,7 +480,22 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
index += 1
}
if !editMember {
if editMember {
let currentRank: String?
if let updatedRank = state.updatedRank {
currentRank = updatedRank
} else if let initialParticipant = initialParticipant {
currentRank = initialParticipant.rank
} else {
currentRank = nil
}
let rankEnabled = !state.updating
entries.append(.rankTitle(presentationData.theme, presentationData.strings.Group_EditAdmin_MemberTagTitle.uppercased(), rankEnabled && state.focusedOnRank ? Int32(currentRank?.count ?? 0) : nil, rankMaxLength))
entries.append(.rankPreview(presentationData.theme, presentationData.strings, member, currentRank ?? "0", false))
entries.append(.rank(presentationData.theme, presentationData.strings, presentationData.strings.EditRank_Placeholder, currentRank ?? "", rankEnabled))
entries.append(.rankInfo(presentationData.theme, presentationData.strings.Group_EditAdmin_MemberTagInfo(member.compactDisplayTitle).string, false))
} else {
entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString))
if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _, _) = initialParticipant, let initialBannedBy = initialBannedBy {
@ -415,7 +557,23 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
index += 1
}
if !editMember {
if editMember {
let currentRank: String?
if let updatedRank = state.updatedRank {
currentRank = updatedRank
} else if let initialParticipant = initialParticipant {
currentRank = initialParticipant.rank
} else {
currentRank = nil
}
let rankEnabled = !state.updating
entries.append(.rankTitle(presentationData.theme, presentationData.strings.Group_EditAdmin_MemberTagTitle.uppercased(), rankEnabled && state.focusedOnRank ? Int32(currentRank?.count ?? 0) : nil, rankMaxLength))
entries.append(.rankPreview(presentationData.theme, presentationData.strings, member, currentRank ?? "0", false))
entries.append(.rank(presentationData.theme, presentationData.strings, presentationData.strings.EditRank_Placeholder, currentRank ?? "", rankEnabled))
entries.append(.rankInfo(presentationData.theme, presentationData.strings.Group_EditAdmin_MemberTagInfo(member.compactDisplayTitle).string, false))
} else {
entries.append(.timeout(presentationData.theme, presentationData.strings.GroupPermission_Duration, currentTimeoutString))
if let initialParticipant = initialParticipant, case let .member(_, _, _, banInfo?, _, _) = initialParticipant, let initialBannedBy = initialBannedBy {
@ -429,7 +587,7 @@ private func channelBannedMemberControllerEntries(presentationData: Presentation
}
public func channelBannedMemberController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: PeerId, memberId: PeerId, editMember: Bool = false, initialParticipant: ChannelParticipant?, updated: @escaping (TelegramChatBannedRights?) -> Void, upgradedToSupergroup: @escaping (PeerId, @escaping () -> Void) -> Void) -> ViewController {
let initialState = ChannelBannedMemberControllerState(referenceTimestamp: Int32(Date().timeIntervalSince1970), updatedFlags: nil, updatedTimeout: nil, updating: false)
let initialState = ChannelBannedMemberControllerState(referenceTimestamp: Int32(Date().timeIntervalSince1970), updatedFlags: nil, updatedTimeout: nil, updating: false, updatedRank: nil, focusedOnRank: false)
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((ChannelBannedMemberControllerState) -> ChannelBannedMemberControllerState) -> Void = { f in
@ -441,9 +599,15 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
let updateRightsDisposable = MetaDisposable()
actionsDisposable.add(updateRightsDisposable)
let updateRankDisposable = MetaDisposable()
actionsDisposable.add(updateRankDisposable)
var dismissImpl: (() -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushControllerImpl: ((ViewController) -> Void)?
var dismissInputImpl: (() -> Void)?
var errorImpl: (() -> Void)?
var scrollToRankImpl: (() -> Void)?
let peerView = Promise<PeerView>()
peerView.set(context.account.viewTracker.peerView(peerId))
@ -475,8 +639,7 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
} else {
effectiveRightsFlags = defaultBannedRightsFlags
}
if rights == .banSendMedia {
if value {
effectiveRightsFlags.remove(rights)
@ -623,6 +786,28 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
pushControllerImpl?(controller)
}
})
}, updateRank: { previousRank, updatedRank in
if updatedRank != previousRank {
updateState { state in
var state = state
state.updatedRank = updatedRank
return state
}
}
}, updateFocusedOnRank: { focusedOnRank in
updateState { state in
var state = state
state.focusedOnRank = focusedOnRank
return state
}
if focusedOnRank {
scrollToRankImpl?()
}
}, dismissInput: {
dismissInputImpl?()
}, animateError: {
errorImpl?()
})
var peerDataItems: [TelegramEngine.EngineData.Item.Peer.Peer] = []
@ -670,6 +855,16 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
return
}
var updateRank: String?
updateState { current in
updateRank = current.updatedRank?.trimmingCharacters(in: .whitespacesAndNewlines)
return current
}
if let updateRank = updateRank, updateRank.count > rankMaxLength || updateRank.containsEmoji {
errorImpl?()
return
}
var resolvedRights: TelegramChatBannedRights?
if let initialParticipant = initialParticipant {
var updateFlags: TelegramChatBannedRightsFlags?
@ -738,12 +933,27 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
previousRights = banInfo?.rights
}
let updateRankSignal: (PeerId) -> Signal<Void, NoError>
if let updateRank {
updateRankSignal = { peerId in
return context.peerChannelMemberCategoriesContextsManager.updateMemberRank(engine: context.engine, peerId: peerId, memberId: memberId, rank: updateRank)
|> `catch` { _ -> Signal<Void, NoError> in
return .single(Void())
}
}
} else {
updateRankSignal = { _ in return .complete() }
}
if let resolvedRights = resolvedRights, previousRights != resolvedRights {
let cleanResolvedRightsFlags = resolvedRights.flags.union(defaultBannedRightsFlags)
let cleanResolvedRights = TelegramChatBannedRights(flags: cleanResolvedRightsFlags, untilDate: resolvedRights.untilDate)
if cleanResolvedRights.flags.isEmpty && previousRights == nil {
dismissImpl?()
updateRankDisposable.set((updateRankSignal(peerId)
|> deliverOnMainQueue).start(completed: {
dismissImpl?()
}))
} else {
let applyRights: () -> Void = {
updateState { state in
@ -770,9 +980,15 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
guard let upgradedPeerId = upgradedPeerId else {
return .single(nil)
}
let rankSignal = updateRankSignal(upgradedPeerId)
return context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: context.engine, peerId: upgradedPeerId, memberId: memberId, bannedRights: cleanResolvedRights)
|> mapToSignal { _ -> Signal<PeerId?, NoError> in
return .complete()
return rankSignal
|> mapToSignal { _ -> Signal<PeerId?, NoError> in
return .complete()
}
}
|> then(.single(upgradedPeerId))
}
@ -799,36 +1015,42 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
}))
} else {
updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: context.engine, peerId: peerId, memberId: memberId, bannedRights: cleanResolvedRights)
|> deliverOnMainQueue).start(error: { _ in
}, completed: {
if previousRights == nil {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.GroupPermission_AddSuccess, false)), nil)
}
updated(cleanResolvedRights.flags.isEmpty ? nil : cleanResolvedRights)
dismissImpl?()
}))
|> deliverOnMainQueue).start(error: { _ in
}, completed: {
if previousRights == nil {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.GroupPermission_AddSuccess, false)), nil)
}
updated(cleanResolvedRights.flags.isEmpty ? nil : cleanResolvedRights)
dismissImpl?()
}))
updateRankDisposable.set(updateRankSignal(peerId).start())
}
}
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
let actionSheet = ActionSheetController(presentationData: presentationData)
var items: [ActionSheetItem] = []
items.append(ActionSheetTextItem(title: presentationData.strings.GroupPermission_ApplyAlertText(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string))
items.append(ActionSheetButtonItem(title: presentationData.strings.GroupPermission_ApplyAlertAction, color: .accent, font: .default, enabled: true, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
applyRights()
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
presentControllerImpl?(actionSheet, nil)
applyRights()
// let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
// let actionSheet = ActionSheetController(presentationData: presentationData)
// var items: [ActionSheetItem] = []
// items.append(ActionSheetTextItem(title: presentationData.strings.GroupPermission_ApplyAlertText(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)).string))
// items.append(ActionSheetButtonItem(title: presentationData.strings.GroupPermission_ApplyAlertAction, color: .accent, font: .default, enabled: true, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// applyRights()
// }))
// actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
// ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// })
// ])])
// presentControllerImpl?(actionSheet, nil)
}
} else {
dismissImpl?()
updateRankDisposable.set((updateRankSignal(peerId)
|> deliverOnMainQueue).start(completed: {
dismissImpl?()
}))
}
})
}
@ -845,11 +1067,21 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
}
}
let footerItem = ChannelParticipantFooterItem(theme: presentationData.theme, title: footerButtonTitle, displayProgress: state.updating, action: {
rightButtonActionImpl()
})
let rightNavigationButton: ItemListNavigationButton?
let footerItem: ItemListControllerFooterItem?
if state.focusedOnRank {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
rightButtonActionImpl()
})
footerItem = nil
} else {
rightNavigationButton = nil
footerItem = ChannelParticipantFooterItem(theme: presentationData.theme, title: footerButtonTitle, displayProgress: state.updating, action: {
rightButtonActionImpl()
})
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelBannedMemberControllerEntries(presentationData: presentationData, state: state, accountPeerId: context.account.peerId, channelPeer: channelPeer, memberPeer: memberPeer, memberPresence: memberPresence, initialParticipant: initialParticipant, initialBannedBy: initialBannedByPeer, editMember: editMember), style: .blocks, emptyStateItem: nil, footerItem: footerItem, animateChanges: true)
@ -870,5 +1102,41 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen
pushControllerImpl = { [weak controller] c in
controller?.push(c)
}
let hapticFeedback = HapticFeedback()
errorImpl = { [weak controller] in
hapticFeedback.error()
controller?.forEachItemNode { itemNode in
if let itemNode = itemNode as? ItemListSingleLineInputItemNode {
itemNode.animateError()
}
}
}
scrollToRankImpl = { [weak controller] in
controller?.afterLayout({
guard let controller = controller else {
return
}
var resultItemNode: ListViewItemNode?
let _ = controller.frameForItemNode({ itemNode in
if let itemNode = itemNode as? ItemListSingleLineInputItemNode {
if let tag = itemNode.tag as? ChannelBannedMemberEntryTag, tag == .rank {
resultItemNode = itemNode
return true
}
}
return false
})
if let resultItemNode = resultItemNode {
Queue.mainQueue().after(0.1) {
controller.ensureItemNodeVisible(resultItemNode, atTop: true)
}
}
})
}
dismissInputImpl = { [weak controller] in
controller?.view.endEditing(true)
}
return controller
}

View file

@ -685,9 +685,15 @@ public func channelMembersController(context: AccountContext, updatedPresentatio
}))
}, openParticipant: { participant, isGroup in
if isGroup {
let controller = channelBannedMemberController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, memberId: participant.peer.id, editMember: true, initialParticipant: participant.participant, updated: { rights in
}, upgradedToSupergroup: { _, _ in })
pushControllerImpl?(controller)
if let _ = participant.participant.adminInfo {
let controller = channelAdminController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, adminId: participant.participant.peerId, initialParticipant: participant.participant, updated: { _ in
}, upgradedToSupergroup: { _, _ in }, transferedOwnership: { _ in })
pushControllerImpl?(controller)
} else {
let controller = channelBannedMemberController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, memberId: participant.peer.id, editMember: true, initialParticipant: participant.participant, updated: { rights in
}, upgradedToSupergroup: { _, _ in })
pushControllerImpl?(controller)
}
} else {
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: participant.peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
pushControllerImpl?(infoController)

View file

@ -45,7 +45,7 @@ public struct PresentationResourcesRootController {
public static func navigationShareIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationShareIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.rootController.navigationBar.accentTextColor)
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.rootController.navigationBar.buttonColor)
})
// return theme.image(PresentationResourceKey.navigationShareIcon.rawValue, generateShareButtonImage)
}
@ -113,7 +113,7 @@ public struct PresentationResourcesRootController {
public static func navigationMoreCircledIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationMoreCircledIcon.rawValue, { theme in
generateTintedImage(image: UIImage(bundleImageName: "Chat List/NavigationMore"), color: theme.rootController.navigationBar.accentTextColor)
generateTintedImage(image: UIImage(bundleImageName: "Chat List/NavigationMore"), color: theme.rootController.navigationBar.buttonColor)
})
}
@ -125,7 +125,7 @@ public struct PresentationResourcesRootController {
public static func navigationAddIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationAddIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: theme.rootController.navigationBar.accentTextColor)
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddIcon"), color: theme.rootController.navigationBar.buttonColor)
})
}

View file

@ -2343,7 +2343,13 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
return result
}, to: &text, entities: &entities)
} else {
appendAttributedText(text: self.presentationData.strings.Channel_AdminLog_MessageRankNew(newRank), generateEntities: { index in
var result: [MessageTextEntityType] = []
if index == 0 {
result.append(.Bold)
}
return result
}, to: &text, entities: &entities)
}
var attributes: [MessageAttribute] = []
if !entities.isEmpty {