This commit is contained in:
isaac 2026-04-26 02:52:26 +04:00
commit a04db4a2a6
4 changed files with 90 additions and 58 deletions

View file

@ -3103,17 +3103,18 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg
self.textPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor)
self.textInputNode?.textView.accessibilityHint = currentPlaceholder
if transition.isAnimated, let snapshotView = self.textPlaceholderNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.textPlaceholderNode.frame
self.textPlaceholderNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.textPlaceholderNode.view)
snapshotView.layer.animateAlpha(from: snapshotView.alpha, to: 0.0, duration: 0.22, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
self.textPlaceholderNode.layer.animateAlpha(from: 0.0, to: self.textPlaceholderNode.alpha, duration: 0.18)
}
let placeholderSize = self.textPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))
if transition.isAnimated, let snapshotLayer = self.textPlaceholderNode.layer.snapshotContentTree() {
self.textPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.textPlaceholderNode.layer)
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.22, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
snapshotLayer?.removeFromSuperlayer()
})
self.textPlaceholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
}
textPlaceholderSize = placeholderSize
} else {
textPlaceholderSize = self.textPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude))

View file

@ -185,11 +185,19 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
//TODO:localize
let text: String
if case .user = peer {
if isSilentPosting {
text = "\(peer.compactDisplayTitle) will receive a silent notification"
if case let .user(user) = peer {
if user.id == component.context.account.peerId {
if isSilentPosting {
text = "You will receive a silent notification"
} else {
text = "You will be notified"
}
} else {
text = "\(peer.compactDisplayTitle) will be notified"
if isSilentPosting {
text = "\(peer.compactDisplayTitle) will receive a silent notification"
} else {
text = "\(peer.compactDisplayTitle) will be notified"
}
}
} else if isChannel {
if isSilentPosting {

View file

@ -188,9 +188,41 @@ extension ChatControllerImpl {
}
var dismissController: ((@escaping () -> Void) -> Void)?
let canDeleteReactions = canDeleteOtherUserMessages(message: message)
let canViewReactions = canViewMessageReactionList(message: message)
let deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)?
if canDeleteReactions && canViewReactions {
deleteReaction = { [weak self] peer, _ in
dismissController?({ [weak self] in
guard let self, self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudChannel else {
return
}
let _ = (self.context.sharedContext.chatAvailableMessageActions(
engine: self.context.engine,
accountPeerId: self.context.account.peerId,
messageIds: Set([message.id]),
keepUpdated: false
)
|> deliverOnMainQueue).startStandalone(next: { [weak self] actions in
guard let self, !actions.options.isEmpty else {
return
}
self.presentBanMessageOptions(
accountPeerId: self.context.account.peerId,
author: peer._asPeer(),
messageIds: Set([message.id]),
options: actions.options,
reaction: true
)
})
})
}
} else {
deleteReaction = nil
}
var items: ContextController.Items
if canViewMessageReactionList(message: message) {
if canViewReactions {
items = ContextController.Items(content: .custom(ReactionListContextMenuContent(
context: self.context,
displayReadTimestamps: true,
@ -210,31 +242,7 @@ extension ChatControllerImpl {
self.openPeer(peer: peer, navigation: .default, fromMessage: MessageReference(message), fromReactionMessageId: hasReaction ? message.id : nil)
})
},
deleteReaction: { [weak self] peer, _ in
dismissController?({ [weak self] in
guard let self, self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudChannel else {
return
}
let _ = (self.context.sharedContext.chatAvailableMessageActions(
engine: self.context.engine,
accountPeerId: self.context.account.peerId,
messageIds: Set([message.id]),
keepUpdated: false
)
|> deliverOnMainQueue).startStandalone(next: { [weak self] actions in
guard let self, !actions.options.isEmpty else {
return
}
self.presentBanMessageOptions(
accountPeerId: self.context.account.peerId,
author: peer._asPeer(),
messageIds: Set([message.id]),
options: actions.options,
reaction: true
)
})
})
}
deleteReaction: deleteReaction
)))
} else {
items = ContextController.Items(content: .list([]))
@ -325,7 +333,7 @@ extension ChatControllerImpl {
let presentationContext = self.controllerInteraction?.presentationContext
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
if "".isEmpty {
if canDeleteReactions && canViewReactions {
items.tip = .deleteReaction
} else if !packReferences.isEmpty && !premiumConfiguration.isPremiumDisabled {
items.tip = .animatedEmoji(text: nil, arguments: nil, file: nil, action: nil)

View file

@ -52,6 +52,13 @@ func canEditMessage(context: AccountContext, limitsConfiguration: EngineConfigur
return canEditMessage(accountPeerId: context.account.peerId, limitsConfiguration: limitsConfiguration, message: message)
}
func canDeleteOtherUserMessages(message: Message) -> Bool {
guard let channel = message.peers[message.id.peerId] as? TelegramChannel else {
return false
}
return channel.hasPermission(.deleteAllMessages)
}
private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: EngineConfiguration.Limits, message: Message, reschedule: Bool = false) -> Bool {
var hasEditRights = false
var unlimitedInterval = reschedule
@ -2173,24 +2180,9 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
displayReadTimestamps = true
}
c.pushItems(items: .single(ContextController.Items(content: .custom(ReactionListContextMenuContent(
context: context,
displayReadTimestamps: displayReadTimestamps,
availableReactions: availableReactions,
animationCache: controllerInteraction.presentationContext.animationCache,
animationRenderer: controllerInteraction.presentationContext.animationRenderer,
message: EngineMessage(message),
reaction: nil,
readStats: stats,
back: { [weak c] in
c?.popItems()
},
openPeer: { [weak c] peer, hasReaction in
c?.dismiss(completion: {
controllerInteraction.openPeer(peer, .default, MessageReference(message), hasReaction ? .reaction : .default)
})
},
deleteReaction: { [weak c] peer, _ in
let deleteReaction: ((EnginePeer, MessageReaction.Reaction) -> Void)?
if canDeleteOtherUserMessages(message: message) {
deleteReaction = { [weak c] peer, _ in
c?.dismiss(completion: {
guard let chatController = interfaceInteraction.chatController() as? ChatControllerImpl, chatController.chatLocation.peerId?.namespace == Namespaces.Peer.CloudChannel else {
return
@ -2209,11 +2201,34 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
accountPeerId: context.account.peerId,
author: peer._asPeer(),
messageIds: Set([message.id]),
options: actions.options
options: actions.options,
reaction: true
)
})
})
}
} else {
deleteReaction = nil
}
c.pushItems(items: .single(ContextController.Items(content: .custom(ReactionListContextMenuContent(
context: context,
displayReadTimestamps: displayReadTimestamps,
availableReactions: availableReactions,
animationCache: controllerInteraction.presentationContext.animationCache,
animationRenderer: controllerInteraction.presentationContext.animationRenderer,
message: EngineMessage(message),
reaction: nil,
readStats: stats,
back: { [weak c] in
c?.popItems()
},
openPeer: { [weak c] peer, hasReaction in
c?.dismiss(completion: {
controllerInteraction.openPeer(peer, .default, MessageReference(message), hasReaction ? .reaction : .default)
})
},
deleteReaction: deleteReaction
)), tip: tip)))
} else {
f(.default)