[WIP] Post suggestion

This commit is contained in:
Isaac 2025-06-17 15:22:39 +04:00
parent da225fd4d8
commit ab470b6be7
18 changed files with 140 additions and 42 deletions

View File

@ -178,6 +178,7 @@ public final class BrowserBookmarksScreen: ViewController {
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))

View File

@ -496,10 +496,12 @@ public final class ChatInterfaceState: Codable, Equatable {
}
public struct PostSuggestionState: Codable, Equatable {
public var editingOriginalMessageId: MessageId?
public var price: Int64
public var timestamp: Int32?
public init(price: Int64, timestamp: Int32?) {
public init(editingOriginalMessageId: MessageId?, price: Int64, timestamp: Int32?) {
self.editingOriginalMessageId = editingOriginalMessageId
self.price = price
self.timestamp = timestamp
}

View File

@ -1348,7 +1348,7 @@ public final class ChatEmptyNodePremiumRequiredChatContent: ASDisplayNode, ChatE
text: .plain(NSAttributedString(string: actionText, font: Font.semibold(15.0), textColor: serviceColor.primaryText))
)),
environment: {},
containerSize: CGSize(width: 200.0, height: 100.0)
containerSize: CGSize(width: 250.0, height: 100.0)
)
} else {
self.buttonTitle.view?.removeFromSuperview()

View File

@ -34,6 +34,7 @@ swift_library(
"//submodules/Markdown",
"//submodules/ComponentFlow",
"//submodules/ReactionSelectionNode",
"//submodules/Components/MultilineTextComponent",
],
visibility = [
"//visibility:public",

View File

@ -24,6 +24,7 @@ import ChatMessageItemCommon
import Markdown
import ComponentFlow
import ReactionSelectionNode
import MultilineTextComponent
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, messageCount: Int? = nil, accountPeerId: PeerId, forForumOverview: Bool) -> NSAttributedString? {
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), messageCount: messageCount, accountPeerId: accountPeerId, forChatList: false, forForumOverview: forForumOverview)
@ -40,7 +41,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
public let backgroundMaskNode: ASImageNode
public var linkHighlightingNode: LinkHighlightingNode?
private var buyStarsTitle: ComponentView<Empty>?
private var buyStarsTitle: TextNode?
private var buyStarsButton: HighlightTrackingButton?
private var buttonStarsNode: PremiumStarsNode?
@ -162,9 +163,16 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
return mediaHidden
}
@objc private func buyStarsPressed() {
if let item = self.item {
item.controllerInteraction.openStarsPurchase(nil)
}
}
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeLabelLayout = TextNodeWithEntities.asyncLayout(self.labelNode)
let makeBuyStarsTitleLayout = TextNode.asyncLayout(self.buyStarsTitle)
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
@ -322,6 +330,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
}
let rawString: String
var smallFont = false
switch suggestedPost {
case .approved:
rawString = "🤝 Agreement Reached!"
@ -336,6 +345,7 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
}
case .lowBalance:
rawString = "⚠️ **Transaction failed** because the user didn't have enough Stars."
smallFont = true
}
} else {
switch reason {
@ -347,13 +357,15 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
}
case .lowBalance:
rawString = "⚠️ **Transaction failed** because you didn't have enough Stars."
smallFont = true
}
}
}
let baseFontSize: CGFloat = smallFont ? 13.0 : 15.0
let titleString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(
body: MarkdownAttributeSet(font: Font.regular(15.0), textColor: primaryTextColor),
bold: MarkdownAttributeSet(font: Font.bold(15.0), textColor: primaryTextColor),
link: MarkdownAttributeSet(font: Font.semibold(15.0), textColor: primaryTextColor),
body: MarkdownAttributeSet(font: Font.regular(baseFontSize), textColor: primaryTextColor),
bold: MarkdownAttributeSet(font: Font.bold(baseFontSize), textColor: primaryTextColor),
link: MarkdownAttributeSet(font: Font.semibold(baseFontSize), textColor: primaryTextColor),
linkAttribute: { url in
return ("URL", url)
}
@ -429,6 +441,26 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
backgroundSize.height += 4.0
}
var hasBuyStarsButton = false
if item.message.effectivelyIncoming(item.context.account.peerId), let suggestedPost, case let .rejected(reason, _) = suggestedPost, case .lowBalance = reason {
hasBuyStarsButton = true
}
var buyStarsTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
var buyStarsButtonSize: CGSize?
if hasBuyStarsButton {
//TODO:localize
let serviceColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
let buyStarsTitleLayoutAndApplyValue = makeBuyStarsTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Buy Stars", font: Font.semibold(15.0), textColor: serviceColor.primaryText), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: textAlignment, cutout: nil, insets: UIEdgeInsets()))
buyStarsTitleLayoutAndApply = buyStarsTitleLayoutAndApplyValue
let buyStarsButtonSizeValue = CGSize(width: buyStarsTitleLayoutAndApplyValue.0.size.width + 20.0 * 2.0, height: buyStarsTitleLayoutAndApplyValue.0.size.height + 8.0 * 2.0)
buyStarsButtonSize = buyStarsButtonSizeValue
backgroundSize.width = max(backgroundSize.width, buyStarsButtonSizeValue.width + 8.0 * 2.0)
backgroundSize.height += 15.0 + buyStarsButtonSizeValue.height
}
return (backgroundSize.width, { boundingWidth in
return (CGSize(width: boundingWidth, height: backgroundSize.height + contentOuterInsets.top + contentOuterInsets.bottom), { [weak self] animation, synchronousLoads, _ in
if let strongSelf = self {
@ -540,40 +572,66 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
animation.animator.updatePosition(layer: titleNode.layer, position: titleFrame.origin, completion: nil)
titleNode.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
}
} else {
labelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingWidth - labelLayout.size.width) / 2.0) - 1.0, y: image != nil ? 2.0 : floorToScreenPixels((backgroundSize.height - labelLayout.size.height) / 2.0) - 1.0), size: labelLayout.size)
contentFrame = labelFrame
}
if item.message.effectivelyIncoming(item.context.account.peerId), let suggestedPost, case let .rejected(reason, _) = suggestedPost, case .lowBalance = reason {
let buyStarsTitle: ComponentView<Empty>?
if let current = strongSelf.buyStarsTitle {
buyStarsTitle = current
} else {
buyStarsTitle = ComponentView()
strongSelf.buyStarsTitle = buyStarsTitle
}
let buyStarsButton: HighlightTrackingButton?
if hasBuyStarsButton, let (buyStarsTitleLayout, buyStarsTitleApply) = buyStarsTitleLayoutAndApply, let buyStarsButtonSize {
let buyStarsButton: HighlightTrackingButton
if let current = strongSelf.buyStarsButton {
buyStarsButton = current
} else {
buyStarsButton = HighlightTrackingButton()
buyStarsButton.clipsToBounds = true
strongSelf.buyStarsButton = buyStarsButton
strongSelf.view.addSubview(buyStarsButton)
buyStarsButton.highligthedChanged = { [weak buyStarsButton] highlighted in
guard let buyStarsButton else {
return
}
if highlighted {
buyStarsButton.layer.removeAnimation(forKey: "opacity")
buyStarsButton.alpha = 0.6
} else {
buyStarsButton.alpha = 1.0
buyStarsButton.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
}
}
buyStarsButton.addTarget(strongSelf, action: #selector(strongSelf.buyStarsPressed), for: .touchUpInside)
}
let buttonStarsNode: PremiumStarsNode?
let buttonStarsNode: PremiumStarsNode
if let current = strongSelf.buttonStarsNode {
buttonStarsNode = current
} else {
buttonStarsNode = PremiumStarsNode()
buttonStarsNode.isUserInteractionEnabled = false
strongSelf.buttonStarsNode = buttonStarsNode
buyStarsButton.addSubview(buttonStarsNode.view)
}
let buyStarsTitle = buyStarsTitleApply()
if buyStarsTitle !== strongSelf.buyStarsTitle {
buyStarsTitle.isUserInteractionEnabled = false
strongSelf.buyStarsTitle?.view.removeFromSuperview()
}
strongSelf.buyStarsTitle = buyStarsTitle
buyStarsButton.addSubview(buyStarsTitle.view)
let buttonTitleSize = buyStarsTitleLayout.size
let buttonFrame = CGRect(origin: CGPoint(x: contentFrame.minX + floor((contentFrame.width - buyStarsButtonSize.width) * 0.5), y: labelFrame.minY - 2.0), size: buyStarsButtonSize)
buyStarsButton.frame = buttonFrame
buyStarsButton.layer.cornerRadius = buttonFrame.height * 0.5
buyStarsTitle.frame = CGRect(origin: CGPoint(x: floor((buyStarsButtonSize.width - buttonTitleSize.width) * 0.5), y: floor((buyStarsButtonSize.height - buttonTitleSize.height) * 0.5)), size: buttonTitleSize)
buyStarsButton.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
buttonStarsNode.frame = CGRect(origin: CGPoint(), size: buyStarsButtonSize)
} else {
if let buyStarsTitle = strongSelf.buyStarsTitle {
strongSelf.buyStarsTitle = nil
buyStarsTitle.view?.removeFromSuperview()
buyStarsTitle.view.removeFromSuperview()
}
if let buyStarsButton = strongSelf.buyStarsButton {
strongSelf.buyStarsButton = nil
@ -871,9 +929,12 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
return ChatMessageBubbleContentTapAction(content: .hashtag(hashtag.peerName, hashtag.hashtag))
}
}
if let imageNode = imageNode, imageNode.frame.contains(point) {
if let imageNode = self.imageNode, imageNode.frame.contains(point) {
return ChatMessageBubbleContentTapAction(content: .openMessage)
}
if let buyStarsButton = self.buyStarsButton, buyStarsButton.frame.contains(point) {
return ChatMessageBubbleContentTapAction(content: .ignore)
}
if let backgroundNode = self.backgroundNode, backgroundNode.frame.contains(point) {
if let item = self.item, item.message.media.contains(where: { $0 is TelegramMediaStory }) {

View File

@ -1060,6 +1060,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
self.backgroundWallpaperNode.animateFrom(sourceView: textInput.backgroundView, transition: transition)
self.backgroundNode.animateFrom(sourceView: textInput.backgroundView, transition: transition)
if let suggestedPostInfoNode = self.suggestedPostInfoNode {
transition.horizontal.animatePositionAdditive(layer: suggestedPostInfoNode.layer, offset: CGPoint(x: -widthDifference, y: 0.0))
transition.horizontal.animateTransformScale(view: suggestedPostInfoNode.view, from: 0.001)
suggestedPostInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
}
for contentNode in self.contentNodes {
if let contentNode = contentNode as? ChatMessageTextBubbleContentNode {
let localSourceContentFrame = self.mainContextSourceNode.contentNode.view.convert(textInput.contentView.frame.offsetBy(dx: self.mainContextSourceNode.contentRect.minX, dy: self.mainContextSourceNode.contentRect.minY), to: contentNode.view)
@ -3526,11 +3532,9 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
strongSelf.suggestedPostInfoNode?.removeFromSupernode()
strongSelf.suggestedPostInfoNode = suggestedPostInfoNode
strongSelf.mainContextSourceNode.contentNode.addSubnode(suggestedPostInfoNode)
let suggestedPostInfoFrame = CGRect(origin: CGPoint(x: floor((params.width - suggestedPostInfoSize.width) * 0.5), y: 4.0), size: suggestedPostInfoSize)
suggestedPostInfoNode.frame = suggestedPostInfoFrame
//animation.animator.updateFrame(layer: suggestedPostInfoNode.layer, frame: suggestedPostInfoFrame, completion: nil)
}
let suggestedPostInfoFrame = CGRect(origin: CGPoint(x: floor((params.width - suggestedPostInfoSize.width) * 0.5), y: 4.0), size: suggestedPostInfoSize)
suggestedPostInfoNode.frame = suggestedPostInfoFrame
} else if let suggestedPostInfoNode = strongSelf.suggestedPostInfoNode {
strongSelf.suggestedPostInfoNode = nil
suggestedPostInfoNode.removeFromSupernode()

View File

@ -649,6 +649,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: self.backgroundNode))
self.controllerInteraction = controllerInteraction

View File

@ -504,6 +504,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: self.context, backgroundNode: self.wallpaperBackgroundNode))

View File

@ -288,6 +288,8 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
public let updateChatLocationThread: (Int64?, ChatControllerAnimateInnerChatSwitchDirection?) -> Void
public let requestToggleTodoMessageItem: (MessageId, Int32, Bool) -> Void
public let displayTodoToggleUnavailable: (MessageId) -> Void
public let openStarsPurchase: (Int64?) -> Void
public var canPlayMedia: Bool = false
public var hiddenMedia: [MessageId: [Media]] = [:]
public var expandedTranslationMessageStableIds: Set<UInt32> = Set()
@ -452,6 +454,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
updateChatLocationThread: @escaping (Int64?, ChatControllerAnimateInnerChatSwitchDirection?) -> Void,
requestToggleTodoMessageItem: @escaping (MessageId, Int32, Bool) -> Void,
displayTodoToggleUnavailable: @escaping (MessageId) -> Void,
openStarsPurchase: @escaping (Int64?) -> Void,
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
pollActionState: ChatInterfacePollActionState,
stickerSettings: ChatInterfaceStickerSettings,
@ -573,6 +576,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
self.updateChatLocationThread = updateChatLocationThread
self.requestToggleTodoMessageItem = requestToggleTodoMessageItem
self.displayTodoToggleUnavailable = displayTodoToggleUnavailable
self.openStarsPurchase = openStarsPurchase
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings

View File

@ -3869,6 +3869,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))
self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().startStrict(next: { [weak self] ids in

View File

@ -508,9 +508,9 @@ private final class SheetContent: CombinedComponent {
switch mode {
case .sender:
if let amount = state.amount {
buttonString = "Offer # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
buttonString = "Set # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))"
} else {
buttonString = "Offer"
buttonString = "Set"
}
case .admin:
buttonString = "Update Terms"

View File

@ -4140,6 +4140,7 @@ extension ChatControllerImpl {
state = state.updatedInterfaceState { interfaceState in
var interfaceState = interfaceState
interfaceState = interfaceState.withUpdatedPostSuggestionState(ChatInterfaceState.PostSuggestionState(
editingOriginalMessageId: nil,
price: 0,
timestamp: nil
))

View File

@ -1001,6 +1001,7 @@ extension ChatControllerImpl {
state = state.updatedInterfaceState { interfaceState in
var interfaceState = interfaceState
interfaceState = interfaceState.withUpdatedPostSuggestionState(ChatInterfaceState.PostSuggestionState(
editingOriginalMessageId: interfaceState.postSuggestionState?.editingOriginalMessageId,
price: price,
timestamp: timestamp
))

View File

@ -2358,20 +2358,28 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone()
}
case 2:
strongSelf.push(strongSelf.context.sharedContext.makeStarsWithdrawalScreen(
context: strongSelf.context,
subject: .postSuggestionModification(
current: StarsAmount(value: attribute.amount, nanos: 0),
timestamp: attribute.timestamp,
completion: { [weak strongSelf] price, timestamp in
guard let strongSelf else {
return
}
var entities: [MessageTextEntity] = []
for attribute in message.attributes {
if let attribute = attribute as? TextEntitiesMessageAttribute {
entities = attribute.entities
break
}
}
let inputText = chatInputStateStringWithAppliedEntities(message.text, entities: entities)
let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .proposeChanges(amount: price, timestamp: timestamp)).startStandalone()
}
)
))
strongSelf.updateChatPresentationInterfaceState(interactive: true, { state in
var state = state
state = state.updatedInterfaceState { interfaceState in
var interfaceState = interfaceState
interfaceState = interfaceState.withUpdatedPostSuggestionState(ChatInterfaceState.PostSuggestionState(
editingOriginalMessageId: message.id,
price: attribute.amount,
timestamp: attribute.timestamp
)).withUpdatedComposeInputState(ChatTextInputState(inputText: inputText))
return interfaceState
}
return state
})
default:
break
}
@ -4946,6 +4954,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
)
self.present(controller, in: .current)
}
}, openStarsPurchase: { [weak self] amount in
self?.interfaceInteraction?.openStarsPurchase(amount)
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode))
controllerInteraction.enableFullTranslucency = context.sharedContext.energyUsageSettings.fullTranslucency
@ -7917,6 +7927,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .customChatContents:
break
}
if let postSuggestionState = self.presentationInterfaceState.interfaceState.postSuggestionState, let editingOriginalMessageId = postSuggestionState.editingOriginalMessageId {
defaultReplyMessageSubject = EngineMessageReplySubject(messageId: editingOriginalMessageId, quote: nil)
}
return messages.map { message in
var message = message

View File

@ -1716,7 +1716,12 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
} else if let _ = accessoryPanelNode as? SuggestPostAccessoryPanelNode {
strongSelf.requestUpdateChatInterfaceState(.animated(duration: 0.4, curve: .spring), false, { state in
var state = state
state = state.withUpdatedPostSuggestionState(nil)
if let postSuggestionState = state.postSuggestionState {
state = state.withUpdatedPostSuggestionState(nil)
if postSuggestionState.editingOriginalMessageId != nil {
state = state.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: "")))
}
}
return state
})
}

View File

@ -231,7 +231,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
if channel.flags.contains(.isMonoforum) {
if let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = chatPresentationInterfaceState.renderedPeer?.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect), case .peer = chatPresentationInterfaceState.chatLocation {
if chatPresentationInterfaceState.interfaceState.editMessage != nil {
if chatPresentationInterfaceState.interfaceState.editMessage != nil || chatPresentationInterfaceState.interfaceState.postSuggestionState != nil {
displayInputTextPanel = true
} else if chatPresentationInterfaceState.interfaceState.replyMessageSubject == nil {
displayInputTextPanel = false

View File

@ -196,6 +196,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil))
self.dimNode = ASDisplayNode()

View File

@ -2402,6 +2402,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, updateChatLocationThread: { _, _ in
}, requestToggleTodoMessageItem: { _, _, _ in
}, displayTodoToggleUnavailable: { _ in
}, openStarsPurchase: { _ in
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: backgroundNode as? WallpaperBackgroundNode))