Merge commit '7015c76e74c0fdac2597079b860f66fd1c6b14ab'

This commit is contained in:
Ali 2022-10-01 00:08:14 +02:00
commit 399b679532
14 changed files with 397 additions and 85 deletions

View File

@ -2590,6 +2590,7 @@ Unused sets are archived when you add more.";
"Conversation.HoldForVideo" = "Hold to record video. Tap to switch to audio.";
"UserInfo.TelegramCall" = "Telegram Call";
"UserInfo.TelegramVideoCall" = "Telegram Video Call";
"UserInfo.PhoneCall" = "Phone Call";
"SharedMedia.CategoryMedia" = "Media";

View File

@ -649,7 +649,6 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
iconNode.isLayerBacked = true
iconNode.displaysAsynchronously = false
iconNode.displayWithoutProcessing = true
strongSelf.containerNode.addSubnode(iconNode)
strongSelf.credibilityIconNode = iconNode
}
iconNode.image = currentCredibilityIconImage
@ -780,7 +779,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
transition.updateFrameAdditive(node: self.dateNode, frame: CGRect(origin: CGPoint(x: editingOffset + revealOffset + self.bounds.size.width - dateRightInset - self.dateNode.bounds.size.width, y: self.dateNode.frame.minY), size: self.dateNode.bounds.size))
transition.updateFrameAdditive(node: self.typeIconNode, frame: CGRect(origin: CGPoint(x: revealOffset + leftInset - 81.0, y: self.typeIconNode.frame.minY), size: self.typeIconNode.bounds.size))
transition.updateFrameAdditive(node: self.infoButtonNode, frame: CGRect(origin: CGPoint(x: revealOffset + self.bounds.size.width - infoIconRightInset - self.infoButtonNode.bounds.width, y: self.infoButtonNode.frame.minY), size: self.infoButtonNode.bounds.size))
}
}

View File

@ -499,7 +499,7 @@ private final class CallListTabBarContextExtractedContentSource: ContextExtracte
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode

View File

@ -3813,7 +3813,7 @@ private final class ChatListTabBarContextExtractedContentSource: ContextExtracte
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ChatListController
private let sourceNode: ContextExtractedContentContainingNode

View File

@ -686,7 +686,7 @@ private final class ContactsTabBarContextExtractedContentSource: ContextExtracte
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode

View File

@ -965,6 +965,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
}
private var delayLayoutUpdate = false
func animateOut(result initialResult: ContextMenuActionResult, completion: @escaping () -> Void) {
self.isUserInteractionEnabled = false
@ -973,11 +974,15 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
if let _ = self.presentationNode {
self.currentPresentationStateTransition = .animateOut(result: initialResult, completion: completion)
if let validLayout = self.validLayout {
self.updateLayout(
layout: validLayout,
transition: .animated(duration: 0.35, curve: .easeInOut),
previousActionsContainerNode: nil
)
self.delayLayoutUpdate = true
Queue.mainQueue().after(0.05) {
self.delayLayoutUpdate = false
self.updateLayout(
layout: validLayout,
transition: .animated(duration: 0.35, curve: .easeInOut),
previousActionsContainerNode: nil
)
}
}
return
}
@ -1520,7 +1525,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition, previousActionsContainerNode: ContextActionsContainerNode?, previousActionsContainerFrame: CGRect? = nil, previousActionsTransition: ContextController.PreviousActionsTransition = .scale) {
if self.isAnimatingOut {
if self.isAnimatingOut || self.delayLayoutUpdate {
return
}
@ -2220,14 +2225,22 @@ public final class ContextControllerPutBackViewInfo {
}
}
public enum ContextActionsHorizontalAlignment {
case `default`
case left
case center
case right
}
public protocol ContextExtractedContentSource: AnyObject {
var centerVertically: Bool { get }
var keepInPlace: Bool { get }
var ignoreContentTouches: Bool { get }
var blurBackground: Bool { get }
var centerActionsHorizontally: Bool { get }
var shouldBeDismissed: Signal<Bool, NoError> { get }
var actionsHorizontalAlignment: ContextActionsHorizontalAlignment { get }
func takeView() -> ContextControllerTakeViewInfo?
func putBack() -> ContextControllerPutBackViewInfo?
}
@ -2237,8 +2250,8 @@ public extension ContextExtractedContentSource {
return false
}
var centerActionsHorizontally: Bool {
return false
var actionsHorizontalAlignment: ContextActionsHorizontalAlignment {
return .default
}
var shouldBeDismissed: Signal<Bool, NoError> {

View File

@ -647,14 +647,14 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
}
let keepInPlace: Bool
let centerActionsHorizontally: Bool
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment
switch self.source {
case .location, .reference:
keepInPlace = true
centerActionsHorizontally = false
actionsHorizontalAlignment = .default
case let .extracted(source):
keepInPlace = source.keepInPlace
centerActionsHorizontally = source.centerActionsHorizontally
actionsHorizontalAlignment = source.actionsHorizontalAlignment
}
var defaultScrollY: CGFloat = 0.0
@ -769,7 +769,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
if let reactionContextNode = self.reactionContextNode {
additionalVisibleOffsetY += reactionContextNode.visibleExtensionDistance
}
if centerActionsHorizontally {
if case .center = actionsHorizontalAlignment {
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
@ -780,20 +780,24 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
} else {
if case .location = self.source {
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
} else if contentRect.midX < layout.size.width / 2.0 {
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
} else if case .right = actionsHorizontalAlignment {
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.maxX - actionsSideInset - actionsSize.width - 1.0
} else {
switch self.source {
case .location, .reference:
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
if contentRect.midX < layout.size.width / 2.0 {
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
} else {
switch self.source {
case .location, .reference:
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
}
if actionsFrame.minX < actionsEdgeInset {
actionsFrame.origin.x = actionsEdgeInset
}
case .extracted:
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.maxX - actionsSideInset - actionsSize.width - 1.0
}
if actionsFrame.minX < actionsEdgeInset {
actionsFrame.origin.x = actionsEdgeInset
}
case .extracted:
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.maxX - actionsSideInset - actionsSize.width - 1.0
}
}
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
@ -900,7 +904,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
let actionsSize = self.actionsStackNode.bounds.size
var actionsPositionDeltaXDistance: CGFloat = 0.0
if centerActionsHorizontally {
if case .center = actionsHorizontalAlignment {
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
}
@ -1116,7 +1120,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
let actionsSize = self.actionsStackNode.bounds.size
var actionsPositionDeltaXDistance: CGFloat = 0.0
if centerActionsHorizontally {
if case .center = actionsHorizontalAlignment {
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
}
let actionsPositionDeltaYDistance = -animationInContentDistance + actionsVerticalTransitionDirection * actionsSize.height / 2.0 - contentActionsSpacing

View File

@ -1206,7 +1206,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
for message in messages {
let currentKind = messageContentKind(contentSettings: strongSelf.context.currentContentSettings.with { $0 }, message: message, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat, accountPeerId: strongSelf.context.account.peerId)
if beganContentKindScanning && currentKind != generalMessageContentKind {
if beganContentKindScanning, let messageContentKind = generalMessageContentKind, !messageContentKind.isSemanticallyEqual(to: currentKind) {
generalMessageContentKind = nil
} else if !beganContentKindScanning || currentKind == generalMessageContentKind {
beganContentKindScanning = true
@ -1225,6 +1225,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
case .video:
preferredAction = .saveToCameraRoll
actionCompletionText = strongSelf.presentationData.strings.Gallery_VideoSaved
case .file:
preferredAction = .saveToCameraRoll
default:
break
}

View File

@ -2255,10 +2255,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
return nil
})
var loadedEmojiPack: LoadedStickerPack?
var highlightableLinks = false
let secondaryTitleText: String
if let otherPeerName = state.otherPeerName {
if case let .emojiStatus(_, _, file, maybeEmojiPack) = context.component.source, let emojiPack = maybeEmojiPack, case let .result(info, _, _) = emojiPack {
loadedEmojiPack = maybeEmojiPack
highlightableLinks = true
var packReference: StickerPackReference?
@ -2337,7 +2339,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
if let emojiFile = state?.emojiFile, let controller = environment?.controller() as? PremiumIntroScreen, let navigationController = controller.navigationController as? NavigationController {
for attribute in emojiFile.attributes {
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
let controller = accountContext.sharedContext.makeStickerPackScreen(context: accountContext, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: navigationController, sendSticker: { _, _, _ in
let controller = accountContext.sharedContext.makeStickerPackScreen(context: accountContext, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: loadedEmojiPack.flatMap { [$0] } ?? [], parentNavigationController: navigationController, sendSticker: { _, _, _ in
return false
})
presentController(controller)

View File

@ -47,6 +47,119 @@ public enum MessageContentKind: Equatable {
case dice(String)
case invoice(String)
public func isSemanticallyEqual(to other: MessageContentKind) -> Bool {
switch self {
case .text:
if case .text = other {
return true
} else {
return false
}
case .image:
if case .image = other {
return true
} else {
return false
}
case .video:
if case .video = other {
return true
} else {
return false
}
case .videoMessage:
if case .videoMessage = other {
return true
} else {
return false
}
case .audioMessage:
if case .audioMessage = other {
return true
} else {
return false
}
case .sticker:
if case .sticker = other {
return true
} else {
return false
}
case .animation:
if case .animation = other {
return true
} else {
return false
}
case .file:
if case .file = other {
return true
} else {
return false
}
case .contact:
if case .contact = other {
return true
} else {
return false
}
case .game:
if case .game = other {
return true
} else {
return false
}
case .location:
if case .location = other {
return true
} else {
return false
}
case .liveLocation:
if case .liveLocation = other {
return true
} else {
return false
}
case .expiredImage:
if case .expiredImage = other {
return true
} else {
return false
}
case .expiredVideo:
if case .expiredVideo = other {
return true
} else {
return false
}
case .poll:
if case .poll = other {
return true
} else {
return false
}
case .restricted:
if case .restricted = other {
return true
} else {
return false
}
case .dice:
if case .dice = other {
return true
} else {
return false
}
case .invoice:
if case .invoice = other {
return true
} else {
return false
}
}
}
public var key: MessageContentKindKey {
switch self {
case .text:

View File

@ -99,7 +99,7 @@ final class ChatMessageReactionContextExtractedContentSource: ContextExtractedCo
let keepInPlace: Bool = false
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private weak var chatNode: ChatControllerNode?
private let engine: TelegramEngine
@ -174,7 +174,7 @@ final class ChatMessageNavigationButtonContextExtractedContentSource: ContextExt
let keepInPlace: Bool = false
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private weak var chatNode: ChatControllerNode?
private let contentNode: ContextExtractedContentContainingNode

View File

@ -80,6 +80,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
}
}
self.micButton.layer.allowsGroupOpacity = true
self.view.addSubview(self.micButton)
self.addSubnode(self.sendContainerNode)

View File

@ -6,6 +6,7 @@ import TextFormat
import UIKit
import AppBundle
import TelegramStringFormatting
import ContextUI
enum PeerInfoScreenLabeledValueTextColor {
case primary
@ -29,10 +30,11 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
let textColor: PeerInfoScreenLabeledValueTextColor
let textBehavior: PeerInfoScreenLabeledValueTextBehavior
let icon: PeerInfoScreenLabeledValueIcon?
let action: (() -> Void)?
let action: ((ASDisplayNode) -> Void)?
let longTapAction: ((ASDisplayNode) -> Void)?
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
let iconAction: (() -> Void)?
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
let requestLayout: () -> Void
init(
@ -43,10 +45,11 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
textColor: PeerInfoScreenLabeledValueTextColor = .primary,
textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine,
icon: PeerInfoScreenLabeledValueIcon? = nil,
action: (() -> Void)?,
action: ((ASDisplayNode) -> Void)?,
longTapAction: ((ASDisplayNode) -> Void)? = nil,
linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil,
iconAction: (() -> Void)? = nil,
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
requestLayout: @escaping () -> Void
) {
self.id = id
@ -60,6 +63,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
self.longTapAction = longTapAction
self.linkItemAction = linkItemAction
self.iconAction = iconAction
self.contextAction = contextAction
self.requestLayout = requestLayout
}
@ -85,6 +89,14 @@ private func generateExpandBackground(size: CGSize, color: UIColor) -> UIImage?
}
private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
private let containerNode: ContextControllerSourceNode
private let contextSourceNode: ContextExtractedContentContainingNode
private let extractedBackgroundImageNode: ASImageNode
private var extractedRect: CGRect?
private var nonExtractedRect: CGRect?
private let selectionNode: PeerInfoScreenSelectableBackgroundNode
private let maskNode: ASImageNode
private let labelNode: ImmediateTextNode
@ -111,6 +123,14 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
override init() {
var bringToFrontForHighlightImpl: (() -> Void)?
self.contextSourceNode = ContextExtractedContentContainingNode()
self.containerNode = ContextControllerSourceNode()
self.extractedBackgroundImageNode = ASImageNode()
self.extractedBackgroundImageNode.displaysAsynchronously = false
self.extractedBackgroundImageNode.alpha = 0.0
self.selectionNode = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() })
self.selectionNode.isUserInteractionEnabled = false
@ -161,17 +181,25 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.addSubnode(self.bottomSeparatorNode)
self.addSubnode(self.selectionNode)
self.containerNode.addSubnode(self.contextSourceNode)
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
self.addSubnode(self.containerNode)
self.addSubnode(self.maskNode)
self.addSubnode(self.labelNode)
self.addSubnode(self.textNode)
self.addSubnode(self.additionalTextNode)
self.addSubnode(self.expandBackgroundNode)
self.addSubnode(self.expandNode)
self.addSubnode(self.expandButonNode)
self.contextSourceNode.contentNode.addSubnode(self.extractedBackgroundImageNode)
self.addSubnode(self.iconNode)
self.addSubnode(self.iconButtonNode)
self.contextSourceNode.contentNode.addSubnode(self.labelNode)
self.contextSourceNode.contentNode.addSubnode(self.textNode)
self.contextSourceNode.contentNode.addSubnode(self.additionalTextNode)
self.contextSourceNode.contentNode.addSubnode(self.expandBackgroundNode)
self.contextSourceNode.contentNode.addSubnode(self.expandNode)
self.contextSourceNode.contentNode.addSubnode(self.expandButonNode)
self.contextSourceNode.contentNode.addSubnode(self.iconNode)
self.contextSourceNode.contentNode.addSubnode(self.iconButtonNode)
self.addSubnode(self.activateArea)
@ -200,6 +228,35 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
}
}
}
self.containerNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self, let item = strongSelf.item, let contextAction = item.contextAction else {
gesture.cancel()
return
}
contextAction(strongSelf.contextSourceNode, gesture, nil)
}
self.contextSourceNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtracted, transition in
guard let strongSelf = self, let theme = strongSelf.theme else {
return
}
if isExtracted {
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: theme.list.plainBackgroundColor)
}
if let extractedRect = strongSelf.extractedRect, let nonExtractedRect = strongSelf.nonExtractedRect {
let rect = isExtracted ? extractedRect : nonExtractedRect
transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect)
}
transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
if !isExtracted {
self?.extractedBackgroundImageNode.image = nil
}
})
}
}
@objc private func expandPressed() {
@ -260,7 +317,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
} else if case .longTap = gesture {
item.longTapAction?(self)
} else if case .tap = gesture {
item.action?()
item.action?(self.contextSourceNode)
}
}
default:
@ -280,8 +337,16 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.item = item
self.theme = presentationData.theme
self.selectionNode.pressed = item.action
if let action = item.action {
self.selectionNode.pressed = { [weak self] in
if let strongSelf = self {
action(strongSelf.contextSourceNode)
}
}
} else {
self.selectionNode.pressed = nil
}
let sideInset: CGFloat = 16.0 + safeInsets.left
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
@ -460,6 +525,25 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.activateArea.accessibilityLabel = item.label
self.activateArea.accessibilityValue = item.text
let contentSize = CGSize(width: width, height: height)
self.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: contentSize)
self.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: contentSize)
self.containerNode.isGestureEnabled = false
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: contentSize.width, height: contentSize.height))
let extractedRect = nonExtractedRect
self.extractedRect = extractedRect
self.nonExtractedRect = nonExtractedRect
if self.contextSourceNode.isExtractedToContextPreview {
self.extractedBackgroundImageNode.frame = extractedRect
} else {
self.extractedBackgroundImageNode.frame = nonExtractedRect
}
self.contextSourceNode.contentRect = extractedRect
return height
}

View File

@ -462,7 +462,7 @@ private enum PeerInfoReportType {
private final class PeerInfoInteraction {
let openChat: () -> Void
let openUsername: (String) -> Void
let openPhone: (String) -> Void
let openPhone: (String, ASDisplayNode, ContextGesture?) -> Void
let editingOpenNotificationSettings: () -> Void
let editingOpenSoundSettings: () -> Void
let editingToggleShowMessageText: (Bool) -> Void
@ -505,7 +505,7 @@ private final class PeerInfoInteraction {
init(
openUsername: @escaping (String) -> Void,
openPhone: @escaping (String) -> Void,
openPhone: @escaping (String, ASDisplayNode, ContextGesture?) -> Void,
editingOpenNotificationSettings: @escaping () -> Void,
editingOpenSoundSettings: @escaping () -> Void,
editingToggleShowMessageText: @escaping (Bool) -> Void,
@ -942,10 +942,10 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
if let phone = user.phone {
let formattedPhone = formatPhoneNumber(phone)
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: presentationData.strings.ContactInfo_PhoneLabelMobile, text: formattedPhone, textColor: .accent, action: {
interaction.openPhone(phone)
}, longTapAction: { sourceNode in
interaction.openPeerInfoContextMenu(.phone(formattedPhone), sourceNode)
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: presentationData.strings.ContactInfo_PhoneLabelMobile, text: formattedPhone, textColor: .accent, action: { node in
interaction.openPhone(phone, node, nil)
}, longTapAction: nil, contextAction: { node, gesture, _ in
interaction.openPhone(phone, node, gesture)
}, requestLayout: {
interaction.requestLayout(false)
}))
@ -959,7 +959,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
additionalText: nil, //presentationData.strings.Profile_AdditionalUsernames("@username1, @username2, @username3, @username4"),
textColor: .accent,
icon: .qrCode,
action: {
action: { _ in
interaction.openUsername(username)
}, longTapAction: { sourceNode in
interaction.openPeerInfoContextMenu(.link, sourceNode)
@ -1076,7 +1076,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
}
if let username = channel.username {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, icon: .qrCode, action: {
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: ItemUsername, label: presentationData.strings.Channel_LinkItem, text: "https://t.me/\(username)", textColor: .accent, icon: .qrCode, action: { _ in
interaction.openUsername(username)
}, longTapAction: { sourceNode in
interaction.openPeerInfoContextMenu(.link, sourceNode)
@ -1812,8 +1812,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
openUsername: { [weak self] value in
self?.openUsername(value: value)
},
openPhone: { [weak self] value in
self?.openPhone(value: value)
openPhone: { [weak self] value, node, gesture in
self?.openPhone(value: value, node: node, gesture: gesture)
},
editingOpenNotificationSettings: { [weak self] in
self?.editingOpenNotificationSettings()
@ -4892,39 +4892,110 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
}
}
private func openPhone(value: String) {
private func openPhone(value: String, node: ASDisplayNode, gesture: ContextGesture?) {
guard let sourceNode = node as? ContextExtractedContentContainingNode else {
return
}
let _ = (getUserPeer(engine: self.context.engine, peerId: self.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
return
}
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
let dismissAction: () -> Void = { [weak actionSheet] in
actionSheet?.dismissAnimated()
// if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) {
// let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
// let dismissAction: () -> Void = { [weak actionSheet] in
// actionSheet?.dismissAnimated()
// }
// actionSheet.setItemGroups([
// ActionSheetItemGroup(items: [
// ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_TelegramCall, action: {
// dismissAction()
// self?.requestCall(isVideo: false)
// }),
// ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_PhoneCall, action: {
// dismissAction()
//
// guard let strongSelf = self else {
// return
// }
// strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))")
// }),
// ]),
// ActionSheetItemGroup(items: [ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, action: { dismissAction() })])
// ])
// strongSelf.view.endEditing(true)
// strongSelf.controller?.present(actionSheet, in: .window(.root))
// } else {
// strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))")
// }
//
let presentationData = strongSelf.presentationData
let telegramCallAction: (Bool) -> Void = { [weak self] isVideo in
guard let strongSelf = self else {
return
}
strongSelf.requestCall(isVideo: isVideo)
}
let phoneCallAction = { [weak self] in
guard let strongSelf = self else {
return
}
actionSheet.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_TelegramCall, action: {
dismissAction()
self?.requestCall(isVideo: false)
}),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.UserInfo_PhoneCall, action: {
dismissAction()
guard let strongSelf = self else {
return
}
strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))")
}),
]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
strongSelf.view.endEditing(true)
strongSelf.controller?.present(actionSheet, in: .window(.root))
} else {
strongSelf.context.sharedContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(value).replacingOccurrences(of: " ", with: ""))")
}
let copyAction = { [weak self] in
guard let strongSelf = self else {
return
}
UIPasteboard.general.string = formatPhoneNumber(value)
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_PhoneCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
var items: [ContextMenuItem] = []
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_TelegramCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
telegramCallAction(false)
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_TelegramVideoCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/VideoCall"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
telegramCallAction(true)
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_PhoneCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: ""), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
phoneCallAction()
}
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
copyAction()
}
})))
} else {
items = [
.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_PhoneCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: ""), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
phoneCallAction()
}
})),
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
c.dismiss {
copyAction()
}
})),
]
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .extracted(PeerInfoContextExtractedContentSource(sourceNode: sourceNode)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
// contextController.useComplexItemsTransitionAnimation = true
strongSelf.controller?.present(contextController, in: .window(.root))
})
}
@ -8516,7 +8587,7 @@ private final class SettingsTabBarContextExtractedContentSource: ContextExtracte
let keepInPlace: Bool = true
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let centerActionsHorizontally: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode
@ -8814,6 +8885,28 @@ private final class MessageContextExtractedContentSource: ContextExtractedConten
}
}
private final class PeerInfoContextExtractedContentSource: ContextExtractedContentSource {
var keepInPlace: Bool = false
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .right
private let sourceNode: ContextExtractedContentContainingNode
init(sourceNode: ContextExtractedContentContainingNode) {
self.sourceNode = sourceNode
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(containingItem: .node(self.sourceNode), contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
}
}
private final class PeerInfoContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceNode: ContextReferenceContentNode