mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +00:00
Merge commit '7015c76e74c0fdac2597079b860f66fd1c6b14ab'
This commit is contained in:
commit
399b679532
@ -2590,6 +2590,7 @@ Unused sets are archived when you add more.";
|
|||||||
"Conversation.HoldForVideo" = "Hold to record video. Tap to switch to audio.";
|
"Conversation.HoldForVideo" = "Hold to record video. Tap to switch to audio.";
|
||||||
|
|
||||||
"UserInfo.TelegramCall" = "Telegram Call";
|
"UserInfo.TelegramCall" = "Telegram Call";
|
||||||
|
"UserInfo.TelegramVideoCall" = "Telegram Video Call";
|
||||||
"UserInfo.PhoneCall" = "Phone Call";
|
"UserInfo.PhoneCall" = "Phone Call";
|
||||||
|
|
||||||
"SharedMedia.CategoryMedia" = "Media";
|
"SharedMedia.CategoryMedia" = "Media";
|
||||||
|
|||||||
@ -649,7 +649,6 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
|
|||||||
iconNode.isLayerBacked = true
|
iconNode.isLayerBacked = true
|
||||||
iconNode.displaysAsynchronously = false
|
iconNode.displaysAsynchronously = false
|
||||||
iconNode.displayWithoutProcessing = true
|
iconNode.displayWithoutProcessing = true
|
||||||
strongSelf.containerNode.addSubnode(iconNode)
|
|
||||||
strongSelf.credibilityIconNode = iconNode
|
strongSelf.credibilityIconNode = iconNode
|
||||||
}
|
}
|
||||||
iconNode.image = currentCredibilityIconImage
|
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.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.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))
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -499,7 +499,7 @@ private final class CallListTabBarContextExtractedContentSource: ContextExtracte
|
|||||||
let keepInPlace: Bool = true
|
let keepInPlace: Bool = true
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextExtractedContentContainingNode
|
private let sourceNode: ContextExtractedContentContainingNode
|
||||||
|
|||||||
@ -3813,7 +3813,7 @@ private final class ChatListTabBarContextExtractedContentSource: ContextExtracte
|
|||||||
let keepInPlace: Bool = true
|
let keepInPlace: Bool = true
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private let controller: ChatListController
|
private let controller: ChatListController
|
||||||
private let sourceNode: ContextExtractedContentContainingNode
|
private let sourceNode: ContextExtractedContentContainingNode
|
||||||
|
|||||||
@ -686,7 +686,7 @@ private final class ContactsTabBarContextExtractedContentSource: ContextExtracte
|
|||||||
let keepInPlace: Bool = true
|
let keepInPlace: Bool = true
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextExtractedContentContainingNode
|
private let sourceNode: ContextExtractedContentContainingNode
|
||||||
|
|||||||
@ -965,6 +965,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var delayLayoutUpdate = false
|
||||||
func animateOut(result initialResult: ContextMenuActionResult, completion: @escaping () -> Void) {
|
func animateOut(result initialResult: ContextMenuActionResult, completion: @escaping () -> Void) {
|
||||||
self.isUserInteractionEnabled = false
|
self.isUserInteractionEnabled = false
|
||||||
|
|
||||||
@ -973,11 +974,15 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
|
|||||||
if let _ = self.presentationNode {
|
if let _ = self.presentationNode {
|
||||||
self.currentPresentationStateTransition = .animateOut(result: initialResult, completion: completion)
|
self.currentPresentationStateTransition = .animateOut(result: initialResult, completion: completion)
|
||||||
if let validLayout = self.validLayout {
|
if let validLayout = self.validLayout {
|
||||||
self.updateLayout(
|
self.delayLayoutUpdate = true
|
||||||
layout: validLayout,
|
Queue.mainQueue().after(0.05) {
|
||||||
transition: .animated(duration: 0.35, curve: .easeInOut),
|
self.delayLayoutUpdate = false
|
||||||
previousActionsContainerNode: nil
|
self.updateLayout(
|
||||||
)
|
layout: validLayout,
|
||||||
|
transition: .animated(duration: 0.35, curve: .easeInOut),
|
||||||
|
previousActionsContainerNode: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
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) {
|
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition, previousActionsContainerNode: ContextActionsContainerNode?, previousActionsContainerFrame: CGRect? = nil, previousActionsTransition: ContextController.PreviousActionsTransition = .scale) {
|
||||||
if self.isAnimatingOut {
|
if self.isAnimatingOut || self.delayLayoutUpdate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2220,14 +2225,22 @@ public final class ContextControllerPutBackViewInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ContextActionsHorizontalAlignment {
|
||||||
|
case `default`
|
||||||
|
case left
|
||||||
|
case center
|
||||||
|
case right
|
||||||
|
}
|
||||||
|
|
||||||
public protocol ContextExtractedContentSource: AnyObject {
|
public protocol ContextExtractedContentSource: AnyObject {
|
||||||
var centerVertically: Bool { get }
|
var centerVertically: Bool { get }
|
||||||
var keepInPlace: Bool { get }
|
var keepInPlace: Bool { get }
|
||||||
var ignoreContentTouches: Bool { get }
|
var ignoreContentTouches: Bool { get }
|
||||||
var blurBackground: Bool { get }
|
var blurBackground: Bool { get }
|
||||||
var centerActionsHorizontally: Bool { get }
|
|
||||||
var shouldBeDismissed: Signal<Bool, NoError> { get }
|
var shouldBeDismissed: Signal<Bool, NoError> { get }
|
||||||
|
|
||||||
|
var actionsHorizontalAlignment: ContextActionsHorizontalAlignment { get }
|
||||||
|
|
||||||
func takeView() -> ContextControllerTakeViewInfo?
|
func takeView() -> ContextControllerTakeViewInfo?
|
||||||
func putBack() -> ContextControllerPutBackViewInfo?
|
func putBack() -> ContextControllerPutBackViewInfo?
|
||||||
}
|
}
|
||||||
@ -2237,8 +2250,8 @@ public extension ContextExtractedContentSource {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var centerActionsHorizontally: Bool {
|
var actionsHorizontalAlignment: ContextActionsHorizontalAlignment {
|
||||||
return false
|
return .default
|
||||||
}
|
}
|
||||||
|
|
||||||
var shouldBeDismissed: Signal<Bool, NoError> {
|
var shouldBeDismissed: Signal<Bool, NoError> {
|
||||||
|
|||||||
@ -647,14 +647,14 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
let keepInPlace: Bool
|
let keepInPlace: Bool
|
||||||
let centerActionsHorizontally: Bool
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment
|
||||||
switch self.source {
|
switch self.source {
|
||||||
case .location, .reference:
|
case .location, .reference:
|
||||||
keepInPlace = true
|
keepInPlace = true
|
||||||
centerActionsHorizontally = false
|
actionsHorizontalAlignment = .default
|
||||||
case let .extracted(source):
|
case let .extracted(source):
|
||||||
keepInPlace = source.keepInPlace
|
keepInPlace = source.keepInPlace
|
||||||
centerActionsHorizontally = source.centerActionsHorizontally
|
actionsHorizontalAlignment = source.actionsHorizontalAlignment
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultScrollY: CGFloat = 0.0
|
var defaultScrollY: CGFloat = 0.0
|
||||||
@ -769,7 +769,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
if let reactionContextNode = self.reactionContextNode {
|
if let reactionContextNode = self.reactionContextNode {
|
||||||
additionalVisibleOffsetY += reactionContextNode.visibleExtensionDistance
|
additionalVisibleOffsetY += reactionContextNode.visibleExtensionDistance
|
||||||
}
|
}
|
||||||
if centerActionsHorizontally {
|
if case .center = actionsHorizontalAlignment {
|
||||||
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
|
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
|
||||||
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
|
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
|
||||||
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
|
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
|
||||||
@ -780,20 +780,24 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
} else {
|
} else {
|
||||||
if case .location = self.source {
|
if case .location = self.source {
|
||||||
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
|
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
|
||||||
} else if contentRect.midX < layout.size.width / 2.0 {
|
} else if case .right = actionsHorizontalAlignment {
|
||||||
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
|
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.maxX - actionsSideInset - actionsSize.width - 1.0
|
||||||
} else {
|
} else {
|
||||||
switch self.source {
|
if contentRect.midX < layout.size.width / 2.0 {
|
||||||
case .location, .reference:
|
actionsFrame.origin.x = contentParentGlobalFrame.minX + contentRect.minX + actionsSideInset - 4.0
|
||||||
actionsFrame.origin.x = floor(contentParentGlobalFrame.minX + contentRect.midX - actionsFrame.width / 2.0)
|
} else {
|
||||||
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
|
switch self.source {
|
||||||
actionsFrame.origin.x = layout.size.width - actionsEdgeInset - actionsFrame.width
|
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 {
|
if actionsFrame.maxX > layout.size.width - actionsEdgeInset {
|
||||||
@ -900,7 +904,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
let actionsSize = self.actionsStackNode.bounds.size
|
let actionsSize = self.actionsStackNode.bounds.size
|
||||||
|
|
||||||
var actionsPositionDeltaXDistance: CGFloat = 0.0
|
var actionsPositionDeltaXDistance: CGFloat = 0.0
|
||||||
if centerActionsHorizontally {
|
if case .center = actionsHorizontalAlignment {
|
||||||
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
|
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,7 +1120,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
|||||||
let actionsSize = self.actionsStackNode.bounds.size
|
let actionsSize = self.actionsStackNode.bounds.size
|
||||||
|
|
||||||
var actionsPositionDeltaXDistance: CGFloat = 0.0
|
var actionsPositionDeltaXDistance: CGFloat = 0.0
|
||||||
if centerActionsHorizontally {
|
if case .center = actionsHorizontalAlignment {
|
||||||
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
|
actionsPositionDeltaXDistance = currentContentScreenFrame.midX - self.actionsStackNode.frame.midX
|
||||||
}
|
}
|
||||||
let actionsPositionDeltaYDistance = -animationInContentDistance + actionsVerticalTransitionDirection * actionsSize.height / 2.0 - contentActionsSpacing
|
let actionsPositionDeltaYDistance = -animationInContentDistance + actionsVerticalTransitionDirection * actionsSize.height / 2.0 - contentActionsSpacing
|
||||||
|
|||||||
@ -1206,7 +1206,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
|
|
||||||
for message in messages {
|
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)
|
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
|
generalMessageContentKind = nil
|
||||||
} else if !beganContentKindScanning || currentKind == generalMessageContentKind {
|
} else if !beganContentKindScanning || currentKind == generalMessageContentKind {
|
||||||
beganContentKindScanning = true
|
beganContentKindScanning = true
|
||||||
@ -1225,6 +1225,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
case .video:
|
case .video:
|
||||||
preferredAction = .saveToCameraRoll
|
preferredAction = .saveToCameraRoll
|
||||||
actionCompletionText = strongSelf.presentationData.strings.Gallery_VideoSaved
|
actionCompletionText = strongSelf.presentationData.strings.Gallery_VideoSaved
|
||||||
|
case .file:
|
||||||
|
preferredAction = .saveToCameraRoll
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2255,10 +2255,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var loadedEmojiPack: LoadedStickerPack?
|
||||||
var highlightableLinks = false
|
var highlightableLinks = false
|
||||||
let secondaryTitleText: String
|
let secondaryTitleText: String
|
||||||
if let otherPeerName = state.otherPeerName {
|
if let otherPeerName = state.otherPeerName {
|
||||||
if case let .emojiStatus(_, _, file, maybeEmojiPack) = context.component.source, let emojiPack = maybeEmojiPack, case let .result(info, _, _) = emojiPack {
|
if case let .emojiStatus(_, _, file, maybeEmojiPack) = context.component.source, let emojiPack = maybeEmojiPack, case let .result(info, _, _) = emojiPack {
|
||||||
|
loadedEmojiPack = maybeEmojiPack
|
||||||
highlightableLinks = true
|
highlightableLinks = true
|
||||||
|
|
||||||
var packReference: StickerPackReference?
|
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 {
|
if let emojiFile = state?.emojiFile, let controller = environment?.controller() as? PremiumIntroScreen, let navigationController = controller.navigationController as? NavigationController {
|
||||||
for attribute in emojiFile.attributes {
|
for attribute in emojiFile.attributes {
|
||||||
if case let .CustomEmoji(_, _, packReference) = attribute, let packReference = packReference {
|
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
|
return false
|
||||||
})
|
})
|
||||||
presentController(controller)
|
presentController(controller)
|
||||||
|
|||||||
@ -47,6 +47,119 @@ public enum MessageContentKind: Equatable {
|
|||||||
case dice(String)
|
case dice(String)
|
||||||
case invoice(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 {
|
public var key: MessageContentKindKey {
|
||||||
switch self {
|
switch self {
|
||||||
case .text:
|
case .text:
|
||||||
|
|||||||
@ -99,7 +99,7 @@ final class ChatMessageReactionContextExtractedContentSource: ContextExtractedCo
|
|||||||
let keepInPlace: Bool = false
|
let keepInPlace: Bool = false
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private weak var chatNode: ChatControllerNode?
|
private weak var chatNode: ChatControllerNode?
|
||||||
private let engine: TelegramEngine
|
private let engine: TelegramEngine
|
||||||
@ -174,7 +174,7 @@ final class ChatMessageNavigationButtonContextExtractedContentSource: ContextExt
|
|||||||
let keepInPlace: Bool = false
|
let keepInPlace: Bool = false
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private weak var chatNode: ChatControllerNode?
|
private weak var chatNode: ChatControllerNode?
|
||||||
private let contentNode: ContextExtractedContentContainingNode
|
private let contentNode: ContextExtractedContentContainingNode
|
||||||
|
|||||||
@ -80,6 +80,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.micButton.layer.allowsGroupOpacity = true
|
||||||
self.view.addSubview(self.micButton)
|
self.view.addSubview(self.micButton)
|
||||||
|
|
||||||
self.addSubnode(self.sendContainerNode)
|
self.addSubnode(self.sendContainerNode)
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import TextFormat
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
|
import ContextUI
|
||||||
|
|
||||||
enum PeerInfoScreenLabeledValueTextColor {
|
enum PeerInfoScreenLabeledValueTextColor {
|
||||||
case primary
|
case primary
|
||||||
@ -29,10 +30,11 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
|||||||
let textColor: PeerInfoScreenLabeledValueTextColor
|
let textColor: PeerInfoScreenLabeledValueTextColor
|
||||||
let textBehavior: PeerInfoScreenLabeledValueTextBehavior
|
let textBehavior: PeerInfoScreenLabeledValueTextBehavior
|
||||||
let icon: PeerInfoScreenLabeledValueIcon?
|
let icon: PeerInfoScreenLabeledValueIcon?
|
||||||
let action: (() -> Void)?
|
let action: ((ASDisplayNode) -> Void)?
|
||||||
let longTapAction: ((ASDisplayNode) -> Void)?
|
let longTapAction: ((ASDisplayNode) -> Void)?
|
||||||
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
||||||
let iconAction: (() -> Void)?
|
let iconAction: (() -> Void)?
|
||||||
|
let contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||||
let requestLayout: () -> Void
|
let requestLayout: () -> Void
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -43,10 +45,11 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
|||||||
textColor: PeerInfoScreenLabeledValueTextColor = .primary,
|
textColor: PeerInfoScreenLabeledValueTextColor = .primary,
|
||||||
textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine,
|
textBehavior: PeerInfoScreenLabeledValueTextBehavior = .singleLine,
|
||||||
icon: PeerInfoScreenLabeledValueIcon? = nil,
|
icon: PeerInfoScreenLabeledValueIcon? = nil,
|
||||||
action: (() -> Void)?,
|
action: ((ASDisplayNode) -> Void)?,
|
||||||
longTapAction: ((ASDisplayNode) -> Void)? = nil,
|
longTapAction: ((ASDisplayNode) -> Void)? = nil,
|
||||||
linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil,
|
linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil,
|
||||||
iconAction: (() -> Void)? = nil,
|
iconAction: (() -> Void)? = nil,
|
||||||
|
contextAction: ((ASDisplayNode, ContextGesture?, CGPoint?) -> Void)? = nil,
|
||||||
requestLayout: @escaping () -> Void
|
requestLayout: @escaping () -> Void
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
@ -60,6 +63,7 @@ final class PeerInfoScreenLabeledValueItem: PeerInfoScreenItem {
|
|||||||
self.longTapAction = longTapAction
|
self.longTapAction = longTapAction
|
||||||
self.linkItemAction = linkItemAction
|
self.linkItemAction = linkItemAction
|
||||||
self.iconAction = iconAction
|
self.iconAction = iconAction
|
||||||
|
self.contextAction = contextAction
|
||||||
self.requestLayout = requestLayout
|
self.requestLayout = requestLayout
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +89,14 @@ private func generateExpandBackground(size: CGSize, color: UIColor) -> UIImage?
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
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 selectionNode: PeerInfoScreenSelectableBackgroundNode
|
||||||
private let maskNode: ASImageNode
|
private let maskNode: ASImageNode
|
||||||
private let labelNode: ImmediateTextNode
|
private let labelNode: ImmediateTextNode
|
||||||
@ -111,6 +123,14 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
|
|
||||||
override init() {
|
override init() {
|
||||||
var bringToFrontForHighlightImpl: (() -> Void)?
|
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 = PeerInfoScreenSelectableBackgroundNode(bringToFrontForHighlight: { bringToFrontForHighlightImpl?() })
|
||||||
self.selectionNode.isUserInteractionEnabled = false
|
self.selectionNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
@ -161,17 +181,25 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
|
|
||||||
self.addSubnode(self.bottomSeparatorNode)
|
self.addSubnode(self.bottomSeparatorNode)
|
||||||
self.addSubnode(self.selectionNode)
|
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.maskNode)
|
||||||
self.addSubnode(self.labelNode)
|
|
||||||
self.addSubnode(self.textNode)
|
|
||||||
self.addSubnode(self.additionalTextNode)
|
|
||||||
|
|
||||||
self.addSubnode(self.expandBackgroundNode)
|
self.contextSourceNode.contentNode.addSubnode(self.extractedBackgroundImageNode)
|
||||||
self.addSubnode(self.expandNode)
|
|
||||||
self.addSubnode(self.expandButonNode)
|
|
||||||
|
|
||||||
self.addSubnode(self.iconNode)
|
self.contextSourceNode.contentNode.addSubnode(self.labelNode)
|
||||||
self.addSubnode(self.iconButtonNode)
|
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)
|
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() {
|
@objc private func expandPressed() {
|
||||||
@ -260,7 +317,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
} else if case .longTap = gesture {
|
} else if case .longTap = gesture {
|
||||||
item.longTapAction?(self)
|
item.longTapAction?(self)
|
||||||
} else if case .tap = gesture {
|
} else if case .tap = gesture {
|
||||||
item.action?()
|
item.action?(self.contextSourceNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -280,8 +337,16 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
self.item = item
|
self.item = item
|
||||||
self.theme = presentationData.theme
|
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
|
let sideInset: CGFloat = 16.0 + safeInsets.left
|
||||||
|
|
||||||
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
self.bottomSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
||||||
@ -460,6 +525,25 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
|
|||||||
self.activateArea.accessibilityLabel = item.label
|
self.activateArea.accessibilityLabel = item.label
|
||||||
self.activateArea.accessibilityValue = item.text
|
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
|
return height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -462,7 +462,7 @@ private enum PeerInfoReportType {
|
|||||||
private final class PeerInfoInteraction {
|
private final class PeerInfoInteraction {
|
||||||
let openChat: () -> Void
|
let openChat: () -> Void
|
||||||
let openUsername: (String) -> Void
|
let openUsername: (String) -> Void
|
||||||
let openPhone: (String) -> Void
|
let openPhone: (String, ASDisplayNode, ContextGesture?) -> Void
|
||||||
let editingOpenNotificationSettings: () -> Void
|
let editingOpenNotificationSettings: () -> Void
|
||||||
let editingOpenSoundSettings: () -> Void
|
let editingOpenSoundSettings: () -> Void
|
||||||
let editingToggleShowMessageText: (Bool) -> Void
|
let editingToggleShowMessageText: (Bool) -> Void
|
||||||
@ -505,7 +505,7 @@ private final class PeerInfoInteraction {
|
|||||||
|
|
||||||
init(
|
init(
|
||||||
openUsername: @escaping (String) -> Void,
|
openUsername: @escaping (String) -> Void,
|
||||||
openPhone: @escaping (String) -> Void,
|
openPhone: @escaping (String, ASDisplayNode, ContextGesture?) -> Void,
|
||||||
editingOpenNotificationSettings: @escaping () -> Void,
|
editingOpenNotificationSettings: @escaping () -> Void,
|
||||||
editingOpenSoundSettings: @escaping () -> Void,
|
editingOpenSoundSettings: @escaping () -> Void,
|
||||||
editingToggleShowMessageText: @escaping (Bool) -> Void,
|
editingToggleShowMessageText: @escaping (Bool) -> Void,
|
||||||
@ -942,10 +942,10 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
|
|
||||||
if let phone = user.phone {
|
if let phone = user.phone {
|
||||||
let formattedPhone = formatPhoneNumber(phone)
|
let formattedPhone = formatPhoneNumber(phone)
|
||||||
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: presentationData.strings.ContactInfo_PhoneLabelMobile, text: formattedPhone, textColor: .accent, action: {
|
items[.peerInfo]!.append(PeerInfoScreenLabeledValueItem(id: 2, label: presentationData.strings.ContactInfo_PhoneLabelMobile, text: formattedPhone, textColor: .accent, action: { node in
|
||||||
interaction.openPhone(phone)
|
interaction.openPhone(phone, node, nil)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: nil, contextAction: { node, gesture, _ in
|
||||||
interaction.openPeerInfoContextMenu(.phone(formattedPhone), sourceNode)
|
interaction.openPhone(phone, node, gesture)
|
||||||
}, requestLayout: {
|
}, requestLayout: {
|
||||||
interaction.requestLayout(false)
|
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"),
|
additionalText: nil, //presentationData.strings.Profile_AdditionalUsernames("@username1, @username2, @username3, @username4"),
|
||||||
textColor: .accent,
|
textColor: .accent,
|
||||||
icon: .qrCode,
|
icon: .qrCode,
|
||||||
action: {
|
action: { _ in
|
||||||
interaction.openUsername(username)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
||||||
@ -1076,7 +1076,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let username = channel.username {
|
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)
|
interaction.openUsername(username)
|
||||||
}, longTapAction: { sourceNode in
|
}, longTapAction: { sourceNode in
|
||||||
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
interaction.openPeerInfoContextMenu(.link, sourceNode)
|
||||||
@ -1812,8 +1812,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
openUsername: { [weak self] value in
|
openUsername: { [weak self] value in
|
||||||
self?.openUsername(value: value)
|
self?.openUsername(value: value)
|
||||||
},
|
},
|
||||||
openPhone: { [weak self] value in
|
openPhone: { [weak self] value, node, gesture in
|
||||||
self?.openPhone(value: value)
|
self?.openPhone(value: value, node: node, gesture: gesture)
|
||||||
},
|
},
|
||||||
editingOpenNotificationSettings: { [weak self] in
|
editingOpenNotificationSettings: { [weak self] in
|
||||||
self?.editingOpenNotificationSettings()
|
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)
|
let _ = (getUserPeer(engine: self.context.engine, peerId: self.peerId)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) {
|
// if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formatPhoneNumber(value) == formatPhoneNumber(peerPhoneNumber) {
|
||||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
// let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||||
let dismissAction: () -> Void = { [weak actionSheet] in
|
// let dismissAction: () -> Void = { [weak actionSheet] in
|
||||||
actionSheet?.dismissAnimated()
|
// 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: ""))")
|
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 keepInPlace: Bool = true
|
||||||
let ignoreContentTouches: Bool = true
|
let ignoreContentTouches: Bool = true
|
||||||
let blurBackground: Bool = true
|
let blurBackground: Bool = true
|
||||||
let centerActionsHorizontally: Bool = true
|
let actionsHorizontalAlignment: ContextActionsHorizontalAlignment = .center
|
||||||
|
|
||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextExtractedContentContainingNode
|
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 final class PeerInfoContextReferenceContentSource: ContextReferenceContentSource {
|
||||||
private let controller: ViewController
|
private let controller: ViewController
|
||||||
private let sourceNode: ContextReferenceContentNode
|
private let sourceNode: ContextReferenceContentNode
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user