mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add text link editing
Auto-paste url from pasteboard if any
This commit is contained in:
parent
b4c706b9a1
commit
1e14a6c687
@ -36,6 +36,7 @@ swift_library(
|
|||||||
"//submodules/Components/AnimatedStickerComponent:AnimatedStickerComponent",
|
"//submodules/Components/AnimatedStickerComponent:AnimatedStickerComponent",
|
||||||
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
|
"//submodules/Components/MultilineTextComponent:MultilineTextComponent",
|
||||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||||
|
"//submodules/TextFormat:TextFormat",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -18,6 +18,7 @@ import SemanticStatusNode
|
|||||||
import MediaResources
|
import MediaResources
|
||||||
import MultilineTextComponent
|
import MultilineTextComponent
|
||||||
import ShimmerEffect
|
import ShimmerEffect
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
private let buttonSize = CGSize(width: 88.0, height: 49.0)
|
private let buttonSize = CGSize(width: 88.0, height: 49.0)
|
||||||
private let smallButtonWidth: CGFloat = 69.0
|
private let smallButtonWidth: CGFloat = 69.0
|
||||||
@ -885,20 +886,29 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}, openLinkEditing: { [weak self] in
|
}, openLinkEditing: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var selectionRange: Range<Int>?
|
var selectionRange: Range<Int>?
|
||||||
var text: String?
|
var text: NSAttributedString?
|
||||||
var inputMode: ChatInputMode?
|
var inputMode: ChatInputMode?
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
||||||
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||||
if let selectionRange = selectionRange {
|
if let selectionRange = selectionRange {
|
||||||
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count)).string
|
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||||
}
|
}
|
||||||
inputMode = state.inputMode
|
inputMode = state.inputMode
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var link: String?
|
||||||
|
if let text {
|
||||||
|
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||||
|
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||||
|
link = linkAttribute.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text ?? "", link: nil, apply: { [weak self] link in
|
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { [weak self] link in
|
||||||
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
||||||
if let link = link {
|
if let link = link {
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
||||||
|
@ -12,7 +12,7 @@ import UrlEscaping
|
|||||||
private final class ChatTextLinkEditInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegate {
|
private final class ChatTextLinkEditInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegate {
|
||||||
private var theme: PresentationTheme
|
private var theme: PresentationTheme
|
||||||
private let backgroundNode: ASImageNode
|
private let backgroundNode: ASImageNode
|
||||||
private let textInputNode: EditableTextNode
|
fileprivate let textInputNode: EditableTextNode
|
||||||
private let placeholderNode: ASTextNode
|
private let placeholderNode: ASTextNode
|
||||||
|
|
||||||
var updateHeight: (() -> Void)?
|
var updateHeight: (() -> Void)?
|
||||||
@ -238,6 +238,21 @@ private final class ChatTextLinkEditAlertContentNode: AlertContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.updateTheme(theme)
|
self.updateTheme(theme)
|
||||||
|
|
||||||
|
if (link ?? "").isEmpty {
|
||||||
|
Queue.mainQueue().after(0.1, {
|
||||||
|
let pasteboard = UIPasteboard.general
|
||||||
|
if pasteboard.hasURLs {
|
||||||
|
if let url = pasteboard.url?.absoluteString, !url.isEmpty {
|
||||||
|
self.inputFieldNode.text = url
|
||||||
|
if let lastNode = self.actionNodes.last {
|
||||||
|
lastNode.actionEnabled = true
|
||||||
|
}
|
||||||
|
self.inputFieldNode.textInputNode.textView.selectAll(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
@ -9777,18 +9777,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, openLinkEditing: { [weak self] in
|
}, openLinkEditing: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var selectionRange: Range<Int>?
|
var selectionRange: Range<Int>?
|
||||||
var text: String?
|
var text: NSAttributedString?
|
||||||
var inputMode: ChatInputMode?
|
var inputMode: ChatInputMode?
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
||||||
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||||
if let selectionRange = selectionRange {
|
if let selectionRange = selectionRange {
|
||||||
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count)).string
|
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||||
}
|
}
|
||||||
inputMode = state.inputMode
|
inputMode = state.inputMode
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, account: strongSelf.context.account, text: text ?? "", link: nil, apply: { [weak self] link in
|
var link: String?
|
||||||
|
if let text {
|
||||||
|
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||||
|
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||||
|
link = linkAttribute.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: strongSelf.updatedPresentationData, account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { [weak self] link in
|
||||||
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
||||||
if let link = link {
|
if let link = link {
|
||||||
strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||||
@ -12507,18 +12516,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}, openLinkEditing: { [weak self] in
|
}, openLinkEditing: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var selectionRange: Range<Int>?
|
var selectionRange: Range<Int>?
|
||||||
var text: String?
|
var text: NSAttributedString?
|
||||||
var inputMode: ChatInputMode?
|
var inputMode: ChatInputMode?
|
||||||
updateChatPresentationInterfaceStateImpl?({ state in
|
updateChatPresentationInterfaceStateImpl?({ state in
|
||||||
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||||
if let selectionRange = selectionRange {
|
if let selectionRange = selectionRange {
|
||||||
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count)).string
|
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||||
}
|
}
|
||||||
inputMode = state.inputMode
|
inputMode = state.inputMode
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text ?? "", link: nil, apply: { link in
|
var link: String?
|
||||||
|
if let text {
|
||||||
|
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||||
|
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||||
|
link = linkAttribute.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { link in
|
||||||
if let inputMode = inputMode, let selectionRange = selectionRange {
|
if let inputMode = inputMode, let selectionRange = selectionRange {
|
||||||
if let link = link {
|
if let link = link {
|
||||||
updateChatPresentationInterfaceStateImpl?({
|
updateChatPresentationInterfaceStateImpl?({
|
||||||
@ -16013,7 +16031,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.dismiss()
|
self.dismiss()
|
||||||
|
|
||||||
let navigateToLocation: NavigateToChatControllerParams.Location
|
let navigateToLocation: NavigateToChatControllerParams.Location
|
||||||
if let message = messages.first, let threadId = message.threadId, threadId != 1 || (message.peers[message.id.peerId] as? TelegramChannel)?.flags.contains(.isForum) == true {
|
if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
|
||||||
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
|
||||||
} else {
|
} else {
|
||||||
navigateToLocation = .peer(peer)
|
navigateToLocation = .peer(peer)
|
||||||
|
@ -22,6 +22,7 @@ import AnimatedStickerNode
|
|||||||
import TelegramAnimatedStickerNode
|
import TelegramAnimatedStickerNode
|
||||||
import SolidRoundedButtonNode
|
import SolidRoundedButtonNode
|
||||||
import ContextUI
|
import ContextUI
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
final class PeerSelectionControllerNode: ASDisplayNode {
|
final class PeerSelectionControllerNode: ASDisplayNode {
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
@ -611,19 +612,28 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}, openLinkEditing: { [weak self] in
|
}, openLinkEditing: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var selectionRange: Range<Int>?
|
var selectionRange: Range<Int>?
|
||||||
var text: String?
|
var text: NSAttributedString?
|
||||||
var inputMode: ChatInputMode?
|
var inputMode: ChatInputMode?
|
||||||
|
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
||||||
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||||
if let selectionRange = selectionRange {
|
if let selectionRange = selectionRange {
|
||||||
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count)).string
|
text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||||
}
|
}
|
||||||
inputMode = state.inputMode
|
inputMode = state.inputMode
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
|
|
||||||
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text ?? "", link: nil, apply: { [weak self] link in
|
var link: String?
|
||||||
|
if let text {
|
||||||
|
text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||||
|
if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||||
|
link = linkAttribute.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let controller = chatTextLinkEditController(sharedContext: strongSelf.context.sharedContext, updatedPresentationData: (presentationData, .never()), account: strongSelf.context.account, text: text?.string ?? "", link: link, apply: { [weak self] link in
|
||||||
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
if let strongSelf = self, let inputMode = inputMode, let selectionRange = selectionRange {
|
||||||
if let link = link {
|
if let link = link {
|
||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
strongSelf.updateChatPresentationInterfaceState(animated: true, { state in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user