Various improvements

This commit is contained in:
Isaac 2025-06-27 09:58:46 +02:00
parent a78224b965
commit fd324106e3
11 changed files with 103 additions and 91 deletions

View File

@ -3797,6 +3797,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
controller.completion = { [weak controller] title, fileId, iconColor, _ in
controller?.isInProgress = true
controller?.view.endEditing(true)
let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId)
|> deliverOnMainQueue).startStandalone(next: { topicId in
@ -7127,7 +7128,7 @@ private final class ChatListLocationContext {
strings: presentationData.strings,
dateTimeFormat: presentationData.dateTimeFormat,
nameDisplayOrder: presentationData.nameDisplayOrder,
content: .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true),
content: .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true),
tapped: { [weak self] in
guard let self else {
return

View File

@ -3220,7 +3220,14 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
if displayAsMessage {
switch item.content {
case let .peer(peerData):
if let peer = peerData.messages.last?.author {
var iconPeer: EnginePeer?
if case let .chat(itemPeer) = contentPeer, let peer = itemPeer.chatOrMonoforumMainPeer {
iconPeer = peer
} else {
iconPeer = peerData.messages.last?.author
}
if let peer = iconPeer {
if case let .peer(peerData) = item.content, peerData.customMessageListData != nil {
currentCredibilityIconContent = nil
} else if case .savedMessagesChats = item.chatListLocation, peer.id == item.context.account.peerId {

View File

@ -127,6 +127,7 @@ public enum PresentationResourceKey: Int32 {
case chatListLocationIcon
case chatListGeneralTopicIcon
case chatListGeneralTopicTemplateIcon
case chatListGeneralTopicSmallIcon
case searchAdIcon

View File

@ -445,6 +445,12 @@ public struct PresentationResourcesChatList {
})
}
public static func generalTopicTemplateIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatListGeneralTopicTemplateIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/GeneralTopicIcon"), color: .white)?.withRenderingMode(.alwaysTemplate)
})
}
public static func statusAutoremoveIcon(_ theme: PresentationTheme, isActive: Bool) -> UIImage? {
return theme.image(PresentationResourceParameterKey.statusAutoremoveIcon(isActive: isActive), { theme in
return generateTintedImage(image: UIImage(bundleImageName: isActive ? "Chat List/StatusIconAutoremoveOn" : "Chat List/StatusIconAutoremoveOff"), color: isActive ? theme.list.itemAccentColor : theme.list.itemSecondaryTextColor)

View File

@ -360,6 +360,7 @@ public final class ChatSideTopicsPanel: Component {
}
func update(component: VerticalItemComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
let previousComponent = self.component
self.component = component
self.tapRecognizer?.isEnabled = component.action != nil
@ -381,12 +382,12 @@ public final class ChatSideTopicsPanel: Component {
if case let .forum(topicId) = component.item.item.id {
if topicId != 1, let threadData = component.item.item.threadData {
if let fileId = threadData.info.icon, fileId != 0 {
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: iconSize, placeholderColor: component.theme.list.mediaPlaceholderColor, themeColor: component.theme.list.itemAccentColor, loopMode: .count(0))
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: iconSize, placeholderColor: component.theme.list.mediaPlaceholderColor, themeColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor, loopMode: .count(0))
} else {
avatarIconContent = .topic(title: String(threadData.info.title.prefix(1)), color: threadData.info.iconColor, size: iconSize)
}
} else {
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicIcon(component.theme), tintColor: component.theme.rootController.navigationBar.secondaryTextColor)
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
}
}
@ -406,8 +407,14 @@ public final class ChatSideTopicsPanel: Component {
icon = ComponentView()
self.icon = icon
}
var iconTransition = transition
if iconTransition.animation.isImmediate, let previousComponent, previousComponent.isSelected != component.isSelected {
iconTransition = .easeInOut(duration: 0.2)
}
let _ = icon.update(
transition: .immediate,
transition: iconTransition,
component: AnyComponent(avatarIconComponent),
environment: {},
containerSize: iconSize
@ -813,12 +820,12 @@ public final class ChatSideTopicsPanel: Component {
if case let .forum(topicId) = component.item.item.id {
if topicId != 1, let threadData = component.item.item.threadData {
if let fileId = threadData.info.icon, fileId != 0 {
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: iconSize, placeholderColor: component.theme.list.mediaPlaceholderColor, themeColor: component.theme.list.itemAccentColor, loopMode: .count(0))
avatarIconContent = .animation(content: .customEmoji(fileId: fileId), size: iconSize, placeholderColor: component.theme.list.mediaPlaceholderColor, themeColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor, loopMode: .count(0))
} else {
avatarIconContent = .topic(title: String(threadData.info.title.prefix(1)), color: threadData.info.iconColor, size: iconSize)
}
} else {
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicIcon(component.theme), tintColor: component.theme.rootController.navigationBar.secondaryTextColor)
avatarIconContent = .image(image: PresentationResourcesChatList.generalTopicTemplateIcon(component.theme), tintColor: component.isSelected ? component.theme.rootController.navigationBar.accentTextColor : component.theme.rootController.navigationBar.controlColor)
}
}
@ -1845,7 +1852,7 @@ public final class ChatSideTopicsPanel: Component {
case .side:
scrollSize = CGSize(width: availableSize.width, height: availableSize.height - directionContainerInset)
scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: directionContainerInset), size: scrollSize)
listContentInsets = UIEdgeInsets(top: 8.0, left: 0.0, bottom: 8.0, right: 0.0)
listContentInsets = UIEdgeInsets(top: 8.0 + environment.insets.top, left: 0.0, bottom: 8.0 + environment.insets.bottom, right: 0.0)
case .top:
scrollSize = CGSize(width: availableSize.width - directionContainerInset, height: availableSize.height)
scrollFrame = CGRect(origin: CGPoint(x: directionContainerInset, y: 0.0), size: scrollSize)

View File

@ -92,20 +92,23 @@ public enum ChatTitleContent: Equatable {
case replies
}
case peer(peerView: PeerData, customTitle: String?, onlineMemberCount: (total: Int32?, recent: Int32?), isScheduledMessages: Bool, isMuted: Bool?, customMessageCount: Int?, isEnabled: Bool)
case peer(peerView: PeerData, customTitle: String?, customSubtitle: String?, onlineMemberCount: (total: Int32?, recent: Int32?), isScheduledMessages: Bool, isMuted: Bool?, customMessageCount: Int?, isEnabled: Bool)
case replyThread(type: ReplyThreadType, count: Int)
case custom(String, String?, Bool)
public static func ==(lhs: ChatTitleContent, rhs: ChatTitleContent) -> Bool {
switch lhs {
case let .peer(peerView, customTitle, onlineMemberCount, isScheduledMessages, isMuted, customMessageCount, isEnabled):
if case let .peer(rhsPeerView, rhsCustomTitle, rhsOnlineMemberCount, rhsIsScheduledMessages, rhsIsMuted, rhsCustomMessageCount, rhsIsEnabled) = rhs {
case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, isMuted, customMessageCount, isEnabled):
if case let .peer(rhsPeerView, rhsCustomTitle, rhsCustomSubtitle, rhsOnlineMemberCount, rhsIsScheduledMessages, rhsIsMuted, rhsCustomMessageCount, rhsIsEnabled) = rhs {
if peerView != rhsPeerView {
return false
}
if customTitle != rhsCustomTitle {
return false
}
if customSubtitle != rhsCustomSubtitle {
return false
}
if onlineMemberCount.0 != rhsOnlineMemberCount.0 || onlineMemberCount.1 != rhsOnlineMemberCount.1 {
return false
}
@ -246,7 +249,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var titleStatusIcon: ChatTitleCredibilityIcon = .none
var isEnabled = true
switch titleContent {
case let .peer(peerView, customTitle, _, isScheduledMessages, isMuted, _, isEnabledValue):
case let .peer(peerView, customTitle, _, _, isScheduledMessages, isMuted, _, isEnabledValue):
if peerView.peerId.isReplies {
let typeText: String = self.strings.DialogList_Replies
segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
@ -260,7 +263,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
isEnabled = false
} else {
if let peer = peerView.peer {
if let customTitle = customTitle {
if let customTitle {
segments = [.text(0, NSAttributedString(string: customTitle, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))]
} else if peerView.peerId == self.context.account.peerId {
if peerView.isSavedMessages {
@ -444,8 +447,8 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var enableAnimation = false
switch titleContent {
case let .peer(_, customTitle, _, _, _, _, _):
if case let .peer(_, previousCustomTitle, _, _, _, _, _) = oldValue {
case let .peer(_, customTitle, _, _, _, _, _, _):
if case let .peer(_, previousCustomTitle, _, _, _, _, _, _) = oldValue {
if customTitle != previousCustomTitle {
enableAnimation = false
}
@ -471,7 +474,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var inputActivitiesAllowed = true
if let titleContent = self.titleContent {
switch titleContent {
case let .peer(peerView, _, _, isScheduledMessages, _, _, _):
case let .peer(peerView, _, _, _, isScheduledMessages, _, _, _):
if let peer = peerView.peer {
if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isRepliesOrVerificationCodes {
inputActivitiesAllowed = false
@ -572,8 +575,11 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
} else {
if let titleContent = self.titleContent {
switch titleContent {
case let .peer(peerView, customTitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _):
if let customMessageCount = customMessageCount, customMessageCount != 0 {
case let .peer(peerView, customTitle, customSubtitle, onlineMemberCount, isScheduledMessages, _, customMessageCount, _):
if let customSubtitle {
let string = NSAttributedString(string: customSubtitle, font: subtitleFont, textColor: titleTheme.rootController.navigationBar.secondaryTextColor)
state = .info(string, .generic)
} else if let customMessageCount = customMessageCount, customMessageCount != 0 {
let string = NSAttributedString(string: self.strings.Conversation_Messages(Int32(customMessageCount)), font: subtitleFont, textColor: titleTheme.rootController.navigationBar.secondaryTextColor)
state = .info(string, .generic)
} else if let peer = peerView.peer {

View File

@ -233,7 +233,10 @@ public final class EmojiStatusComponent: Component {
private weak var state: EmptyComponentState?
private var component: EmojiStatusComponent?
private var starsLayer: StarsEffectLayer?
private var iconView: UIImageView?
private var iconLayer: SimpleLayer?
private var iconLayerImage: UIImage?
private var animationLayer: InlineStickerItemLayer?
private var lottieAnimationView: AnimationView?
private let hierarchyTrackingLayer: HierarchyTrackingLayer
@ -323,7 +326,7 @@ public final class EmojiStatusComponent: Component {
case let .premium(color):
iconTintColor = color
if case .premium = self.component?.content, let image = self.iconView?.image {
if case .premium = self.component?.content, let image = self.iconLayerImage {
iconImage = image
} else {
if let sourceImage = UIImage(bundleImageName: "Chat/Input/Media/EntityInputPremiumIcon") {
@ -454,7 +457,7 @@ public final class EmojiStatusComponent: Component {
}
}
} else {
iconImage = self.iconView?.image
iconImage = self.iconLayerImage
if case let .animation(animationContent, size, placeholderColor, themeColor, loopMode) = component.content {
emojiFileId = animationContent.fileId.id
emojiPlaceholderColor = placeholderColor
@ -471,31 +474,28 @@ public final class EmojiStatusComponent: Component {
var size = CGSize()
if let iconImage = iconImage {
let iconView: UIImageView
if let current = self.iconView {
iconView = current
let iconLayer: SimpleLayer
if let current = self.iconLayer {
iconLayer = current
} else {
iconView = UIImageView()
self.iconView = iconView
self.addSubview(iconView)
iconLayer = SimpleLayer()
self.iconLayer = iconLayer
self.layer.addSublayer(iconLayer)
if !transition.animation.isImmediate {
iconView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
iconView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
iconLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
iconLayer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
}
}
if iconView.image !== iconImage {
iconView.image = iconImage
if self.iconLayerImage !== iconImage {
self.iconLayerImage = iconImage
iconLayer.contents = iconImage.cgImage
}
if let iconTintColor {
if transition.animation.isImmediate {
iconView.tintColor = iconTintColor
} else {
transition.setTintColor(view: iconView, color: iconTintColor)
}
transition.setTintColor(layer: iconLayer, color: iconTintColor)
} else {
iconView.tintColor = nil
iconLayer.layerTintColor = nil
}
var useFit = false
@ -509,24 +509,25 @@ public final class EmojiStatusComponent: Component {
}
if useFit {
size = CGSize(width: iconImage.size.width, height: availableSize.height)
iconView.frame = CGRect(origin: CGPoint(x: floor((size.width - iconImage.size.width) / 2.0), y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
iconLayer.frame = CGRect(origin: CGPoint(x: floor((size.width - iconImage.size.width) / 2.0), y: floor((size.height - iconImage.size.height) / 2.0)), size: iconImage.size)
} else {
size = iconImage.size.aspectFilled(availableSize)
iconView.frame = CGRect(origin: CGPoint(), size: size)
iconLayer.frame = CGRect(origin: CGPoint(), size: size)
}
} else {
if let iconView = self.iconView {
self.iconView = nil
if let iconLayer = self.iconLayer {
self.iconLayer = nil
if !transition.animation.isImmediate {
iconView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak iconView] _ in
iconView?.removeFromSuperview()
iconLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak iconLayer] _ in
iconLayer?.removeFromSuperlayer()
})
iconView.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
iconLayer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
} else {
iconView.removeFromSuperview()
iconLayer.removeFromSuperlayer()
}
}
self.iconLayerImage = nil
}
let emojiFileUpdated = component.emojiFileUpdated
@ -607,44 +608,6 @@ public final class EmojiStatusComponent: Component {
animationLayer.frame = CGRect(origin: CGPoint(), size: size)
animationLayer.isVisibleForAnimations = component.isVisibleForAnimations
/*} else {
if self.emojiFileDataPathDisposable == nil {
let account = component.context.account
self.emojiFileDataPathDisposable = (Signal<AnimationFileProperties?, NoError> { subscriber in
let disposable = MetaDisposable()
let _ = (account.postbox.mediaBox.resourceData(emojiFile.resource)
|> take(1)).start(next: { firstAttemptData in
if firstAttemptData.complete {
subscriber.putNext(AnimationFileProperties.load(from: firstAttemptData.path))
subscriber.putCompletion()
} else {
let fetchDisposable = freeMediaFileInteractiveFetched(account: account, fileReference: .standalone(media: emojiFile)).start()
let dataDisposable = account.postbox.mediaBox.resourceData(emojiFile.resource).start(next: { data in
if data.complete {
subscriber.putNext(AnimationFileProperties.load(from: data.path))
subscriber.putCompletion()
}
})
disposable.set(ActionDisposable {
fetchDisposable.dispose()
dataDisposable.dispose()
})
}
})
return disposable
}
|> deliverOnMainQueue).start(next: { [weak self] properties in
guard let strongSelf = self else {
return
}
strongSelf.emojiFileDataProperties = properties
strongSelf.state?.updated(transition: transition)
})
}
}*/
} else {
if self.emojiFileDisposable == nil {
self.emojiFileDisposable = (component.resolveInlineStickers([emojiFileId])

View File

@ -967,7 +967,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return false
}
switch action.action {
case .pinnedMessageUpdated, .gameScore, .setSameChatWallpaper, .giveawayResults, .customText, .todoCompletions, .todoAppendTasks:
case .pinnedMessageUpdated, .gameScore, .setSameChatWallpaper, .giveawayResults, .customText, .todoCompletions, .todoAppendTasks, .suggestedPostRefund, .suggestedPostSuccess, .suggestedPostApprovalStatus:
for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
var todoTaskId: Int32?
@ -1244,6 +1244,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .boostsApplied:
self.controllerInteraction?.openGroupBoostInfo(nil, 0)
return true
case .paidMessagesPriceEdited:
self.interfaceInteraction?.openMonoforum()
return true
default:
break
}

View File

@ -548,12 +548,20 @@ extension ChatControllerImpl {
strongSelf.state.chatTitleContent = .custom(strings.Chat_TitlePinnedMessages(Int32(displayedCount ?? 1)), nil, false)
} else if let channel = peer as? TelegramChannel, channel.isMonoForum {
if let linkedMonoforumId = channel.linkedMonoforumId, let mainPeer = peerView.peers[linkedMonoforumId] {
strongSelf.state.chatTitleContent = .custom(mainPeer.debugDisplayTitle, strings.Chat_Monoforum_Subtitle, true)
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(
peerId: mainPeer.id,
peer: mainPeer,
isContact: false,
isSavedMessages: false,
notificationSettings: nil,
peerPresences: [:],
cachedData: nil
), customTitle: nil, customSubtitle: strings.Chat_Monoforum_Subtitle, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true)
} else {
strongSelf.state.chatTitleContent = .custom(channel.debugDisplayTitle, nil, true)
}
} else {
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo)
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo)
let imageOverride: AvatarNodeImageOverride?
if context.account.peerId == peer.id {
@ -1447,7 +1455,7 @@ extension ChatControllerImpl {
customMessageCount = savedMessagesPeer?.messageCount ?? 0
}
strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, isEnabled: true)
strongSelf.state.chatTitleContent = .peer(peerView: mappedPeerData, customTitle: nil, customSubtitle: nil, onlineMemberCount: (nil, nil), isScheduledMessages: false, isMuted: false, customMessageCount: customMessageCount, isEnabled: true)
strongSelf.state.peerView = peerView
@ -1534,7 +1542,7 @@ extension ChatControllerImpl {
}
if let threadInfo = messageAndTopic.threadData?.info {
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, isEnabled: true)
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: threadInfo.title, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: peerIsMuted, customMessageCount: messageAndTopic.messageCount == 0 ? nil : messageAndTopic.messageCount, isEnabled: true)
let avatarContent: EmojiStatusComponent.Content
if chatLocation.threadId == 1 {

View File

@ -2477,11 +2477,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
ChatSidePanelEnvironment(insets: UIEdgeInsets(
top: 0.0,
left: leftPanelLeftInset,
bottom: 0.0,
bottom: containerInsets.bottom + inputPanelsHeight,
right: 0.0
))
},
containerSize: CGSize(width: leftPanelSize.width, height: leftPanelSize.height - sidePanelTopInset - (containerInsets.bottom + inputPanelsHeight))
containerSize: CGSize(width: leftPanelSize.width, height: leftPanelSize.height - sidePanelTopInset)
)
let leftPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: sidePanelTopInset), size: leftPanelSize)

View File

@ -149,6 +149,13 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
canMatchThread = true
switchToThread = true
}
if case .replyThread = params.chatLocation {
if case let .replyThread(replyThread) = params.chatLocation, (replyThread.isForumPost || replyThread.isMonoforumPost) {
} else {
canMatchThread = false
switchToThread = false
}
}
if controller.chatLocation.peerId == params.chatLocation.asChatLocation.peerId && canMatchThread && (controller.subject != .scheduledMessages || controller.subject == params.subject) {
if let updateTextInputState = params.updateTextInputState {
@ -191,7 +198,10 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
controller.purposefulAction = params.purposefulAction
if let activateInput = params.activateInput {
controller.activateInput(type: activateInput)
if case let .replyThread(replyThread) = params.chatLocation, (replyThread.isForumPost || replyThread.isMonoforumPost) {
} else {
controller.activateInput(type: activateInput)
}
}
if params.changeColors {
controller.presentThemeSelection()