Keep mention panel if mentioning with long press

Closes #103

Co-Authored-By: kukuruzka <60149954+kukuruzka165@users.noreply.github.com>
This commit is contained in:
Kylmakalle 2025-03-14 00:12:34 +02:00
parent 4673545a86
commit fe45202bcd
2 changed files with 43 additions and 12 deletions

View File

@ -32,7 +32,7 @@ private struct MentionChatInputContextPanelEntry: Comparable, Identifiable {
return lhs.index < rhs.index return lhs.index < rhs.index
} }
func item(context: AccountContext, presentationData: PresentationData, inverted: Bool, setPeerIdRevealed: @escaping (EnginePeer.Id?) -> Void, peerSelected: @escaping (EnginePeer) -> Void, removeRequested: @escaping (EnginePeer.Id) -> Void) -> ListViewItem { func item(context: AccountContext, presentationData: PresentationData, inverted: Bool, setPeerIdRevealed: @escaping (EnginePeer.Id?) -> Void, peerSelected: @escaping (EnginePeer, Bool) -> Void, removeRequested: @escaping (EnginePeer.Id) -> Void) -> ListViewItem {
return MentionChatInputPanelItem(context: context, presentationData: ItemListPresentationData(presentationData), inverted: inverted, peer: self.peer._asPeer(), revealed: self.revealed, setPeerIdRevealed: setPeerIdRevealed, peerSelected: peerSelected, removeRequested: removeRequested) return MentionChatInputPanelItem(context: context, presentationData: ItemListPresentationData(presentationData), inverted: inverted, peer: self.peer._asPeer(), revealed: self.revealed, setPeerIdRevealed: setPeerIdRevealed, peerSelected: peerSelected, removeRequested: removeRequested)
} }
} }
@ -43,7 +43,7 @@ private struct CommandChatInputContextPanelTransition {
let updates: [ListViewUpdateItem] let updates: [ListViewUpdateItem]
} }
private func preparedTransition(from fromEntries: [MentionChatInputContextPanelEntry], to toEntries: [MentionChatInputContextPanelEntry], context: AccountContext, presentationData: PresentationData, inverted: Bool, forceUpdate: Bool, setPeerIdRevealed: @escaping (EnginePeer.Id?) -> Void, peerSelected: @escaping (EnginePeer) -> Void, removeRequested: @escaping (EnginePeer.Id) -> Void) -> CommandChatInputContextPanelTransition { private func preparedTransition(from fromEntries: [MentionChatInputContextPanelEntry], to toEntries: [MentionChatInputContextPanelEntry], context: AccountContext, presentationData: PresentationData, inverted: Bool, forceUpdate: Bool, setPeerIdRevealed: @escaping (EnginePeer.Id?) -> Void, peerSelected: @escaping (EnginePeer, Bool) -> Void, removeRequested: @escaping (EnginePeer.Id) -> Void) -> CommandChatInputContextPanelTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries, allUpdated: forceUpdate) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries, allUpdated: forceUpdate)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
@ -121,7 +121,7 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
strongSelf.revealedPeerId = peerId strongSelf.revealedPeerId = peerId
strongSelf.updateResults(strongSelf.currentResults) strongSelf.updateResults(strongSelf.currentResults)
} }
}, peerSelected: { [weak self] peer in }, peerSelected: { [weak self] peer, mentionNext in
if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction { if let strongSelf = self, let interfaceInteraction = strongSelf.interfaceInteraction {
switch strongSelf.mode { switch strongSelf.mode {
case .input: case .input:
@ -138,7 +138,8 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
let inputText = NSMutableAttributedString(attributedString: textInputState.inputText) let inputText = NSMutableAttributedString(attributedString: textInputState.inputText)
if let addressName = peer.addressName, !addressName.isEmpty { if let addressName = peer.addressName, !addressName.isEmpty {
let replacementText = addressName + " " // MARK: Swiftgram
let replacementText = addressName + (mentionNext ? " @" : " ")
inputText.replaceCharacters(in: range, with: replacementText) inputText.replaceCharacters(in: range, with: replacementText)
@ -148,7 +149,8 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
} else if !peer.compactDisplayTitle.isEmpty { } else if !peer.compactDisplayTitle.isEmpty {
let replacementText = NSMutableAttributedString() let replacementText = NSMutableAttributedString()
replacementText.append(NSAttributedString(string: peer.compactDisplayTitle, attributes: [ChatTextInputAttributes.textMention: ChatTextInputTextMentionAttribute(peerId: peer.id)])) replacementText.append(NSAttributedString(string: peer.compactDisplayTitle, attributes: [ChatTextInputAttributes.textMention: ChatTextInputTextMentionAttribute(peerId: peer.id)]))
replacementText.append(NSAttributedString(string: " ")) // MARK: Swiftgram
replacementText.append(NSAttributedString(string: mentionNext ? " @" : " "))
let updatedRange = NSRange(location: range.location - 1, length: range.length + 1) let updatedRange = NSRange(location: range.location - 1, length: range.length + 1)

View File

@ -17,13 +17,13 @@ final class MentionChatInputPanelItem: ListViewItem {
fileprivate let revealed: Bool fileprivate let revealed: Bool
fileprivate let inverted: Bool fileprivate let inverted: Bool
fileprivate let peer: Peer fileprivate let peer: Peer
private let peerSelected: (EnginePeer) -> Void let peerSelected: (EnginePeer, Bool) -> Void
fileprivate let setPeerIdRevealed: (EnginePeer.Id?) -> Void fileprivate let setPeerIdRevealed: (EnginePeer.Id?) -> Void
fileprivate let removeRequested: (EnginePeer.Id) -> Void fileprivate let removeRequested: (EnginePeer.Id) -> Void
let selectable: Bool = true let selectable: Bool = true
public init(context: AccountContext, presentationData: ItemListPresentationData, inverted: Bool, peer: Peer, revealed: Bool, setPeerIdRevealed: @escaping (PeerId?) -> Void, peerSelected: @escaping (EnginePeer) -> Void, removeRequested: @escaping (PeerId) -> Void) { public init(context: AccountContext, presentationData: ItemListPresentationData, inverted: Bool, peer: Peer, revealed: Bool, setPeerIdRevealed: @escaping (PeerId?) -> Void, peerSelected: @escaping (EnginePeer, Bool) -> Void, removeRequested: @escaping (PeerId) -> Void) {
self.context = context self.context = context
self.presentationData = presentationData self.presentationData = presentationData
self.inverted = inverted self.inverted = inverted
@ -85,14 +85,14 @@ final class MentionChatInputPanelItem: ListViewItem {
if self.revealed { if self.revealed {
self.setPeerIdRevealed(nil) self.setPeerIdRevealed(nil)
} else { } else {
self.peerSelected(EnginePeer(self.peer)) self.peerSelected(EnginePeer(self.peer), false)
} }
} }
} }
private let avatarFont = avatarPlaceholderFont(size: 16.0) private let avatarFont = avatarPlaceholderFont(size: 16.0)
final class MentionChatInputPanelItemNode: ListViewItemNode { final class MentionChatInputPanelItemNode: ListViewItemNode, UIGestureRecognizerDelegate {
static let itemHeight: CGFloat = 42.0 static let itemHeight: CGFloat = 42.0
private let avatarNode: AvatarNode private let avatarNode: AvatarNode
@ -147,7 +147,16 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
let recognizer = ItemListRevealOptionsGestureRecognizer(target: self, action: #selector(self.revealGesture(_:))) let recognizer = ItemListRevealOptionsGestureRecognizer(target: self, action: #selector(self.revealGesture(_:)))
self.recognizer = recognizer self.recognizer = recognizer
recognizer.allowAnyDirection = false recognizer.allowAnyDirection = false
// MARK: Swiftgram
recognizer.delegate = self
//
self.view.addGestureRecognizer(recognizer) self.view.addGestureRecognizer(recognizer)
// MARK: Swiftgram
let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressed(_:)))
longPressRecognizer.minimumPressDuration = 0.3
longPressRecognizer.delegate = self
self.view.addGestureRecognizer(longPressRecognizer)
} }
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) { override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
@ -328,11 +337,13 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
} }
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if let recognizer = self.recognizer, otherGestureRecognizer == recognizer { if gestureRecognizer is ItemListRevealOptionsGestureRecognizer && otherGestureRecognizer is UILongPressGestureRecognizer {
return true return true
} else {
return false
} }
if gestureRecognizer is UILongPressGestureRecognizer && otherGestureRecognizer is ItemListRevealOptionsGestureRecognizer {
return true
}
return false
} }
@objc func revealGesture(_ recognizer: ItemListRevealOptionsGestureRecognizer) { @objc func revealGesture(_ recognizer: ItemListRevealOptionsGestureRecognizer) {
@ -473,3 +484,21 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
self.hapticFeedback?.impact(.medium) self.hapticFeedback?.impact(.medium)
} }
} }
// MARK: Swiftgram
extension MentionChatInputPanelItemNode {
@objc private func longPressed(_ gestureRecognizer: UILongPressGestureRecognizer) {
switch gestureRecognizer.state {
case .began:
if let item = self.item {
item.peerSelected(EnginePeer(item.peer), true)
}
default:
break
}
}
}