Various FIxes

This commit is contained in:
Ilya Laktyushin 2021-03-14 20:57:13 +04:00
parent 58f5910af3
commit 18f5f3d0d3
21 changed files with 3817 additions and 3688 deletions

View File

@ -6269,6 +6269,7 @@ Sorry for the inconvenience.";
"Conversation.MessageCopied" = "Message copied to clipboard";
"Conversation.LinkCopied" = "Link copied to clipboard";
"Conversation.TextCopied" = "Text copied to clipboard";
"Conversation.ImageCopied" = "Image copied to clipboard";
"Conversation.HashtagCopied" = "Hashtag copied to clipboard";
"Conversation.PhoneCopied" = "Phone copied to clipboard";
"Conversation.EmailCopied" = "Email copied to clipboard";

View File

@ -683,33 +683,40 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
let context = self.context
let (peers, messages) = self.currentMessages
let items = context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: [message.id], messages: messages, peers: peers)
|> map { actions -> [ContextMenuItem] in
|> map { [weak self] actions -> [ContextMenuItem] in
guard let strongSelf = self else {
return []
}
var items: [ContextMenuItem] = []
if let linkForCopying = linkForCopying {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
c.dismiss(completion: {})
UIPasteboard.general.string = linkForCopying
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self?.present?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
})))
}
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
c.dismiss(completion: { [weak self] in
if let strongSelf = self {
strongSelf.forwardMessages(messageIds: Set([message.id]))
}
})
})))
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
c.dismiss(completion: { [weak self] in
self?.openMessage(message.peers[message.id.peerId]!, message.id, false)
})
})))
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
c.dismiss(completion: {
if let strongSelf = self {
strongSelf.dismissInput()

View File

@ -15,6 +15,7 @@ import TelegramUniversalVideoContent
import WebsiteType
import OpenInExternalAppUI
import ScreenCaptureDetection
import UndoUI
private func tagsForMessage(_ message: Message) -> MessageTags? {
for media in message.media {
@ -664,6 +665,7 @@ public class GalleryController: ViewController, StandalonePresentableController
openActionOptionsImpl = { [weak self] action in
if let strongSelf = self {
let presentationData = strongSelf.presentationData
switch action {
case let .url(url, _):
var cleanUrl = url
@ -673,14 +675,19 @@ public class GalleryController: ViewController, StandalonePresentableController
let telString = "tel:"
var openText = strongSelf.presentationData.strings.Conversation_LinkDialogOpen
var phoneNumber: String?
var isEmail = false
var isPhoneNumber = false
if cleanUrl.hasPrefix(mailtoString) {
canAddToReadingList = false
cleanUrl = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: mailtoString.distance(from: mailtoString.startIndex, to: mailtoString.endIndex))...])
isEmail = true
} else if cleanUrl.hasPrefix(telString) {
canAddToReadingList = false
phoneNumber = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: telString.distance(from: telString.startIndex, to: telString.endIndex))...])
cleanUrl = phoneNumber!
openText = strongSelf.presentationData.strings.UserInfo_PhoneCall
isPhoneNumber = true
} else if canOpenIn {
openText = strongSelf.presentationData.strings.Conversation_FileOpenIn
}
@ -708,9 +715,21 @@ public class GalleryController: ViewController, StandalonePresentableController
}
}))
}
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = cleanUrl
let content: UndoOverlayContent
if isPhoneNumber {
content = .copy(text: presentationData.strings.Conversation_PhoneCopied)
} else if isEmail {
content = .copy(text: presentationData.strings.Conversation_EmailCopied)
} else if canAddToReadingList {
content = .linkCopied(text: presentationData.strings.Conversation_LinkCopied)
} else {
content = .copy(text: presentationData.strings.Conversation_TextCopied)
}
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}))
if canAddToReadingList {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
@ -740,9 +759,12 @@ public class GalleryController: ViewController, StandalonePresentableController
}
}))
if !mention.isEmpty {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_UsernameCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
@ -762,9 +784,12 @@ public class GalleryController: ViewController, StandalonePresentableController
strongSelf.actionInteraction?.openPeerMention(mention)
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -776,9 +801,12 @@ public class GalleryController: ViewController, StandalonePresentableController
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData.withUpdated(theme: defaultDarkColorPresentationTheme))
var items: [ActionSheetItem] = []
items.append(ActionSheetTextItem(title: command))
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = command
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -797,9 +825,12 @@ public class GalleryController: ViewController, StandalonePresentableController
strongSelf.actionInteraction?.openHashtag(peerName, hashtag)
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = hashtag
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_HashtagCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -819,9 +850,12 @@ public class GalleryController: ViewController, StandalonePresentableController
strongSelf.galleryNode.pager.centralItemNode()?.processAction(.timecode(timecode))
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = text
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in

View File

@ -492,7 +492,7 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.addSubnode(toolbarNode)
self.toolbarNode = toolbarNode
if case let .animated(duration, curve) = transition {
toolbarNode.layer.animatePosition(from: CGPoint(x: 0.0, y: toolbarFrame.height / 2.0), to: CGPoint(), duration: duration, mediaTimingFunction: curve.mediaTimingFunction, additive: true)
toolbarNode.layer.animatePosition(from: CGPoint(x: 0.0, y: toolbarFrame.height), to: CGPoint(), duration: duration, mediaTimingFunction: curve.mediaTimingFunction, additive: true)
}
}
@ -516,7 +516,7 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else if let toolbarNode = self.toolbarNode {
self.toolbarNode = nil
if case let .animated(duration, curve) = transition {
toolbarNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: toolbarNode.frame.size.height / 2.0), duration: duration, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: false, additive: true, completion: { [weak toolbarNode] _ in
toolbarNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: toolbarNode.frame.size.height), duration: duration, mediaTimingFunction: curve.mediaTimingFunction, removeOnCompletion: false, additive: true, completion: { [weak toolbarNode] _ in
toolbarNode?.removeFromSupernode()
})
} else {

View File

@ -28,7 +28,6 @@ private final class ChannelVisibilityControllerArguments {
let updateCurrentType: (CurrentChannelType) -> Void
let updatePublicLinkText: (String?, String) -> Void
let scrollToPublicLinkText: () -> Void
let displayPrivateLinkMenu: (String) -> Void
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
let revokePeerId: (PeerId) -> Void
let copyLink: (ExportedInvitation) -> Void
@ -36,12 +35,11 @@ private final class ChannelVisibilityControllerArguments {
let linkContextAction: (ASDisplayNode, ContextGesture?) -> Void
let manageInviteLinks: () -> Void
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, displayPrivateLinkMenu: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void) {
init(context: AccountContext, updateCurrentType: @escaping (CurrentChannelType) -> Void, updatePublicLinkText: @escaping (String?, String) -> Void, scrollToPublicLinkText: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, revokePeerId: @escaping (PeerId) -> Void, copyLink: @escaping (ExportedInvitation) -> Void, shareLink: @escaping (ExportedInvitation) -> Void, linkContextAction: @escaping (ASDisplayNode, ContextGesture?) -> Void, manageInviteLinks: @escaping () -> Void) {
self.context = context
self.updateCurrentType = updateCurrentType
self.updatePublicLinkText = updatePublicLinkText
self.scrollToPublicLinkText = scrollToPublicLinkText
self.displayPrivateLinkMenu = displayPrivateLinkMenu
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
self.revokePeerId = revokePeerId
self.copyLink = copyLink
@ -831,7 +829,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
var dismissImpl: (() -> Void)?
var nextImpl: (() -> Void)?
var displayPrivateLinkMenuImpl: ((String) -> Void)?
var scrollToPublicLinkTextImpl: (() -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var pushControllerImpl: ((ViewController) -> Void)?
@ -883,8 +880,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
}
}, scrollToPublicLinkText: {
scrollToPublicLinkTextImpl?()
}, displayPrivateLinkMenu: { text in
displayPrivateLinkMenuImpl?(text)
}, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
updateState { state in
if (peerId == nil && fromPeerId == state.revealedRevokePeerId) || (peerId != nil && fromPeerId == nil) {
@ -1385,35 +1380,6 @@ public func channelVisibilityController(context: AccountContext, peerId: PeerId,
}
}
}
displayPrivateLinkMenuImpl = { [weak controller] text in
if let strongController = controller {
var resultItemNode: ListViewItemNode?
let _ = strongController.frameForItemNode({ itemNode in
if let itemNode = itemNode as? ItemListActionItemNode {
if let tag = itemNode.tag as? ChannelVisibilityEntryTag {
if tag == .privateLink {
resultItemNode = itemNode
return true
}
}
}
return false
})
if let resultItemNode = resultItemNode {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuCopyLink, accessibilityLabel: presentationData.strings.Conversation_ContextMenuCopyLink), action: {
UIPasteboard.general.string = text
})])
strongController.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak resultItemNode] in
if let strongController = controller, let resultItemNode = resultItemNode {
return (resultItemNode, resultItemNode.contentBounds.insetBy(dx: 0.0, dy: -2.0), strongController.displayNode, strongController.view.bounds)
} else {
return nil
}
}))
}
}
}
scrollToPublicLinkTextImpl = { [weak controller] in
DispatchQueue.main.async {
if let strongController = controller {

View File

@ -21,6 +21,7 @@ import Geocoding
import ItemListAddressItem
import LocalizedPeerData
import PhoneNumberFormat
import UndoUI
private enum DeviceContactInfoAction {
case sendMessage
@ -395,31 +396,31 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! DeviceContactInfoControllerArguments
switch self {
case let .info(_, theme, strings, dateTimeFormat, peer, state, jobSummary, isPlain):
case let .info(_, _, strings, dateTimeFormat, peer, state, jobSummary, isPlain):
return ItemListAvatarAndNameInfoItem(accountContext: arguments.context, presentationData: presentationData, dateTimeFormat: dateTimeFormat, mode: .contact, peer: peer, presence: nil, label: jobSummary, cachedData: nil, state: state, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks(withTopInset: false, withExtendedBottomInset: true), editingNameUpdated: { editingName in
arguments.updateEditingName(editingName)
}, avatarTapped: {
}, context: nil, call: nil)
case let .sendMessage(_, theme, title):
case let .sendMessage(_, _, title):
return ItemListActionItem(presentationData: presentationData, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, action: {
arguments.performAction(.sendMessage)
})
case let .invite(_, theme, title):
case let .invite(_, _, title):
return ItemListActionItem(presentationData: presentationData, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, action: {
arguments.performAction(.invite)
})
case let .createContact(_, theme, title):
case let .createContact(_, _, title):
return ItemListActionItem(presentationData: presentationData, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, action: {
arguments.performAction(.createContact)
})
case let .addToExisting(_, theme, title):
case let .addToExisting(_, _, title):
return ItemListActionItem(presentationData: presentationData, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, action: {
arguments.performAction(.addToExisting)
})
case let .company(_, theme, title, value, selected):
case let .company(_, _, title, value, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: value, style: arguments.isPlain ? .plain : .blocks, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
}, tag: nil)
case let .phoneNumber(_, index, theme, title, label, value, selected, isInteractionEnabled):
case let .phoneNumber(_, index, _, title, label, value, selected, isInteractionEnabled):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: value, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: false, selected: selected, sectionId: self.section, action: isInteractionEnabled ? {
if selected != nil {
arguments.toggleSelection(.phoneNumber(label, value))
@ -431,15 +432,15 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), value)
}
} : nil, tag: DeviceContactInfoEntryTag.info(index))
case let .phoneNumberSharingInfo(_, theme, text):
case let .phoneNumberSharingInfo(_, _, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
case let .phoneNumberShareViaException(_, theme, text, value):
case let .phoneNumberShareViaException(_, _, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: arguments.isPlain ? .plain : .blocks, updated: { value in
arguments.updateShareViaException(value)
})
case let .phoneNumberShareViaExceptionInfo(_, theme, text):
case let .phoneNumberShareViaExceptionInfo(_, _, text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
case let .editingPhoneNumber(_, theme, strings, id, title, label, value, hasActiveRevealControls):
case let .editingPhoneNumber(_, _, strings, id, title, label, value, hasActiveRevealControls):
return UserInfoEditingPhoneItem(presentationData: presentationData, id: id, label: title, value: value, editing: UserInfoEditingPhoneItemEditing(editable: true, hasActiveRevealControls: hasActiveRevealControls), sectionId: self.section, setPhoneIdWithRevealedOptions: { lhs, rhs in
arguments.setPhoneIdWithRevealedOptions(lhs, rhs)
}, updated: { value in
@ -449,11 +450,11 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
}, delete: {
arguments.deletePhone(id)
}, tag: DeviceContactInfoEntryTag.editingPhone(id))
case let .addPhoneNumber(_, theme, title):
case let .addPhoneNumber(_, _, title):
return UserInfoEditingPhoneActionItem(presentationData: presentationData, title: title, sectionId: self.section, action: {
arguments.addPhoneNumber()
})
case let .email(_, index, theme, title, label, value, selected):
case let .email(_, index, _, title, label, value, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: value, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: false, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.email(label, value))
@ -465,7 +466,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), value)
}
}, tag: DeviceContactInfoEntryTag.info(index))
case let .url(_, index, theme, title, label, value, selected):
case let .url(_, index, _, title, label, value, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: value, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: false, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.url(label, value))
@ -504,7 +505,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), string)
}
}, tag: DeviceContactInfoEntryTag.info(index))
case let .birthday(_, theme, title, value, text, selected):
case let .birthday(_, _, title, value, text, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: text, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.birthday)
@ -533,7 +534,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.birthday, text)
}
}, tag: DeviceContactInfoEntryTag.birthday)
case let .socialProfile(_, index, theme, title, value, text, selected):
case let .socialProfile(_, index, _, title, value, text, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: text, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.socialProfile(value))
@ -545,7 +546,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), text)
}
}, tag: DeviceContactInfoEntryTag.info(index))
case let .instantMessenger(_, index, theme, title, value, text, selected):
case let .instantMessenger(_, index, _, title, value, text, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: text, style: arguments.isPlain ? .plain : .blocks, textColor: .accent, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.instantMessenger(value))
@ -555,7 +556,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry {
arguments.displayCopyContextMenu(.info(index), text)
}
}, tag: DeviceContactInfoEntryTag.info(index))
case let .note(_, theme, title, text, selected):
case let .note(_, _, title, text, selected):
return ItemListTextWithLabelItem(presentationData: presentationData, label: title, text: text, style: arguments.isPlain ? .plain : .blocks, enabledEntityTypes: [], multiline: true, selected: selected, sectionId: self.section, action: {
if selected != nil {
arguments.toggleSelection(.note)
@ -1298,6 +1299,9 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
if let resultItemNode = resultItemNode {
let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: presentationData.strings.Conversation_ContextMenuCopy), action: {
UIPasteboard.general.string = value
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
})])
strongController.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak resultItemNode] in
if let strongController = controller, let resultItemNode = resultItemNode {
@ -1306,7 +1310,6 @@ public func deviceContactInfoController(context: AccountContext, subject: Device
return nil
}
}))
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1517,6 +1517,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}, longTap: { [weak self] action, message in
if let strongSelf = self {
let presentationData = strongSelf.presentationData
switch action {
case let .url(url):
var (cleanUrl, _) = parseUrl(url: url, wasConcealed: false)
@ -1526,15 +1527,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let telString = "tel:"
var openText = strongSelf.presentationData.strings.Conversation_LinkDialogOpen
var phoneNumber: String?
var isPhoneNumber = false
var isEmail = false
if cleanUrl.hasPrefix(mailtoString) {
canAddToReadingList = false
cleanUrl = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: mailtoString.distance(from: mailtoString.startIndex, to: mailtoString.endIndex))...])
isEmail = true
} else if cleanUrl.hasPrefix(telString) {
canAddToReadingList = false
phoneNumber = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: telString.distance(from: telString.startIndex, to: telString.endIndex))...])
cleanUrl = phoneNumber!
openText = strongSelf.presentationData.strings.UserInfo_PhoneCall
canOpenIn = false
isPhoneNumber = true
} else if canOpenIn {
openText = strongSelf.presentationData.strings.Conversation_FileOpenIn
}
@ -1560,9 +1567,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}))
}
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = cleanUrl
let content: UndoOverlayContent
if isPhoneNumber {
content = .copy(text: presentationData.strings.Conversation_PhoneCopied)
} else if isEmail {
content = .copy(text: presentationData.strings.Conversation_EmailCopied)
} else if canAddToReadingList {
content = .linkCopied(text: presentationData.strings.Conversation_LinkCopied)
} else {
content = .copy(text: presentationData.strings.Conversation_TextCopied)
}
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}))
if canAddToReadingList {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
@ -1595,6 +1614,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_UsernameCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
@ -1616,7 +1638,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -1640,6 +1665,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = command
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -1670,6 +1698,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = hashtag
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_HashtagCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -1694,6 +1725,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = text
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -1759,6 +1793,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = number
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_CardNumberCopied)
self?.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}))
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
@ -2523,7 +2560,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
storeMessageTextInPasteboard(text, entities: nil)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
return true
}), in: .current)
}
}, displayUndo: { [weak self] content in
if let strongSelf = self {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in
return true
}), in: .current)
}

View File

@ -11,6 +11,7 @@ import TextSelectionNode
import ReactionSelectionNode
import ContextUI
import ChatInterfaceState
import UndoUI
struct ChatInterfaceHighlightedState: Equatable {
let messageStableId: UInt32
@ -119,6 +120,7 @@ public final class ChatControllerInteraction {
let openMessageStats: (MessageId) -> Void
let editMessageMedia: (MessageId, Bool) -> Void
let copyText: (String) -> Void
let displayUndo: (UndoOverlayContent) -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -167,7 +169,7 @@ public final class ChatControllerInteraction {
updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void,
updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void,
openMessageShareMenu: @escaping (MessageId) -> Void,
presentController: @escaping (ViewController, Any?) -> Void,
presentController: @escaping (ViewController, Any?) -> Void,
navigationController: @escaping () -> NavigationController?,
chatControllerNode: @escaping () -> ASDisplayNode?,
reactionContainerNode: @escaping () -> ReactionSelectionParentNode?,
@ -209,6 +211,7 @@ public final class ChatControllerInteraction {
openMessageStats: @escaping (MessageId) -> Void,
editMessageMedia: @escaping (MessageId, Bool) -> Void,
copyText: @escaping (String) -> Void,
displayUndo: @escaping (UndoOverlayContent) -> Void,
requestMessageUpdate: @escaping (MessageId) -> Void,
cancelInteractiveKeyboardGestures: @escaping () -> Void,
automaticMediaDownloadSettings: MediaAutoDownloadSettings,
@ -286,7 +289,7 @@ public final class ChatControllerInteraction {
self.openMessageStats = openMessageStats
self.editMessageMedia = editMessageMedia
self.copyText = copyText
self.displayUndo = displayUndo
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -340,6 +343,7 @@ public final class ChatControllerInteraction {
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -837,8 +837,8 @@ final class ChatEmptyNode: ASDisplayNode {
contentType = .group
} else if let _ = interfaceState.peerNearbyData {
contentType = .peerNearby
} else if let _ = peer as? TelegramUser {
if peer.isDeleted {
} else if let peer = peer as? TelegramUser {
if peer.isDeleted || peer.botInfo != nil || peer.flags.contains(.isSupport) {
contentType = .regular
} else if case .clearedHistory = emptyType {
contentType = .regular

View File

@ -561,6 +561,9 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
storeMessageTextInPasteboard(message.text, entities: messageEntities)
let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied)
controllerInteraction.displayUndo(content)
}
if resourceAvailable {
for media in message.media {
@ -574,6 +577,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
copyTextWithEntities()
} else {
UIPasteboard.general.image = image
let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_ImageCopied)
controllerInteraction.displayUndo(content)
}
} else {
copyTextWithEntities()

View File

@ -181,8 +181,8 @@ final class ChatRecentActionsController: TelegramBaseController {
override func loadDisplayNode() {
self.displayNode = ChatRecentActionsControllerNode(context: self.context, peer: self.peer, presentationData: self.presentationData, interaction: self.interaction, pushController: { [weak self] c in
(self?.navigationController as? NavigationController)?.pushViewController(c)
}, presentController: { [weak self] c, a in
self?.present(c, in: .window(.root), with: a, blockInteraction: true)
}, presentController: { [weak self] c, t, a in
self?.present(c, in: t, with: a, blockInteraction: true)
}, getNavigationController: { [weak self] in
return self?.navigationController as? NavigationController
})

View File

@ -40,7 +40,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
private var presentationData: PresentationData
private let pushController: (ViewController) -> Void
private let presentController: (ViewController, Any?) -> Void
private let presentController: (ViewController, PresentationContextType, Any?) -> Void
private let getNavigationController: () -> NavigationController?
private let interaction: ChatRecentActionsInteraction
@ -87,7 +87,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
private var adminsState: ChannelMemberListState?
private let banDisposables = DisposableDict<PeerId>()
init(context: AccountContext, peer: Peer, presentationData: PresentationData, interaction: ChatRecentActionsInteraction, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) {
init(context: AccountContext, peer: Peer, presentationData: PresentationData, interaction: ChatRecentActionsInteraction, pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController, PresentationContextType, Any?) -> Void, getNavigationController: @escaping () -> NavigationController?) {
self.context = context
self.peer = peer
self.presentationData = presentationData
@ -154,7 +154,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
switch entry.entry.event.action {
case let .changeStickerPack(_, new):
if let new = new {
strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: new, stickerPacks: [new], parentNavigationController: strongSelf.getNavigationController()), nil)
strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: new, stickerPacks: [new], parentNavigationController: strongSelf.getNavigationController()), .window(.root), nil)
return true
}
case let .editExportedInvitation(_, invite), let .revokeExportedInvitation(invite), let .deleteExportedInvitation(invite), let .participantJoinedViaInvite(invite):
@ -179,7 +179,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
} else {
let controller = inviteLinkEditController(context: strongSelf.context, peerId: peer.id, invite: invite, completion: { [weak self] _ in
self?.eventLogContext.reload()
@ -205,7 +205,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
return context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: nil, chatLocationContextHolder: nil, message: message, standalone: true, reverseMessageGalleryOrder: false, navigationController: navigationController, dismissInput: {
//self?.chatDisplayNode.dismissInput()
}, present: { c, a in
self?.presentController(c, a)
self?.presentController(c, .window(.root), a)
}, transitionNode: { messageId, media in
var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
if let strongSelf = self {
@ -271,7 +271,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openWallpaper: { [weak self] message in
if let strongSelf = self{
openChatWallpaper(context: strongSelf.context, message: message, present: { [weak self] c, a in
self?.presentController(c, a)
self?.presentController(c, .window(.root), a)
})
}
}, openTheme: { _ in
@ -319,13 +319,18 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
let mailtoString = "mailto:"
let telString = "tel:"
var openText = strongSelf.presentationData.strings.Conversation_LinkDialogOpen
var isEmail = false
var isPhoneNumber = false
if cleanUrl.hasPrefix(mailtoString) {
canAddToReadingList = false
cleanUrl = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: mailtoString.distance(from: mailtoString.startIndex, to: mailtoString.endIndex))...])
isEmail = true
} else if cleanUrl.hasPrefix(telString) {
canAddToReadingList = false
cleanUrl = String(cleanUrl[cleanUrl.index(cleanUrl.startIndex, offsetBy: telString.distance(from: telString.startIndex, to: telString.endIndex))...])
openText = strongSelf.presentationData.strings.Conversation_Call
isPhoneNumber = true
} else if canOpenIn {
openText = strongSelf.presentationData.strings.Conversation_FileOpenIn
}
@ -339,9 +344,21 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.openUrl(url)
}
}))
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: canAddToReadingList ? strongSelf.presentationData.strings.ShareMenu_CopyShareLink : strongSelf.presentationData.strings.Conversation_ContextMenuCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = cleanUrl
let content: UndoOverlayContent
if isPhoneNumber {
content = .copy(text: presentationData.strings.Conversation_PhoneCopied)
} else if isEmail {
content = .copy(text: presentationData.strings.Conversation_EmailCopied)
} else if canAddToReadingList {
content = .linkCopied(text: presentationData.strings.Conversation_LinkCopied)
} else {
content = .copy(text: presentationData.strings.Conversation_TextCopied)
}
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
}))
if canAddToReadingList {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
@ -356,7 +373,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case let .peerMention(peerId, mention):
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = []
@ -370,9 +387,12 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}
}))
if !mention.isEmpty {
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_UsernameCopied)
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
}))
}
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
@ -380,7 +400,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case let .mention(mention):
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
@ -391,30 +411,36 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.openPeerMention(mention)
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = mention
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case let .command(command):
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
ActionSheetTextItem(title: command),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = command
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case let .hashtag(hashtag):
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
@ -426,16 +452,19 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.pushController(searchController)
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = hashtag
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_HashtagCopied)
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case let .timecode(timecode, text):
guard let message = message else {
return
@ -449,16 +478,19 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.controllerInteraction?.seekToTimecode(message, timecode, true)
}
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet, weak self] in
actionSheet?.dismissAnimated()
UIPasteboard.general.string = text
let content: UndoOverlayContent = .copy(text: presentationData.strings.Conversation_TextCopied)
self?.presentController(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
})
]), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
})
])])
strongSelf.presentController(actionSheet, nil)
strongSelf.presentController(actionSheet, .window(.root), nil)
case .bankCard:
break
}
@ -503,6 +535,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
@ -802,7 +835,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
strongSelf.banDisposables.set((fetchChannelParticipant(account: strongSelf.context.account, peerId: strongSelf.peer.id, participantId: author.id)
|> deliverOnMainQueue).start(next: { participant in
if let strongSelf = self {
strongSelf.presentController(channelBannedMemberController(context: strongSelf.context, peerId: strongSelf.peer.id, memberId: author.id, initialParticipant: participant, updated: { _ in }, upgradedToSupergroup: { _, f in f() }), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
strongSelf.presentController(channelBannedMemberController(context: strongSelf.context, peerId: strongSelf.peer.id, memberId: author.id, initialParticipant: participant, updated: { _ in }, upgradedToSupergroup: { _, f in f() }), .window(.root), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}), forKey: author.id)
}
@ -825,7 +858,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}
}
self.presentController(contextMenuController, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak node] in
self.presentController(contextMenuController, .window(.root), ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak node] in
if let strongSelf = self, let node = node {
return (node, frame, strongSelf, strongSelf.bounds)
} else {
@ -875,7 +908,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}
case let .stickerPack(name):
let packReference: StickerPackReference = .name(name)
strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: strongSelf.getNavigationController()), nil)
strongSelf.presentController(StickerPackScreen(context: strongSelf.context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: strongSelf.getNavigationController()), .window(.root), nil)
case let .instantView(webpage, anchor):
strongSelf.pushController(InstantPageController(context: strongSelf.context, webPage: webpage, sourcePeerType: .channel, anchor: anchor))
case let .join(link):
@ -883,9 +916,9 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
if let strongSelf = self {
strongSelf.openPeer(peerId: peerId, peer: nil, peekData: peekData)
}
}, parentNavigationController: strongSelf.getNavigationController()), nil)
}, parentNavigationController: strongSelf.getNavigationController()), .window(.root), nil)
case let .localization(identifier):
strongSelf.presentController(LanguageLinkPreviewController(context: strongSelf.context, identifier: identifier), nil)
strongSelf.presentController(LanguageLinkPreviewController(context: strongSelf.context, identifier: identifier), .window(.root), nil)
case .proxy, .confirmationCode, .cancelAccountReset, .share:
strongSelf.context.sharedContext.openResolvedUrl(result, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.getNavigationController(), openPeer: { peerId, _ in
if let strongSelf = self {
@ -896,7 +929,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
requestMessageActionUrlAuth: nil,
joinVoiceChat: nil,
present: { c, a in
self?.presentController(c, a)
self?.presentController(c, .window(.root), a)
}, dismissInput: {
self?.view.endEditing(true)
}, contentContext: nil)
@ -913,7 +946,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
case let .joinVoiceChat(peerId, invite):
strongSelf.presentController(VoiceChatJoinScreen(context: strongSelf.context, peerId: peerId, invite: invite, join: { call in
}), nil)
}), .window(.root), nil)
}
}
}))
@ -937,7 +970,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
text = strongSelf.presentationData.strings.Conversation_AutoremoveOff
}
if let text = text {
strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), nil)
strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), .current, nil)
}
}
})

View File

@ -152,6 +152,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -144,6 +144,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -2153,6 +2153,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
@ -2737,14 +2738,24 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
var actions: [ContextMenuAction] = []
if copyPhone, let phone = user.phone, !phone.isEmpty {
actions.append(ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Settings_CopyPhoneNumber, accessibilityLabel: strongSelf.presentationData.strings.Settings_CopyPhoneNumber), action: {
actions.append(ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Settings_CopyPhoneNumber, accessibilityLabel: strongSelf.presentationData.strings.Settings_CopyPhoneNumber), action: { [weak self] in
UIPasteboard.general.string = formatPhoneNumber(phone)
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_PhoneCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}
}))
}
if copyUsername, let username = user.username, !username.isEmpty {
actions.append(ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Settings_CopyUsername, accessibilityLabel: strongSelf.presentationData.strings.Settings_CopyUsername), action: {
actions.append(ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Settings_CopyUsername, accessibilityLabel: strongSelf.presentationData.strings.Settings_CopyUsername), action: { [weak self] in
UIPasteboard.general.string = username
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_UsernameCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
}
}))
}

View File

@ -1269,6 +1269,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, openMessageStats: { _ in
}, editMessageMedia: { _, _ in
}, copyText: { _ in
}, displayUndo: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -36,6 +36,7 @@ public enum UndoOverlayContent {
case voiceChatFlag(text: String)
case voiceChatCanSpeak(text: String)
case sticker(account: Account, file: TelegramMediaFile, text: String)
case copy(text: String)
}
public enum UndoOverlayAction {

View File

@ -674,6 +674,21 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 80, height: 80, mode: .cached)
}
}
case let .copy(text):
self.avatarNode = nil
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_copy", colors: [:], scale: 0.066)
self.animatedStickerNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .natural)
self.textNode.attributedText = attributedText
self.textNode.maximumNumberOfLines = 2
displayUndo = false
self.originalRemainingSeconds = 3
}
self.remainingSeconds = self.originalRemainingSeconds
@ -702,7 +717,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch content {
case .removedChat:
self.panelWrapperNode.addSubnode(self.timerTextNode)
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker:
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy:
break
case .dice:
self.panelWrapperNode.clipsToBounds = true