diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 833f8d1122..b39f1ace52 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -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"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 0e686c05f2..aface6baf1 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -753,7 +753,7 @@ public protocol SharedAccountContext: AnyObject { func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController - func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController + func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], loadedStickerPacks: [LoadedStickerPack], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController func makeProxySettingsController(sharedContext: SharedAccountContext, account: UnauthorizedAccount) -> ViewController @@ -786,7 +786,7 @@ public enum PremiumIntroSource { case about case deeplink(String?) case profile(PeerId) - case emojiStatus(PeerId, Int64, TelegramMediaFile?, String?) + case emojiStatus(PeerId, Int64, TelegramMediaFile?, LoadedStickerPack?) } #if ENABLE_WALLET diff --git a/submodules/CallListUI/Sources/CallListCallItem.swift b/submodules/CallListUI/Sources/CallListCallItem.swift index da270f6aa8..b2113a287c 100644 --- a/submodules/CallListUI/Sources/CallListCallItem.swift +++ b/submodules/CallListUI/Sources/CallListCallItem.swift @@ -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)) } } diff --git a/submodules/CallListUI/Sources/CallListController.swift b/submodules/CallListUI/Sources/CallListController.swift index 501e8e1cc6..bcd23d8caa 100644 --- a/submodules/CallListUI/Sources/CallListController.swift +++ b/submodules/CallListUI/Sources/CallListController.swift @@ -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 diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index a8b602ebbe..c371e13ab7 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -3512,7 +3512,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 diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 392568bddb..131f630e5c 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2339,7 +2339,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { continue } if let previewNode = self.mediaPreviewNodes[mediaId] { - transition.updateFrame(node: previewNode, frame: CGRect(origin: CGPoint(x: mediaPreviewOffsetX, y: previewNode.frame.minY), size: mediaSize)) + transition.updateFrameAdditive(node: previewNode, frame: CGRect(origin: CGPoint(x: mediaPreviewOffsetX, y: previewNode.frame.minY), size: mediaSize)) } mediaPreviewOffsetX += mediaSize.width + contentImageSpacing } @@ -2358,7 +2358,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } let mutedIconFrame = self.mutedIconNode.frame - transition.updateFrame(node: self.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: mutedIconFrame.minY), size: mutedIconFrame.size)) + transition.updateFrameAdditive(node: self.mutedIconNode, frame: CGRect(origin: CGPoint(x: nextTitleIconOrigin - 5.0, y: mutedIconFrame.minY), size: mutedIconFrame.size)) nextTitleIconOrigin += mutedIconFrame.size.width + 3.0 let badgeFrame = self.badgeNode.frame diff --git a/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift b/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift index 62fe7f3950..35ffb48e3b 100644 --- a/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift +++ b/submodules/ChatMessageBackground/Sources/ChatMessageBackground.swift @@ -234,9 +234,24 @@ public class ChatMessageBackground: ASDisplayNode { }) } } else if transition.isAnimated { - if let previousContents = self.imageNode.layer.contents, let image = image { - if (previousContents as AnyObject) !== image.cgImage { - self.imageNode.layer.animate(from: previousContents as AnyObject, to: image.cgImage! as AnyObject, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.42) + if let previousContents = self.imageNode.layer.contents { + if let image = image { + if (previousContents as AnyObject) !== image.cgImage { + self.imageNode.layer.animate(from: previousContents as AnyObject, to: image.cgImage! as AnyObject, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.42) + } + } else { + let tempLayer = CALayer() + tempLayer.contents = self.imageNode.layer.contents + tempLayer.contentsScale = self.imageNode.layer.contentsScale + tempLayer.rasterizationScale = self.imageNode.layer.rasterizationScale + tempLayer.contentsGravity = self.imageNode.layer.contentsGravity + tempLayer.contentsCenter = self.imageNode.layer.contentsCenter + + tempLayer.frame = self.bounds + self.layer.insertSublayer(tempLayer, above: self.imageNode.layer) + transition.updateAlpha(layer: tempLayer, alpha: 0.0, completion: { [weak tempLayer] _ in + tempLayer?.removeFromSuperlayer() + }) } } } diff --git a/submodules/ContactListUI/Sources/ContactsController.swift b/submodules/ContactListUI/Sources/ContactsController.swift index bbee69c4ba..2e1f0c103a 100644 --- a/submodules/ContactListUI/Sources/ContactsController.swift +++ b/submodules/ContactListUI/Sources/ContactsController.swift @@ -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 diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 380fe516d6..dd591819b7 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -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 { 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 { diff --git a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift index b81ca9f64d..0f983e673e 100644 --- a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift @@ -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 diff --git a/submodules/Display/Source/ChildWindowHostView.swift b/submodules/Display/Source/ChildWindowHostView.swift index 36dadaac16..f4b7a998b9 100644 --- a/submodules/Display/Source/ChildWindowHostView.swift +++ b/submodules/Display/Source/ChildWindowHostView.swift @@ -1,7 +1,7 @@ import Foundation import UIKit -private final class ChildWindowHostView: UIView, WindowHost { +final class ChildWindowHostView: UIView, WindowHost { var updateSize: ((CGSize) -> Void)? var layoutSubviewsEvent: (() -> Void)? var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)? @@ -56,6 +56,7 @@ private final class ChildWindowHostView: UIView, WindowHost { } func presentInGlobalOverlay(_ controller: ContainableController) { + self.presentController?(controller, .root, true, {}) } func addGlobalPortalHostView(sourceView: PortalSourceView) { diff --git a/submodules/Display/Source/WindowContent.swift b/submodules/Display/Source/WindowContent.swift index 81f85d0ca3..64ecf7536e 100644 --- a/submodules/Display/Source/WindowContent.swift +++ b/submodules/Display/Source/WindowContent.swift @@ -561,6 +561,10 @@ public class Window1 { } } + if strongSelf.hostView.containerView is ChildWindowHostView, !isTablet { + keyboardHeight += 27.0 + } + print("keyboardHeight: \(keyboardHeight) (raw: \(keyboardFrame))") var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 diff --git a/submodules/Emoji/Sources/EmojiUtils.swift b/submodules/Emoji/Sources/EmojiUtils.swift index 424fc492bb..4d393fdb6b 100644 --- a/submodules/Emoji/Sources/EmojiUtils.swift +++ b/submodules/Emoji/Sources/EmojiUtils.swift @@ -28,7 +28,7 @@ extension Character { public extension UnicodeScalar { var isEmoji: Bool { switch self.value { - case 0x1F600...0x1F64F, 0x1F300...0x1F5FF, 0x1F680...0x1F6FF, 0x1F1E6...0x1F1FF, 0xE0020...0xE007F, 0xFE00...0xFE0F, 0x1F900...0x1F9FF, 0x1F018...0x1F0F5, 0x1F200...0x1F270, 65024...65039, 9100...9300, 8400...8447, 0x1F004, 0x1F18E, 0x1F191...0x1F19A, 0x1F5E8, 0x1FA70...0x1FA73, 0x1FA78...0x1FA7A, 0x1FA80...0x1FA82, 0x1FA90...0x1FA95, 0x1FAE0, 0x1FAF1, 0x1FAF2, 0x1F382: + case 0x1F600...0x1F64F, 0x1F300...0x1F5FF, 0x1F680...0x1F6FF, 0x1F1E6...0x1F1FF, 0xE0020...0xE007F, 0xFE00...0xFE0F, 0x1F900...0x1F9FF, 0x1F018...0x1F0F5, 0x1F200...0x1F270, 65024...65039, 9100...9300, 8400...8447, 0x1F004, 0x1F18E, 0x1F191...0x1F19A, 0x1F5E8, 0x1FA70...0x1FA73, 0x1FA78...0x1FA7A, 0x1FA80...0x1FA82, 0x1FA90...0x1FA95, 0x1FAE0, 0x1FAF0...0x1FAF6, 0x1F382: return true case 0x2603, 0x265F, 0x267E, 0x2692, 0x26C4, 0x26C8, 0x26CE, 0x26CF, 0x26D1...0x26D3, 0x26E9, 0x26F0...0x26F9, 0x2705, 0x270A, 0x270B, 0x2728, 0x274E, 0x2753...0x2755, 0x274C, 0x2795...0x2797, 0x27B0, 0x27BF: return true diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index a0fbbdd975..b2358f7a01 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -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 } diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h index 46eda2a6b7..3a155692c6 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoCaptionInputMixin.h @@ -34,6 +34,6 @@ - (void)setCaptionPanelHidden:(bool)hidden animated:(bool)animated; -- (void)updateLayoutWithFrame:(CGRect)frame edgeInsets:(UIEdgeInsets)edgeInsets; +- (void)updateLayoutWithFrame:(CGRect)frame edgeInsets:(UIEdgeInsets)edgeInsets animated:(bool)animated; @end diff --git a/submodules/LegacyComponents/Sources/TGCameraController.m b/submodules/LegacyComponents/Sources/TGCameraController.m index a5b5238c77..e17b86a3e0 100644 --- a/submodules/LegacyComponents/Sources/TGCameraController.m +++ b/submodules/LegacyComponents/Sources/TGCameraController.m @@ -2722,10 +2722,14 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus default: { - if (widescreenWidth == 926.0f) + if (widescreenWidth == 932.0f) + return CGRectMake(0, 136, screenSize.width, screenSize.height - 136 - 223); + else if (widescreenWidth == 926.0f) return CGRectMake(0, 121, screenSize.width, screenSize.height - 121 - 234); - if (widescreenWidth == 896.0f) + else if (widescreenWidth == 896.0f) return CGRectMake(0, 121, screenSize.width, screenSize.height - 121 - 223); + if (widescreenWidth == 852.0f) + return CGRectMake(0, 136, screenSize.width, screenSize.height - 136 - 192); else if (widescreenWidth == 844.0f) return CGRectMake(0, 77, screenSize.width, screenSize.height - 77 - 191); else if (widescreenWidth == 812.0f) diff --git a/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m b/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m index c71d45d351..4cee5d2451 100644 --- a/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m +++ b/submodules/LegacyComponents/Sources/TGCameraMainPhoneView.m @@ -113,7 +113,18 @@ CGFloat shutterButtonWidth = 66.0f; CGSize screenSize = TGScreenSize(); CGFloat widescreenWidth = MAX(screenSize.width, screenSize.height); - if (widescreenWidth == 926.0f) + if (widescreenWidth == 932.0f) + { + _topPanelOffset = 48.0f; + _topPanelHeight = 48.0f; + _bottomPanelOffset = 83.0f; + _bottomPanelHeight = 140.0f; + _modeControlOffset = -1.0f; + _modeControlHeight = 66.0f; + _counterOffset = 7.0f; + shutterButtonWidth = 72.0f; + } + else if (widescreenWidth == 926.0f) { _topPanelOffset = 34.0f; _topPanelHeight = 48.0f; @@ -135,6 +146,17 @@ _counterOffset = 7.0f; shutterButtonWidth = 72.0f; } + else if (widescreenWidth == 852.0f) + { + _topPanelOffset = 48.0f; + _topPanelHeight = 44.0f; + _bottomPanelOffset = 63.0f; + _bottomPanelHeight = 128.0f; + _modeControlOffset = -1.0f; + _modeControlHeight = 51.0f; + _counterOffset = 7.0f; + shutterButtonWidth = 72.0f; + } else if (widescreenWidth == 844.0f) { _topPanelOffset = 33.0f; diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m index 12ad1135ac..17f0b3a49b 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerGalleryInterfaceView.m @@ -1644,7 +1644,7 @@ UIEdgeInsets captionEdgeInsets = screenEdges; captionEdgeInsets.bottom = _portraitToolbarView.frame.size.height; - [_captionMixin updateLayoutWithFrame:self.bounds edgeInsets:captionEdgeInsets]; + [_captionMixin updateLayoutWithFrame:self.bounds edgeInsets:captionEdgeInsets animated:false]; switch (orientation) { diff --git a/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m b/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m index 14eef45878..9a7b02a269 100644 --- a/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m +++ b/submodules/LegacyComponents/Sources/TGMediaPickerLayoutMetrics.m @@ -51,7 +51,16 @@ CGSize itemSize = TGPhotoThumbnailSizeForCurrentScreen(); if ([UIScreen mainScreen].scale >= 2.0f - FLT_EPSILON) { - if (widescreenWidth >= 844.0f - FLT_EPSILON) + if (widescreenWidth >= 852.0f - FLT_EPSILON) + { + metrics->_normalItemSize = itemSize; + metrics->_wideItemSize = itemSize; + metrics->_normalEdgeInsets = UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); + metrics->_wideEdgeInsets = UIEdgeInsetsMake(2.0f, 2.0f, 1.0f, 2.0f); + metrics->_normalLineSpacing = 2.0f; + metrics->_wideLineSpacing = 2.0f; + } + else if (widescreenWidth >= 844.0f - FLT_EPSILON) { metrics->_normalItemSize = itemSize; metrics->_wideItemSize = itemSize; diff --git a/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m b/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m index 4014752b9c..d87e86069e 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m +++ b/submodules/LegacyComponents/Sources/TGPhotoCaptionInputMixin.m @@ -84,7 +84,7 @@ _inputPanel.heightUpdated = ^(BOOL animated) { __strong TGPhotoCaptionInputMixin *strongSelf = weakSelf; - [strongSelf updateLayoutWithFrame:strongSelf->_currentFrame edgeInsets:strongSelf->_currentEdgeInsets]; + [strongSelf updateLayoutWithFrame:strongSelf->_currentFrame edgeInsets:strongSelf->_currentEdgeInsets animated:animated]; }; _inputPanelView = inputPanel.view; @@ -219,7 +219,7 @@ self.keyboardHeightChanged(keyboardHeight, duration, curve); } -- (void)updateLayoutWithFrame:(CGRect)frame edgeInsets:(UIEdgeInsets)edgeInsets +- (void)updateLayoutWithFrame:(CGRect)frame edgeInsets:(UIEdgeInsets)edgeInsets animated:(bool)animated { _currentFrame = frame; _currentEdgeInsets = edgeInsets; @@ -233,13 +233,20 @@ y = edgeInsets.top + frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight); } - _inputPanelView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, panelHeight); - CGFloat backgroundHeight = panelHeight; if (_keyboardHeight > 0.0) { backgroundHeight += _keyboardHeight - edgeInsets.bottom; } - _backgroundView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, backgroundHeight + 1.0); + + if (animated) { + [UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ + _inputPanelView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, panelHeight); + _backgroundView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, backgroundHeight + 1.0); + } completion:nil]; + } else { + _inputPanelView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, panelHeight); + _backgroundView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, backgroundHeight + 1.0); + } } @end diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m b/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m index 86298a2ac5..c2dfab89a4 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorUtils.m @@ -24,14 +24,22 @@ CGSize TGPhotoThumbnailSizeForCurrentScreen() if ([UIScreen mainScreen].scale >= 2.0f - FLT_EPSILON) { - if (widescreenWidth >= 926.0f - FLT_EPSILON) + if (widescreenWidth >= 932.0f - FLT_EPSILON) { return CGSizeMake(141.0f + TGScreenPixel, 141.0 + TGScreenPixel); } - if (widescreenWidth >= 896.0f - FLT_EPSILON) + else if (widescreenWidth >= 926.0f - FLT_EPSILON) + { + return CGSizeMake(141.0f + TGScreenPixel, 141.0 + TGScreenPixel); + } + else if (widescreenWidth >= 896.0f - FLT_EPSILON) { return CGSizeMake(137.0f - TGScreenPixel, 137.0f - TGScreenPixel); } + else if (widescreenWidth >= 852.0f - FLT_EPSILON) + { + return CGSizeMake(129.0f - TGScreenPixel, 129.0f - TGScreenPixel); + } else if (widescreenWidth >= 844.0f - FLT_EPSILON) { return CGSizeMake(129.0f - TGScreenPixel, 129.0f - TGScreenPixel); diff --git a/submodules/LegacyComponents/Sources/TGViewController.mm b/submodules/LegacyComponents/Sources/TGViewController.mm index 13b9029bf0..a8cf5f5ca7 100644 --- a/submodules/LegacyComponents/Sources/TGViewController.mm +++ b/submodules/LegacyComponents/Sources/TGViewController.mm @@ -1117,7 +1117,7 @@ static id _defaultContext = nil; + (UIEdgeInsets)safeAreaInsetForOrientation:(UIInterfaceOrientation)orientation hasOnScreenNavigation:(bool)hasOnScreenNavigation { int height = (int)TGScreenSize().height; - if (!TGIsPad() && (height != 812 && height != 896 && height != 780 && height != 844 && height != 926) && !hasOnScreenNavigation) + if (!TGIsPad() && (height != 812 && height != 896 && height != 780 && height != 844 && height != 852 && height != 926 && height != 932) && !hasOnScreenNavigation) return UIEdgeInsetsZero; if (TGIsPad()) { diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 2b59f47be8..907e9d6b15 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -25,6 +25,137 @@ import AnimationCache import MultiAnimationRenderer public enum PremiumSource: Equatable { + public static func == (lhs: PremiumSource, rhs: PremiumSource) -> Bool { + switch lhs { + case .settings: + if case .settings = rhs { + return true + } else { + return false + } + case .stickers: + if case .stickers = rhs { + return true + } else { + return false + } + case .reactions: + if case .reactions = rhs { + return true + } else { + return false + } + case .ads: + if case .ads = rhs { + return true + } else { + return false + } + case .upload: + if case .upload = rhs { + return true + } else { + return false + } + case .groupsAndChannels: + if case .groupsAndChannels = rhs { + return true + } else { + return false + } + case .pinnedChats: + if case .pinnedChats = rhs { + return true + } else { + return false + } + case .publicLinks: + if case .publicLinks = rhs { + return true + } else { + return false + } + case .savedGifs: + if case .savedGifs = rhs { + return true + } else { + return false + } + case .savedStickers: + if case .savedStickers = rhs { + return true + } else { + return false + } + case .folders: + if case .folders = rhs { + return true + } else { + return false + } + case .chatsPerFolder: + if case .chatsPerFolder = rhs { + return true + } else { + return false + } + case .accounts: + if case .accounts = rhs { + return true + } else { + return false + } + case .about: + if case .about = rhs { + return true + } else { + return false + } + case .appIcons: + if case .appIcons = rhs { + return true + } else { + return false + } + case .animatedEmoji: + if case .animatedEmoji = rhs { + return true + } else { + return false + } + case let .deeplink(link): + if case .deeplink(link) = rhs { + return true + } else { + return false + } + case let .profile(peerId): + if case .profile(peerId) = rhs { + return true + } else { + return false + } + case let .emojiStatus(lhsPeerId, lhsFileId, lhsFile, _): + if case let .emojiStatus(rhsPeerId, rhsFileId, rhsFile, _) = rhs { + return lhsPeerId == rhsPeerId && lhsFileId == rhsFileId && lhsFile == rhsFile + } else { + return false + } + case let .gift(from, to, duration): + if case .gift(from, to, duration) = rhs { + return true + } else { + return false + } + case .giftTerms: + if case .giftTerms = rhs { + return true + } else { + return false + } + } + } + case settings case stickers case reactions @@ -43,7 +174,7 @@ public enum PremiumSource: Equatable { case animatedEmoji case deeplink(String?) case profile(PeerId) - case emojiStatus(PeerId, Int64, TelegramMediaFile?, String?) + case emojiStatus(PeerId, Int64, TelegramMediaFile?, LoadedStickerPack?) case gift(from: PeerId, to: PeerId, duration: Int32) case giftTerms @@ -1873,10 +2004,10 @@ private final class PremiumIntroScreenComponent: CombinedComponent { } }) - if case let .emojiStatus(_, emojiFileId, emojiFile, emojiPackTitle) = source { + if case let .emojiStatus(_, emojiFileId, emojiFile, maybeEmojiPack) = source, let emojiPack = maybeEmojiPack, case let .result(info, _, _) = emojiPack { if let emojiFile = emojiFile { self.emojiFile = emojiFile - self.emojiPackTitle = emojiPackTitle + self.emojiPackTitle = info.title self.updated(transition: .immediate) } else { self.emojiFileDisposable = (context.engine.stickers.resolveInlineStickers(fileIds: [emojiFileId]) @@ -2124,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, emojiPackTitle) = context.component.source { + if case let .emojiStatus(_, _, file, maybeEmojiPack) = context.component.source, let emojiPack = maybeEmojiPack, case let .result(info, _, _) = emojiPack { + loadedEmojiPack = maybeEmojiPack highlightableLinks = true var packReference: StickerPackReference? @@ -2141,7 +2274,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent { if let packReference = packReference, case let .id(id, _) = packReference, id == 773947703670341676 { secondaryTitleText = environment.strings.Premium_EmojiStatusShortTitle(otherPeerName).string } else { - secondaryTitleText = environment.strings.Premium_EmojiStatusTitle(otherPeerName, emojiPackTitle ?? "").string.replacingOccurrences(of: "#", with: " # ") + secondaryTitleText = environment.strings.Premium_EmojiStatusTitle(otherPeerName, info.title).string.replacingOccurrences(of: "#", with: " # ") } } else if case .profile = context.component.source { secondaryTitleText = environment.strings.Premium_PersonalTitle(otherPeerName).string @@ -2206,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], 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) diff --git a/submodules/SearchPeerMembers/BUILD b/submodules/SearchPeerMembers/BUILD index 2ba9d1ef0e..2dfde4f9ac 100644 --- a/submodules/SearchPeerMembers/BUILD +++ b/submodules/SearchPeerMembers/BUILD @@ -14,6 +14,7 @@ swift_library( "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", "//submodules/AccountContext:AccountContext", + "//submodules/StringTransliteration:StringTransliteration", ], visibility = [ "//visibility:public", diff --git a/submodules/SearchPeerMembers/Sources/SearchPeerMembers.swift b/submodules/SearchPeerMembers/Sources/SearchPeerMembers.swift index 4b85ba3552..25645782d0 100644 --- a/submodules/SearchPeerMembers/Sources/SearchPeerMembers.swift +++ b/submodules/SearchPeerMembers/Sources/SearchPeerMembers.swift @@ -2,6 +2,7 @@ import Foundation import TelegramCore import SwiftSignalKit import AccountContext +import StringTransliteration public enum SearchPeerMembersScope { case memberSuggestion @@ -9,6 +10,9 @@ public enum SearchPeerMembersScope { } public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, chatLocation: ChatLocation, query: String, scope: SearchPeerMembersScope) -> Signal<[EnginePeer], NoError> { + let normalizedQuery = query.lowercased() + let transformedQuery = postboxTransformedString(normalizedQuery as NSString, true, false) ?? normalizedQuery + if peerId.namespace == Namespaces.Peer.CloudChannel { return context.engine.data.get( TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: peerId) @@ -18,21 +22,17 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch return Signal { subscriber in let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.recent(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, searchQuery: nil, requestUpdate: false, updated: { state in if case .ready = state.loadingState { - let normalizedQuery = query.lowercased() subscriber.putNext((state.list.compactMap { participant -> EnginePeer? in if participant.peer.isDeleted { return nil } - if normalizedQuery.isEmpty { - return EnginePeer(participant.peer) - } if normalizedQuery.isEmpty { return EnginePeer(participant.peer) } else { - if participant.peer.indexName.matchesByTokens(normalizedQuery) { + if participant.peer.indexName.matchesByTokens(normalizedQuery) || participant.peer.indexName.matchesByTokens(transformedQuery) { return EnginePeer(participant.peer) } - if let addressName = participant.peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { + if let addressName = participant.peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) || addressName.lowercased().hasPrefix(transformedQuery) { return EnginePeer(participant.peer) } @@ -52,7 +52,7 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch return Signal { subscriber in switch chatLocation { case let .peer(peerId): - let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.recent(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, searchQuery: query.isEmpty ? nil : query, updated: { state in + let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.recent(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, searchQuery: normalizedQuery.isEmpty ? nil : normalizedQuery, updated: { state in if case .ready = state.loadingState { subscriber.putNext((state.list.compactMap { participant in if participant.peer.isDeleted { @@ -67,7 +67,7 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch disposable.dispose() } case let .replyThread(replyThreadMessage): - let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.mentions(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, threadMessageId: replyThreadMessage.messageId, searchQuery: query.isEmpty ? nil : query, updated: { state in + let (disposable, _) = context.peerChannelMemberCategoriesContextsManager.mentions(engine: context.engine, postbox: context.account.postbox, network: context.account.network, accountPeerId: context.account.peerId, peerId: peerId, threadMessageId: replyThreadMessage.messageId, searchQuery: normalizedQuery.isEmpty ? nil : normalizedQuery, updated: { state in if case .ready = state.loadingState { subscriber.putNext((state.list.compactMap { participant in if participant.peer.isDeleted { @@ -99,17 +99,16 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch ) |> map { peer -> [EnginePeer] in var result = result - let normalizedQuery = query.lowercased() if isReady { if case let .channel(channel) = peer, case .group = channel.info { var matches = false if normalizedQuery.isEmpty { matches = true } else { - if channel.indexName.matchesByTokens(normalizedQuery) { + if channel.indexName.matchesByTokens(normalizedQuery) || channel.indexName.matchesByTokens(transformedQuery) { matches = true } - if let addressName = channel.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { + if let addressName = channel.addressName, addressName.lowercased().hasPrefix(normalizedQuery) || addressName.lowercased().hasPrefix(transformedQuery) { matches = true } } @@ -123,9 +122,29 @@ public func searchPeerMembers(context: AccountContext, peerId: EnginePeer.Id, ch } } } else { - return context.engine.peers.searchGroupMembers(peerId: peerId, query: query) - |> map { peers -> [EnginePeer] in - return peers.map(EnginePeer.init) + let transliteratedPeers: Signal<[EnginePeer], NoError> + if transformedQuery != normalizedQuery { + transliteratedPeers = context.engine.peers.searchGroupMembers(peerId: peerId, query: transformedQuery) + } else { + transliteratedPeers = .single([]) + } + + return combineLatest( + context.engine.peers.searchGroupMembers(peerId: peerId, query: normalizedQuery), + transliteratedPeers + ) + |> map { peers, transliteratedPeers -> [EnginePeer] in + var existingPeerIds = Set() + var result = peers + for peer in peers { + existingPeerIds.insert(peer.id) + } + for peer in transliteratedPeers { + if !existingPeerIds.contains(peer.id) { + result.append(peer) + } + } + return result } } } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift index 85fbd1e7f3..a868b85e56 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsThemeItem.swift @@ -178,6 +178,11 @@ private func createThemeImage(theme: PresentationTheme) -> Signal<(TransformImag context.withContext { c in c.clear(CGRect(origin: CGPoint(), size: drawingRect.size)) + c.setFillColor(theme.list.plainBackgroundColor.cgColor) + let path = UIBezierPath(roundedRect: drawingRect, cornerRadius: arguments.corners.topLeft.radius) + c.addPath(path.cgPath) + c.fillPath() + c.translateBy(x: drawingRect.width / 2.0, y: drawingRect.height / 2.0) c.scaleBy(x: 1.0, y: -1.0) c.translateBy(x: -drawingRect.width / 2.0, y: -drawingRect.height / 2.0) @@ -287,7 +292,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { strongSelf.containerNode.isGestureEnabled = true } if updatedTheme || updatedSelected { - strongSelf.overlayNode.image = generateBorderImage(theme: item.theme, bordered: true, selected: item.selected) + strongSelf.overlayNode.image = generateBorderImage(theme: item.theme, bordered: false, selected: item.selected) } strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: itemLayout.contentSize) diff --git a/submodules/ShareController/Sources/ShareInputFieldNode.swift b/submodules/ShareController/Sources/ShareInputFieldNode.swift index 47de1c6bc3..5ad9bf6393 100644 --- a/submodules/ShareController/Sources/ShareInputFieldNode.swift +++ b/submodules/ShareController/Sources/ShareInputFieldNode.swift @@ -66,7 +66,7 @@ public final class ShareInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegat public var updateText: ((String) -> Void)? private let backgroundInsets = UIEdgeInsets(top: 16.0, left: 16.0, bottom: 1.0, right: 16.0) - private let inputInsets = UIEdgeInsets(top: 10.0, left: 8.0, bottom: 10.0, right: 16.0) + private let inputInsets = UIEdgeInsets(top: 10.0, left: 8.0, bottom: 10.0, right: 22.0) private let accessoryButtonsWidth: CGFloat = 10.0 private var selectTextOnce: Bool = false diff --git a/submodules/ShareController/Sources/ShareSearchBarNode.swift b/submodules/ShareController/Sources/ShareSearchBarNode.swift index f86602ab93..7c5825a231 100644 --- a/submodules/ShareController/Sources/ShareSearchBarNode.swift +++ b/submodules/ShareController/Sources/ShareSearchBarNode.swift @@ -99,6 +99,11 @@ final class ShareSearchBarNode: ASDisplayNode, UITextFieldDelegate { self.textUpdated?(self.textInputNode.textField.text ?? "") } + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.deactivateInput() + return true + } + @objc func clearPressed() { self.textInputNode.textField.text = "" self.textFieldDidChangeText() diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift index f7536d1786..bab1ec6d9e 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift @@ -151,6 +151,7 @@ private final class StickerPackContainer: ASDisplayNode { context: AccountContext, presentationData: PresentationData, stickerPacks: [StickerPackReference], + loadedStickerPacks: [LoadedStickerPack], decideNextAction: @escaping (StickerPackContainer, StickerPackAction) -> StickerPackNextAction, requestDismiss: @escaping () -> Void, expandProgressUpdated: @escaping (StickerPackContainer, ContainedViewLayoutTransition, ContainedViewLayoutTransition) -> Void, @@ -343,11 +344,18 @@ private final class StickerPackContainer: ASDisplayNode { return updatedOffset } - let loadedStickerPacks = combineLatest(stickerPacks.map { - context.engine.stickers.loadedStickerPack(reference: $0, forceActualized: true) + + + let fetchedStickerPacks: Signal<[LoadedStickerPack], NoError> = combineLatest(stickerPacks.map { packReference in + for pack in loadedStickerPacks { + if case let .result(info, _, _) = pack, case let .id(id, _) = packReference, info.id.id == id { + return .single(pack) + } + } + return context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: true) }) - self.itemsDisposable = combineLatest(queue: Queue.mainQueue(), loadedStickerPacks, context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))).start(next: { [weak self] contents, peer in + self.itemsDisposable = combineLatest(queue: Queue.mainQueue(), fetchedStickerPacks, context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))).start(next: { [weak self] contents, peer in guard let strongSelf = self else { return } @@ -1332,7 +1340,7 @@ private final class StickerPackScreenNode: ViewControllerTracingNode { wasAdded = true containerTransition = .immediate let index = i - container = StickerPackContainer(index: index, context: context, presentationData: self.presentationData, stickerPacks: self.stickerPacks, decideNextAction: { [weak self] container, action in + container = StickerPackContainer(index: index, context: self.context, presentationData: self.presentationData, stickerPacks: self.stickerPacks, loadedStickerPacks: self.controller?.loadedStickerPacks ?? [], decideNextAction: { [weak self] container, action in guard let strongSelf = self, let layout = strongSelf.validLayout else { return .dismiss } @@ -1570,6 +1578,8 @@ public final class StickerPackScreenImpl: ViewController { private var presentationDataDisposable: Disposable? private let stickerPacks: [StickerPackReference] + fileprivate let loadedStickerPacks: [LoadedStickerPack] + private let initialSelectedStickerPackIndex: Int fileprivate weak var parentNavigationController: NavigationController? private let sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? @@ -1599,6 +1609,7 @@ public final class StickerPackScreenImpl: ViewController { context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)? = nil, stickerPacks: [StickerPackReference], + loadedStickerPacks: [LoadedStickerPack], selectedStickerPackIndex: Int = 0, parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, @@ -1608,6 +1619,7 @@ public final class StickerPackScreenImpl: ViewController { self.context = context self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 } self.stickerPacks = stickerPacks + self.loadedStickerPacks = loadedStickerPacks self.initialSelectedStickerPackIndex = selectedStickerPackIndex self.parentNavigationController = parentNavigationController self.sendSticker = sendSticker @@ -1820,6 +1832,7 @@ public func StickerPackScreen( mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], + loadedStickerPacks: [LoadedStickerPack] = [], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)? = nil, @@ -1829,6 +1842,7 @@ public func StickerPackScreen( let controller = StickerPackScreenImpl( context: context, stickerPacks: stickerPacks, + loadedStickerPacks: loadedStickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker, diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index f06c780fc8..97804e68c3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -242,8 +242,11 @@ public extension TelegramEngine { return _internal_updateChannelOwnership(account: self.account, accountStateManager: self.account.stateManager, channelId: channelId, memberId: memberId, password: password) } - public func searchGroupMembers(peerId: PeerId, query: String) -> Signal<[Peer], NoError> { + public func searchGroupMembers(peerId: PeerId, query: String) -> Signal<[EnginePeer], NoError> { return _internal_searchGroupMembers(postbox: self.account.postbox, network: self.account.network, accountPeerId: self.account.peerId, peerId: peerId, query: query) + |> map { peers -> [EnginePeer] in + return peers.map { EnginePeer($0) } + } } public func toggleShouldChannelMessagesSignatures(peerId: PeerId, enabled: Bool) -> Signal { diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index 854e2ea5e2..154fa5571c 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -56,6 +56,12 @@ public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, edit if accentColor.rgb == 0xffffff { monochrome = true bubbleColors = [UIColor(rgb: 0x313131).rgb, UIColor(rgb: 0x313131).rgb] + } else if accentColor.rgb == 0x3e88f7 { + bubbleColors = [ + 0x0771ff, + 0x9047ff, + 0xa256bf, + ] } else { bubbleColors = [accentColor.withMultiplied(hue: 0.966, saturation: 0.61, brightness: 0.98).rgb, accentColor.rgb] } @@ -312,10 +318,10 @@ public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, edit } public let defaultDarkWallpaperGradientColors: [UIColor] = [ - UIColor(rgb: 0x00b3dd), - UIColor(rgb: 0x3b59f2), - UIColor(rgb: 0x358be2), - UIColor(rgb: 0xa434cf) + UIColor(rgb: 0x598bf6), + UIColor(rgb: 0x7a5eef), + UIColor(rgb: 0xd67cff), + UIColor(rgb: 0xf38b58) ] public func makeDefaultDarkPresentationTheme(extendingThemeReference: PresentationThemeReference? = nil, preview: Bool) -> PresentationTheme { @@ -675,7 +681,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati badgeTextColor: UIColor(rgb: 0x000000) ) - let defaultPatternWallpaper: TelegramWallpaper = defaultBuiltinWallpaper(data: .default, colors: defaultDarkWallpaperGradientColors.map(\.rgb), intensity: -35) + let defaultPatternWallpaper: TelegramWallpaper = defaultBuiltinWallpaper(data: .default, colors: defaultDarkWallpaperGradientColors.map(\.rgb), intensity: -34) let chat = PresentationThemeChat( defaultWallpaper: defaultPatternWallpaper, diff --git a/submodules/TelegramPresentationData/Sources/PresentationData.swift b/submodules/TelegramPresentationData/Sources/PresentationData.swift index 8ee1dda8b7..15b333c5c7 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationData.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationData.swift @@ -309,7 +309,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager 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: diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/Contents.json new file mode 100644 index 0000000000..248b5e5859 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "phonecall_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/phonecall_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/phonecall_24.pdf new file mode 100644 index 0000000000..bb3744733a --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/PhoneCall.imageset/phonecall_24.pdf @@ -0,0 +1,424 @@ +%PDF-1.7 + +1 0 obj + << /Type /XObject + /Length 2 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 24.000000 24.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +1.000000 0.000000 -0.000000 1.000000 4.500000 1.839966 cm +2.336997 17.660034 m +2.662117 17.660034 2.919991 17.531717 3.113886 17.260115 c +4.585419 14.879068 l +4.920160 14.337935 4.887798 13.646688 4.503964 13.139196 c +3.449515 11.745041 l +3.304240 11.606829 3.209649 11.367731 3.209649 11.106469 c +3.209649 10.919914 3.258480 10.760313 3.345299 10.569205 c +3.613995 10.003538 4.318002 9.122787 5.191207 8.228218 c +5.368025 8.049210 l +6.244456 7.163609 7.244257 6.357477 7.850526 6.038754 c +8.070224 5.937879 8.234513 5.889532 8.432807 5.889532 c +8.701159 5.889532 8.948185 5.981611 9.144370 6.177905 c +10.453788 7.178677 l +10.962485 7.569689 11.660256 7.604506 12.205351 7.266076 c +14.664220 5.739452 l +14.893296 5.579560 15.000061 5.360890 15.000061 5.068824 c +15.000061 4.668618 14.761724 4.178541 14.364333 3.757545 c +13.671964 3.012113 12.839583 2.659973 11.811339 2.659973 c +9.637396 2.659973 6.759635 4.298767 4.190047 6.869761 c +1.619593 9.441620 0.000000 12.297401 0.000000 14.478063 c +0.000000 15.496849 0.341778 16.351761 1.049306 17.037554 c +1.462726 17.444048 1.928928 17.660034 2.336997 17.660034 c +h +0.000000 0.000000 0.000000 scn +f +n + +endstream +endobj + +2 0 obj + 1177 +endobj + +3 0 obj + << /Length 4 0 R + /FunctionType 4 + /Domain [ 0.000000 1.000000 ] + /Range [ 0.000000 1.000000 ] + >> +stream +{ 0 gt { 0 } { 1 } ifelse } +endstream +endobj + +4 0 obj + 27 +endobj + +5 0 obj + << /ExtGState << /E1 << /SMask << /Type /Mask + /G 1 0 R + /S /Alpha + /TR 3 0 R + >> + /Type /ExtGState + >> >> >> +endobj + +6 0 obj + << /Length 7 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +/E1 gs +q +1.000000 0.000000 -0.000000 1.000000 4.500000 1.839966 cm +0.000000 0.000000 0.000000 scn +3.113886 17.260115 m +4.245259 17.959326 l +4.222027 17.996916 l +4.196352 18.032883 l +3.113886 17.260115 l +h +4.585419 14.879068 m +3.454046 14.179857 l +3.454337 14.179388 l +4.585419 14.879068 l +h +4.503964 13.139196 m +3.443199 13.941491 l +3.443199 13.941490 l +4.503964 13.139196 l +h +3.449515 11.745041 m +4.366253 10.781459 l +4.444844 10.856229 l +4.510280 10.942745 l +3.449515 11.745041 l +h +3.345299 10.569205 m +2.134399 10.019096 l +2.139083 10.008785 l +2.143943 9.998554 l +3.345299 10.569205 l +h +5.191207 8.228218 m +4.239443 7.299183 l +4.244984 7.293574 l +5.191207 8.228218 l +h +5.368025 8.049210 m +4.421801 7.114565 l +4.422691 7.113666 l +5.368025 8.049210 l +h +7.850526 6.038754 m +7.231641 4.861520 l +7.263175 4.844942 l +7.295551 4.830077 l +7.850526 6.038754 l +h +9.144370 6.177905 m +8.336740 7.234614 l +8.266318 7.180791 l +8.203662 7.118100 l +9.144370 6.177905 l +h +10.453788 7.178677 m +11.261421 6.121964 l +11.264320 6.124193 l +10.453788 7.178677 l +h +12.205351 7.266076 m +12.906886 8.396009 l +12.906886 8.396009 l +12.205351 7.266076 l +h +14.664220 5.739452 m +15.425447 6.830063 l +15.396130 6.850527 l +15.365755 6.869386 l +14.664220 5.739452 l +h +14.364333 3.757545 m +13.397125 4.670519 l +13.389837 4.662673 l +14.364333 3.757545 l +h +4.190047 6.869761 m +5.130756 7.809957 l +5.130756 7.809957 l +4.190047 6.869761 l +h +1.049306 17.037554 m +1.974998 16.082523 l +1.981782 16.089191 l +1.049306 17.037554 l +h +2.336997 16.330034 m +2.320346 16.330034 2.253638 16.334621 2.169936 16.377350 c +2.085590 16.420408 2.041937 16.472618 2.031421 16.487349 c +4.196352 18.032883 l +3.748895 18.659664 3.084965 18.990034 2.336997 18.990034 c +2.336997 16.330034 l +h +1.982513 16.560905 m +3.454046 14.179857 l +5.716792 15.578279 l +4.245259 17.959326 l +1.982513 16.560905 l +h +3.454337 14.179388 m +3.500106 14.105397 3.495682 14.010881 3.443199 13.941491 c +5.564729 12.336901 l +6.279915 13.282494 6.340214 14.570473 5.716501 15.578749 c +3.454337 14.179388 l +h +3.443199 13.941490 m +2.388749 12.547336 l +4.510280 10.942745 l +5.564729 12.336901 l +3.443199 13.941490 l +h +2.532776 12.708622 m +2.068971 12.267365 1.879649 11.648950 1.879649 11.106469 c +4.539649 11.106469 l +4.539649 11.079510 4.535252 11.043770 4.517922 10.998292 c +4.502114 10.956808 4.462042 10.872591 4.366253 10.781459 c +2.532776 12.708622 l +h +1.879649 11.106469 m +1.879649 10.656174 2.006887 10.299776 2.134399 10.019096 c +4.556200 11.119314 l +4.543678 11.146877 4.536608 11.164371 4.532750 11.174656 c +4.529046 11.184531 4.529113 11.185631 4.530626 11.179913 c +4.532265 11.173723 4.534810 11.162544 4.536798 11.147743 c +4.538805 11.132805 4.539649 11.118605 4.539649 11.106469 c +1.879649 11.106469 l +h +2.143943 9.998554 m +2.513995 9.219506 3.354690 8.205615 4.239460 7.299199 c +6.142955 9.157238 l +5.281314 10.039959 4.713994 10.787569 4.546656 11.139856 c +2.143943 9.998554 l +h +4.244984 7.293574 m +4.421802 7.114566 l +6.314249 8.983854 l +6.137431 9.162863 l +4.244984 7.293574 l +h +4.422691 7.113666 m +5.333439 6.193388 6.446281 5.274392 7.231641 4.861520 c +8.469412 7.215989 l +8.042233 7.440562 7.155473 8.133829 6.313359 8.984755 c +4.422691 7.113666 l +h +7.295551 4.830077 m +7.610502 4.685464 7.971885 4.559532 8.432807 4.559532 c +8.432807 7.219532 l +8.438139 7.219532 8.448376 7.219153 8.461496 7.217438 c +8.474616 7.215722 8.484693 7.213446 8.489946 7.212055 c +8.494530 7.210842 8.491272 7.211398 8.477601 7.216578 c +8.463371 7.221971 8.440556 7.231338 8.405501 7.247433 c +7.295551 4.830077 l +h +8.432807 4.559532 m +9.024679 4.559532 9.619445 4.771820 10.085079 5.237710 c +8.203662 7.118100 l +8.232141 7.146595 8.273987 7.176050 8.325019 7.196304 c +8.374480 7.215935 8.413715 7.219532 8.432807 7.219532 c +8.432807 4.559532 l +h +9.952001 5.121196 m +11.261418 6.121968 l +9.646158 8.235386 l +8.336740 7.234614 l +9.952001 5.121196 l +h +11.264320 6.124193 m +11.333877 6.177657 11.429284 6.182418 11.503816 6.136144 c +12.906886 8.396009 l +11.891228 9.026595 10.591094 8.961720 9.643255 8.233161 c +11.264320 6.124193 l +h +11.503816 6.136144 m +13.962685 4.609520 l +15.365755 6.869386 l +12.906886 8.396009 l +11.503816 6.136144 l +h +13.902991 4.648842 m +13.857372 4.680683 13.782755 4.749804 13.727364 4.861100 c +13.674102 4.968115 13.670061 5.050985 13.670061 5.068824 c +16.330061 5.068824 l +16.330061 5.757030 16.041370 6.400160 15.425447 6.830063 c +13.902991 4.648842 l +h +13.670061 5.068824 m +13.670061 5.122084 13.682167 5.099532 13.634643 5.001590 c +13.590631 4.910884 13.513090 4.793310 13.397157 4.670489 c +15.331510 2.844599 l +15.856868 3.401164 16.330061 4.202022 16.330061 5.068824 c +13.670061 5.068824 l +h +13.389837 4.662673 m +12.957663 4.197376 12.482564 3.989973 11.811339 3.989973 c +11.811339 1.329973 l +13.196602 1.329973 14.386265 1.826848 15.338829 2.852416 c +13.389837 4.662673 l +h +11.811339 3.989973 m +11.034931 3.989973 10.000110 4.292040 8.796299 4.962632 c +7.609632 5.623674 6.344436 6.595613 5.130756 7.809957 c +3.249338 5.929566 l +4.605247 4.572916 6.063725 3.439960 7.501822 2.638857 c +8.922773 1.847304 10.413804 1.329973 11.811339 1.329973 c +11.811339 3.989973 l +h +5.130756 7.809957 m +3.916355 9.025021 2.949746 10.284932 2.293909 11.466198 c +1.629269 12.663321 1.330000 13.695452 1.330000 14.478063 c +-1.330000 14.478063 l +-1.330000 13.080011 -0.819472 11.593922 -0.031702 10.175023 c +0.764871 8.740269 1.893285 7.286361 3.249338 5.929566 c +5.130756 7.809957 l +h +1.330000 14.478063 m +1.330000 15.163555 1.544419 15.665218 1.974975 16.082546 c +0.123637 17.992559 l +-0.860863 17.038303 -1.330000 15.830142 -1.330000 14.478063 c +1.330000 14.478063 l +h +1.981782 16.089191 m +2.096122 16.201618 2.197214 16.267076 2.268798 16.301296 c +2.342271 16.336422 2.365401 16.330034 2.336997 16.330034 c +2.336997 18.990034 l +1.477759 18.990034 0.695014 18.554413 0.116830 17.985914 c +1.981782 16.089191 l +h +f +n +Q +Q +q +1.000000 0.000000 -0.000000 1.000000 13.000000 13.000000 cm +0.000000 0.000000 0.000000 scn +1.000000 6.000000 m +1.552285 6.000000 2.000000 6.447715 2.000000 7.000000 c +2.000000 7.552285 1.552285 8.000000 1.000000 8.000000 c +0.447715 8.000000 0.000000 7.552285 0.000000 7.000000 c +0.000000 6.447715 0.447715 6.000000 1.000000 6.000000 c +h +5.000000 7.000000 m +5.000000 6.447715 4.552284 6.000000 4.000000 6.000000 c +3.447716 6.000000 3.000000 6.447715 3.000000 7.000000 c +3.000000 7.552285 3.447716 8.000000 4.000000 8.000000 c +4.552284 8.000000 5.000000 7.552285 5.000000 7.000000 c +h +8.000000 7.000000 m +8.000000 6.447715 7.552284 6.000000 7.000000 6.000000 c +6.447716 6.000000 6.000000 6.447715 6.000000 7.000000 c +6.000000 7.552285 6.447716 8.000000 7.000000 8.000000 c +7.552284 8.000000 8.000000 7.552285 8.000000 7.000000 c +h +8.000000 4.000000 m +8.000000 3.447715 7.552284 3.000000 7.000000 3.000000 c +6.447716 3.000000 6.000000 3.447715 6.000000 4.000000 c +6.000000 4.552285 6.447716 5.000000 7.000000 5.000000 c +7.552284 5.000000 8.000000 4.552285 8.000000 4.000000 c +h +4.000000 3.000000 m +4.552284 3.000000 5.000000 3.447715 5.000000 4.000000 c +5.000000 4.552285 4.552284 5.000000 4.000000 5.000000 c +3.447716 5.000000 3.000000 4.552285 3.000000 4.000000 c +3.000000 3.447715 3.447716 3.000000 4.000000 3.000000 c +h +2.000000 4.000000 m +2.000000 3.447715 1.552285 3.000000 1.000000 3.000000 c +0.447715 3.000000 0.000000 3.447715 0.000000 4.000000 c +0.000000 4.552285 0.447715 5.000000 1.000000 5.000000 c +1.552285 5.000000 2.000000 4.552285 2.000000 4.000000 c +h +7.000000 0.000000 m +7.552284 0.000000 8.000000 0.447715 8.000000 1.000000 c +8.000000 1.552285 7.552284 2.000000 7.000000 2.000000 c +6.447716 2.000000 6.000000 1.552285 6.000000 1.000000 c +6.000000 0.447715 6.447716 0.000000 7.000000 0.000000 c +h +5.000000 1.000000 m +5.000000 0.447715 4.552284 0.000000 4.000000 0.000000 c +3.447716 0.000000 3.000000 0.447715 3.000000 1.000000 c +3.000000 1.552285 3.447716 2.000000 4.000000 2.000000 c +4.552284 2.000000 5.000000 1.552285 5.000000 1.000000 c +h +1.000000 0.000000 m +1.552285 0.000000 2.000000 0.447715 2.000000 1.000000 c +2.000000 1.552285 1.552285 2.000000 1.000000 2.000000 c +0.447715 2.000000 0.000000 1.552285 0.000000 1.000000 c +0.000000 0.447715 0.447715 0.000000 1.000000 0.000000 c +h +f* +n +Q + +endstream +endobj + +7 0 obj + 8188 +endobj + +8 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 5 0 R + /Contents 6 0 R + /Parent 9 0 R + >> +endobj + +9 0 obj + << /Kids [ 8 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +10 0 obj + << /Pages 9 0 R + /Type /Catalog + >> +endobj + +xref +0 11 +0000000000 65535 f +0000000010 00000 n +0000001435 00000 n +0000001458 00000 n +0000001633 00000 n +0000001654 00000 n +0000001966 00000 n +0000010210 00000 n +0000010233 00000 n +0000010406 00000 n +0000010480 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 10 0 R + /Size 11 +>> +startxref +10540 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift index e380b8dcd3..52aad3bd1a 100644 --- a/submodules/TelegramUI/Sources/ChatBotInfoItem.swift +++ b/submodules/TelegramUI/Sources/ChatBotInfoItem.swift @@ -12,6 +12,7 @@ import PhotoResources import AccountContext import UniversalMediaPlayer import TelegramUniversalVideoContent +import WallpaperBackgroundNode private let messageFont = Font.regular(17.0) private let messageBoldFont = Font.semibold(17.0) @@ -98,6 +99,11 @@ final class ChatBotInfoItemNode: ListViewItemNode { private var theme: ChatPresentationThemeData? + private var wallpaperBackgroundNode: WallpaperBackgroundNode? + private var backgroundContent: WallpaperBubbleBackgroundNode? + + private var absolutePosition: (CGRect, CGSize)? + private var item: ChatBotInfoItem? init() { @@ -145,7 +151,8 @@ final class ChatBotInfoItemNode: ListViewItemNode { videoNode.canAttachContent = true self.videoNode = videoNode - (videoNode.decoration as? VideoDecoration)?.updateCorners(ImageCorners(topLeft: .Corner(17.0), topRight: .Corner(17.0), bottomLeft: .Corner(0.0), bottomRight: .Corner(0.0))) + let cornerRadius = (self.item?.presentationData.chatBubbleCorners.mainRadius ?? 17.0) + (videoNode.decoration as? VideoDecoration)?.updateCorners(ImageCorners(topLeft: .Corner(cornerRadius), topRight: .Corner(cornerRadius), bottomLeft: .Corner(0.0), bottomRight: .Corner(0.0))) self.offsetContainer.addSubnode(videoNode) @@ -179,6 +186,18 @@ final class ChatBotInfoItemNode: ListViewItemNode { self.view.addGestureRecognizer(recognizer) } + override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + super.updateAbsoluteRect(rect, within: containerSize) + + self.absolutePosition = (rect, containerSize) + if let backgroundContent = self.backgroundContent { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += containerSize.height - rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } + } + func asyncLayout() -> (_ item: ChatBotInfoItem, _ width: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { let makeImageLayout = self.imageNode.asyncLayout() let makeTitleLayout = TextNode.asyncLayout(self.titleNode) @@ -292,6 +311,32 @@ final class ChatBotInfoItemNode: ListViewItemNode { strongSelf.titleNode.frame = titleFrame strongSelf.textNode.frame = textFrame + if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true { + if strongSelf.backgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) { + backgroundContent.clipsToBounds = true + + strongSelf.backgroundContent = backgroundContent + strongSelf.offsetContainer.insertSubnode(backgroundContent, at: 0) + } + } else { + strongSelf.backgroundContent?.removeFromSupernode() + strongSelf.backgroundContent = nil + } + + if let backgroundContent = strongSelf.backgroundContent { + strongSelf.backgroundNode.isHidden = true + backgroundContent.cornerRadius = item.presentationData.chatBubbleCorners.mainRadius + backgroundContent.frame = backgroundFrame + if let (rect, containerSize) = strongSelf.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += containerSize.height - rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } + } else { + strongSelf.backgroundNode.isHidden = false + } + strongSelf.setup(context: item.context, videoFile: item.video) if let videoNode = strongSelf.videoNode { videoNode.updateLayout(size: imageFrame.size, transition: .immediate) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 1b2cf147a8..f0ba19dfd8 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1088,6 +1088,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G allReactionsAreAvailable = false } + let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + if premiumConfiguration.isPremiumDisabled { + allReactionsAreAvailable = false + } + if allReactionsAreAvailable { actions.getEmojiContent = { animationCache, animationRenderer in guard let strongSelf = self else { diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index c67774c73c..cd06e81307 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -1385,7 +1385,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let restrictedNode = self.restrictedNode { transition.updateFrame(node: restrictedNode, frame: contentBounds) - restrictedNode.updateLayout(size: contentBounds.size, transition: transition) + restrictedNode.update(rect: contentBounds, within: contentBounds.size, transition: transition) + restrictedNode.updateLayout(backgroundNode: self.backgroundNode, size: contentBounds.size, transition: transition) } let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) @@ -1515,7 +1516,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let emptyNode = self.emptyNode, let emptyType = self.emptyType { emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, emptyType: emptyType, loadingNode: nil, backgroundNode: self.backgroundNode, size: contentBounds.size, insets: emptyNodeInsets, transition: transition) transition.updateFrame(node: emptyNode, frame: contentBounds) - emptyNode.update(rect: contentBounds, within: contentBounds.size) + emptyNode.update(rect: contentBounds, within: contentBounds.size, transition: transition) } var contentBottomInset: CGFloat = inputPanelsHeight + 4.0 diff --git a/submodules/TelegramUI/Sources/ChatEmptyNode.swift b/submodules/TelegramUI/Sources/ChatEmptyNode.swift index dbae9369c6..c6b577c852 100644 --- a/submodules/TelegramUI/Sources/ChatEmptyNode.swift +++ b/submodules/TelegramUI/Sources/ChatEmptyNode.swift @@ -954,8 +954,9 @@ final class ChatEmptyNode: ASDisplayNode { if let backgroundContent = self.backgroundContent { self.backgroundNode.isHidden = true - backgroundContent.cornerRadius = min(20.0, self.backgroundNode.bounds.height / 2.0) - backgroundContent.frame = contentFrame + backgroundContent.cornerRadius = min(20.0, self.backgroundNode.bounds.height / 2.0) + transition.updateFrame(node: backgroundContent, frame: contentFrame) + if let (rect, containerSize) = self.absolutePosition { var backgroundFrame = backgroundContent.frame backgroundFrame.origin.x += rect.minX diff --git a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift index 0a032babec..2cfe3425b4 100644 --- a/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Sources/ChatEntityKeyboardInputNode.swift @@ -2305,7 +2305,7 @@ private final class EmojiContentPeekBehaviorImpl: EmojiContentPeekBehavior { switch attribute { case let .CustomEmoji(_, _, packReference), let .Sticker(_, packReference, _): if let packReference = packReference { - let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: strongSelf.controllerInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in + let controller = strongSelf.context.sharedContext.makeStickerPackScreen(context: context, updatedPresentationData: nil, mainStickerPack: packReference, stickerPacks: [packReference], loadedStickerPacks: [], parentNavigationController: strongSelf.controllerInteraction.navigationController(), sendSticker: { file, sourceView, sourceRect in sendSticker(file, false, false, nil, false, sourceView, sourceRect, nil) return true }) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceInputNodes.swift b/submodules/TelegramUI/Sources/ChatInterfaceInputNodes.swift index a988e0bdc1..1da4d9b0ae 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceInputNodes.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceInputNodes.swift @@ -7,7 +7,7 @@ import AccountContext import ChatPresentationInterfaceState func inputNodeForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentNode: ChatInputNode?, interfaceInteraction: ChatPanelInterfaceInteraction?, inputMediaNode: ChatMediaInputNode?, controllerInteraction: ChatControllerInteraction, inputPanelNode: ChatInputPanelNode?, makeMediaInputNode: () -> ChatInputNode?) -> ChatInputNode? { - if !(inputPanelNode is ChatTextInputPanelNode) { + if let inputPanelNode = inputPanelNode, !(inputPanelNode is ChatTextInputPanelNode) { return nil } switch chatPresentationInterfaceState.inputMode { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index eb6ed053bc..c715bc4e72 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1462,6 +1462,19 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState clearCacheAsDelete = true } + + if isReplyThreadHead { + actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.SharedMedia_ViewInChat, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.actionSheet.primaryTextColor) + }, action: { c, _ in + c.dismiss(completion: { + guard let navigationController = controllerInteraction.navigationController() else { + return + } + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: messages[0].id.peerId), subject: .message(id: .id(messages[0].id), highlight: true, timecode: nil), useExisting: true)) + }) + }))) + } if !isReplyThreadHead, (!data.messageActions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty || clearCacheAsDelete) { var autoremoveDeadline: Int32? diff --git a/submodules/TelegramUI/Sources/ChatMessageActionButtonsNode.swift b/submodules/TelegramUI/Sources/ChatMessageActionButtonsNode.swift index c4f2c48a7e..58e852f280 100644 --- a/submodules/TelegramUI/Sources/ChatMessageActionButtonsNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageActionButtonsNode.swift @@ -12,7 +12,7 @@ private let titleFont = Font.medium(16.0) private final class ChatMessageActionButtonNode: ASDisplayNode { private let backgroundBlurNode: NavigationBackgroundNode - private let backgroundMaskNode: ASImageNode + private var titleNode: TextNode? private var iconNode: ASImageNode? private var buttonView: HighlightTrackingButton? @@ -35,9 +35,6 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { self.backgroundBlurNode = NavigationBackgroundNode(color: .clear) self.backgroundBlurNode.isUserInteractionEnabled = false - self.backgroundMaskNode = ASImageNode() - self.backgroundMaskNode.isUserInteractionEnabled = false - self.accessibilityArea = AccessibilityAreaNode() self.accessibilityArea.accessibilityTraits = .button @@ -159,18 +156,6 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { let messageTheme = incoming ? theme.theme.chat.message.incoming : theme.theme.chat.message.outgoing let (titleSize, titleApply) = titleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: titleFont, textColor: bubbleVariableColor(variableColor: messageTheme.actionButtonsTextColor, wallpaper: theme.wallpaper)), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(44.0, constrainedWidth - minimumSideInset - minimumSideInset), height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets(top: 1.0, left: 0.0, bottom: 1.0, right: 0.0))) - let backgroundMaskImage: UIImage? - switch position { - case .middle: - backgroundMaskImage = graphics.chatBubbleActionButtonMiddleMaskImage - case .bottomLeft: - backgroundMaskImage = graphics.chatBubbleActionButtonBottomLeftMaskImage - case .bottomRight: - backgroundMaskImage = graphics.chatBubbleActionButtonBottomRightMaskImage - case .bottomSingle: - backgroundMaskImage = graphics.chatBubbleActionButtonBottomSingleMaskImage - } - return (titleSize.size.width + sideInset + sideInset, { width in return (CGSize(width: width, height: 42.0), { animation in var animation = animation @@ -194,11 +179,8 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { node.longTapRecognizer?.isEnabled = false } - node.backgroundMaskNode.image = backgroundMaskImage - animation.animator.updateFrame(layer: node.backgroundMaskNode.layer, frame: CGRect(origin: CGPoint(), size: CGSize(width: max(0.0, width), height: 42.0)), completion: nil) - animation.animator.updateFrame(layer: node.backgroundBlurNode.layer, frame: CGRect(origin: CGPoint(), size: CGSize(width: max(0.0, width), height: 42.0)), completion: nil) - node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: bubbleCorners.auxiliaryRadius, animator: animation.animator) + node.backgroundBlurNode.update(size: node.backgroundBlurNode.bounds.size, cornerRadius: 0.0, animator: animation.animator) node.backgroundBlurNode.updateColor(color: selectDateFillStaticColor(theme: theme.theme, wallpaper: theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: theme.theme, wallpaper: theme.wallpaper), transition: .immediate) if backgroundNode?.hasExtraBubbleBackground() == true { @@ -210,7 +192,7 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { node.insertSubnode(backgroundContent, at: 0) let backgroundColorNode = ASDisplayNode() - backgroundColorNode.backgroundColor = UIColor(rgb: 0x000000, alpha: 0.4) + backgroundColorNode.backgroundColor = UIColor(rgb: 0xffffff, alpha: 0.08) backgroundContent.addSubnode(backgroundColorNode) node.backgroundColorNode = backgroundColorNode } @@ -222,10 +204,12 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { node.backgroundColorNode = nil } + node.cornerRadius = bubbleCorners.auxiliaryRadius + node.clipsToBounds = true + if let backgroundContent = node.backgroundContent { node.backgroundBlurNode.isHidden = true backgroundContent.frame = node.backgroundBlurNode.frame - backgroundContent.cornerRadius = bubbleCorners.auxiliaryRadius node.backgroundColorNode?.frame = backgroundContent.bounds @@ -239,6 +223,30 @@ private final class ChatMessageActionButtonNode: ASDisplayNode { node.backgroundBlurNode.isHidden = false } + let rect = node.backgroundBlurNode.bounds + let maskPath: CGPath? + switch position { + case .bottomSingle: + maskPath = UIBezierPath(roundRect: rect, topLeftRadius: bubbleCorners.auxiliaryRadius, topRightRadius: bubbleCorners.auxiliaryRadius, bottomLeftRadius: bubbleCorners.mainRadius, bottomRightRadius: bubbleCorners.mainRadius).cgPath + case .bottomLeft: + maskPath = UIBezierPath(roundRect: rect, topLeftRadius: bubbleCorners.auxiliaryRadius, topRightRadius: bubbleCorners.auxiliaryRadius, bottomLeftRadius: bubbleCorners.mainRadius, bottomRightRadius: bubbleCorners.auxiliaryRadius).cgPath + case .bottomRight: + maskPath = UIBezierPath(roundRect: rect, topLeftRadius: bubbleCorners.auxiliaryRadius, topRightRadius: bubbleCorners.auxiliaryRadius, bottomLeftRadius: bubbleCorners.auxiliaryRadius, bottomRightRadius: bubbleCorners.mainRadius).cgPath + default: + maskPath = nil + } + + let currentMaskPath = (node.layer.mask as? CAShapeLayer)?.path + if currentMaskPath != maskPath { + if let maskPath = maskPath { + let shapeLayer = CAShapeLayer() + shapeLayer.path = maskPath + node.layer.mask = shapeLayer + } else { + node.layer.mask = nil + } + } + if iconImage != nil { if node.iconNode == nil { let iconNode = ASImageNode() @@ -326,7 +334,7 @@ final class ChatMessageActionButtonsNode: ASDisplayNode { return { context, theme, chatBubbleCorners, strings, backgroundNode, replyMarkup, message, constrainedWidth in let buttonHeight: CGFloat = 42.0 - let buttonSpacing: CGFloat = 4.0 + let buttonSpacing: CGFloat = 2.0 var overallMinimumRowWidth: CGFloat = 0.0 @@ -379,7 +387,7 @@ final class ChatMessageActionButtonsNode: ASDisplayNode { var buttonFramesAndApply: [(CGRect, (ListViewItemUpdateAnimation) -> ChatMessageActionButtonNode)] = [] var verticalRowOffset: CGFloat = 0.0 - verticalRowOffset += buttonSpacing + verticalRowOffset += buttonSpacing * 0.5 var rowIndex = 0 for finalizeRowButtonLayouts in finalizeRowLayouts { diff --git a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift index c4773edf75..9a5e8bb317 100644 --- a/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageActionItemNode.swift @@ -333,6 +333,12 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.insertSubnode(backgroundNode, at: 0) } } + + if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true { + strongSelf.backgroundColorNode.isHidden = true + } else { + strongSelf.backgroundColorNode.isHidden = false + } if backgroundMaskUpdated, let backgroundNode = strongSelf.backgroundNode { if labelRects.count == 1 { diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index ee6292924d..ab0d28c5a8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -2287,7 +2287,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true @@ -2302,6 +2302,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let swipeToReplyNode = self.swipeToReplyNode { swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) + + if let (rect, containerSize) = self.absoluteRect { + let mappedRect = CGRect(origin: CGPoint(x: rect.minX + swipeToReplyNode.frame.minX, y: rect.minY + swipeToReplyNode.frame.minY), size: swipeToReplyNode.frame.size) + swipeToReplyNode.updateAbsoluteRect(mappedRect, within: containerSize) + } + if animateReplyNodeIn { swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12) swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 6673df3966..025bbccd7c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -2260,7 +2260,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode layoutSize.height += 4.0 + reactionButtonsSizeAndApply.0.height } if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { - layoutSize.height += actionButtonsSizeAndApply.0.height + layoutSize.height += 1.0 + actionButtonsSizeAndApply.0.height } var layoutInsets = UIEdgeInsets(top: mergedTop.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, left: 0.0, bottom: mergedBottom.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, right: 0.0) @@ -2919,81 +2919,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode shareButtonNode.removeFromSupernode() } - if case let .System(duration, _) = animation/*, !strongSelf.mainContextSourceNode.isExtractedToContextPreview*/ { - if !strongSelf.backgroundNode.frame.equalTo(backgroundFrame) { - if useDisplayLinkAnimations { - let backgroundAnimation = ListViewAnimation(from: strongSelf.backgroundNode.frame, to: backgroundFrame, duration: duration * UIView.animationDurationFactor(), curve: strongSelf.preferredAnimationCurve, beginAt: beginAt, update: { [weak strongSelf] _, frame in - if let strongSelf = strongSelf { - strongSelf.backgroundNode.frame = frame - strongSelf.clippingNode.position = CGPoint(x: frame.midX, y: frame.midY) - strongSelf.clippingNode.bounds = CGRect(origin: CGPoint(x: frame.minX, y: frame.minY), size: frame.size) - - strongSelf.backgroundNode.updateLayout(size: frame.size, transition: .immediate) - strongSelf.backgroundWallpaperNode.updateFrame(frame, transition: .immediate) - strongSelf.shadowNode.updateLayout(backgroundFrame: frame, transition: .immediate) - } - }) - strongSelf.setAnimationForKey("backgroundNodeFrame", animation: backgroundAnimation) - } else { - animation.animator.updateFrame(layer: strongSelf.backgroundNode.layer, frame: backgroundFrame, completion: nil) - animation.animator.updatePosition(layer: strongSelf.clippingNode.layer, position: backgroundFrame.center, completion: nil) - strongSelf.clippingNode.clipsToBounds = true - animation.animator.updateBounds(layer: strongSelf.clippingNode.layer, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: { [weak strongSelf] _ in - strongSelf?.clippingNode.clipsToBounds = false - }) - - strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: animation) - animation.animator.updateFrame(layer: strongSelf.backgroundWallpaperNode.layer, frame: backgroundFrame, completion: nil) - strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, animator: animation.animator) - strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, animator: animation.animator) - } - - if let _ = strongSelf.backgroundNode.type { - if !strongSelf.mainContextSourceNode.isExtractedToContextPreview { - if let (rect, size) = strongSelf.absoluteRect { - strongSelf.updateAbsoluteRect(rect, within: size) - } - } - } - strongSelf.messageAccessibilityArea.frame = backgroundFrame - } - if let shareButtonNode = strongSelf.shareButtonNode { - let currentBackgroundFrame = strongSelf.backgroundNode.frame - let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) - animation.animator.updateFrame(layer: shareButtonNode.layer, frame: CGRect(origin: CGPoint(x: currentBackgroundFrame.maxX + 8.0, y: currentBackgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize), completion: nil) - } - } else { - /*if let _ = strongSelf.backgroundFrameTransition { - strongSelf.animateFrameTransition(1.0, backgroundFrame.size.height) - strongSelf.backgroundFrameTransition = nil - }*/ - strongSelf.messageAccessibilityArea.frame = backgroundFrame - if let shareButtonNode = strongSelf.shareButtonNode { - let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) - shareButtonNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.maxX + 8.0, y: backgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize) - } - - if case .System = animation, strongSelf.mainContextSourceNode.isExtractedToContextPreview { - legacyTransition.updateFrame(node: strongSelf.backgroundNode, frame: backgroundFrame) - - legacyTransition.updateFrame(node: strongSelf.clippingNode, frame: backgroundFrame) - legacyTransition.updateBounds(node: strongSelf.clippingNode, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size)) - - strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: legacyTransition) - strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: legacyTransition) - strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: legacyTransition) - } else { - strongSelf.backgroundNode.frame = backgroundFrame - strongSelf.clippingNode.frame = backgroundFrame - strongSelf.clippingNode.bounds = CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size) - strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: .immediate) - strongSelf.backgroundWallpaperNode.frame = backgroundFrame - strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: .immediate) - } - if let (rect, size) = strongSelf.absoluteRect { - strongSelf.updateAbsoluteRect(rect, within: size) - } - } let offset: CGFloat = params.leftInset + (incoming ? 42.0 : 0.0) let selectionFrame = CGRect(origin: CGPoint(x: -offset, y: 0.0), size: CGSize(width: params.width, height: layout.contentSize.height)) strongSelf.selectionNode?.frame = selectionFrame @@ -3088,6 +3013,82 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } } + if case let .System(duration, _) = animation/*, !strongSelf.mainContextSourceNode.isExtractedToContextPreview*/ { + if !strongSelf.backgroundNode.frame.equalTo(backgroundFrame) { + if useDisplayLinkAnimations { + let backgroundAnimation = ListViewAnimation(from: strongSelf.backgroundNode.frame, to: backgroundFrame, duration: duration * UIView.animationDurationFactor(), curve: strongSelf.preferredAnimationCurve, beginAt: beginAt, update: { [weak strongSelf] _, frame in + if let strongSelf = strongSelf { + strongSelf.backgroundNode.frame = frame + strongSelf.clippingNode.position = CGPoint(x: frame.midX, y: frame.midY) + strongSelf.clippingNode.bounds = CGRect(origin: CGPoint(x: frame.minX, y: frame.minY), size: frame.size) + + strongSelf.backgroundNode.updateLayout(size: frame.size, transition: .immediate) + strongSelf.backgroundWallpaperNode.updateFrame(frame, transition: .immediate) + strongSelf.shadowNode.updateLayout(backgroundFrame: frame, transition: .immediate) + } + }) + strongSelf.setAnimationForKey("backgroundNodeFrame", animation: backgroundAnimation) + } else { + animation.animator.updateFrame(layer: strongSelf.backgroundNode.layer, frame: backgroundFrame, completion: nil) + animation.animator.updatePosition(layer: strongSelf.clippingNode.layer, position: backgroundFrame.center, completion: nil) + strongSelf.clippingNode.clipsToBounds = true + animation.animator.updateBounds(layer: strongSelf.clippingNode.layer, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size), completion: { [weak strongSelf] _ in + strongSelf?.clippingNode.clipsToBounds = false + }) + + strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: animation) + animation.animator.updateFrame(layer: strongSelf.backgroundWallpaperNode.layer, frame: backgroundFrame, completion: nil) + strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, animator: animation.animator) + strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, animator: animation.animator) + } + + if let _ = strongSelf.backgroundNode.type { + if !strongSelf.mainContextSourceNode.isExtractedToContextPreview { + if let (rect, size) = strongSelf.absoluteRect { + strongSelf.updateAbsoluteRect(rect, within: size) + } + } + } + strongSelf.messageAccessibilityArea.frame = backgroundFrame + } + if let shareButtonNode = strongSelf.shareButtonNode { + let currentBackgroundFrame = strongSelf.backgroundNode.frame + let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) + animation.animator.updateFrame(layer: shareButtonNode.layer, frame: CGRect(origin: CGPoint(x: currentBackgroundFrame.maxX + 8.0, y: currentBackgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize), completion: nil) + } + } else { + /*if let _ = strongSelf.backgroundFrameTransition { + strongSelf.animateFrameTransition(1.0, backgroundFrame.size.height) + strongSelf.backgroundFrameTransition = nil + }*/ + strongSelf.messageAccessibilityArea.frame = backgroundFrame + if let shareButtonNode = strongSelf.shareButtonNode { + let buttonSize = shareButtonNode.update(presentationData: item.presentationData, controllerInteraction: item.controllerInteraction, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account, disableComments: true) + shareButtonNode.frame = CGRect(origin: CGPoint(x: backgroundFrame.maxX + 8.0, y: backgroundFrame.maxY - buttonSize.width - 1.0), size: buttonSize) + } + + if case .System = animation, strongSelf.mainContextSourceNode.isExtractedToContextPreview { + legacyTransition.updateFrame(node: strongSelf.backgroundNode, frame: backgroundFrame) + + legacyTransition.updateFrame(node: strongSelf.clippingNode, frame: backgroundFrame) + legacyTransition.updateBounds(node: strongSelf.clippingNode, bounds: CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size)) + + strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: legacyTransition) + strongSelf.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: legacyTransition) + strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: legacyTransition) + } else { + strongSelf.backgroundNode.frame = backgroundFrame + strongSelf.clippingNode.frame = backgroundFrame + strongSelf.clippingNode.bounds = CGRect(origin: CGPoint(x: backgroundFrame.minX, y: backgroundFrame.minY), size: backgroundFrame.size) + strongSelf.backgroundNode.updateLayout(size: backgroundFrame.size, transition: .immediate) + strongSelf.backgroundWallpaperNode.frame = backgroundFrame + strongSelf.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: .immediate) + } + if let (rect, size) = strongSelf.absoluteRect { + strongSelf.updateAbsoluteRect(rect, within: size) + } + } + let previousContextContentFrame = strongSelf.mainContextSourceNode.contentRect strongSelf.mainContextSourceNode.contentRect = backgroundFrame.offsetBy(dx: incomingOffset, dy: 0.0) strongSelf.mainContainerNode.targetNodeForActivationProgressContentRect = strongSelf.mainContextSourceNode.contentRect @@ -3859,7 +3860,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode let graphics = PresentationResourcesChat.principalGraphics(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners) let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper - self.backgroundNode.setType(type: backgroundType, highlighted: highlighted, graphics: graphics, maskMode: self.mainContextSourceNode.isExtractedToContextPreview, hasWallpaper: hasWallpaper, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate, backgroundNode: item.controllerInteraction.presentationContext.backgroundNode) + self.backgroundNode.setType(type: backgroundType, highlighted: highlighted, graphics: graphics, maskMode: self.backgroundMaskMode, hasWallpaper: hasWallpaper, transition: animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate, backgroundNode: item.controllerInteraction.presentationContext.backgroundNode) } } } @@ -3898,7 +3899,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.insertSubnode(swipeToReplyNode, belowSubnode: self.messageAccessibilityArea) animateReplyNodeIn = true @@ -3916,6 +3917,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode if let swipeToReplyNode = self.swipeToReplyNode { swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) + + if let (rect, containerSize) = self.absoluteRect { + let mappedRect = CGRect(origin: CGPoint(x: rect.minX + swipeToReplyNode.frame.minX, y: rect.minY + swipeToReplyNode.frame.minY), size: swipeToReplyNode.frame.size) + swipeToReplyNode.updateAbsoluteRect(mappedRect, within: containerSize) + } + if animateReplyNodeIn { swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12) swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) diff --git a/submodules/TelegramUI/Sources/ChatMessageContextControllerContentSource.swift b/submodules/TelegramUI/Sources/ChatMessageContextControllerContentSource.swift index 319ca3f95e..cb99cd36d5 100644 --- a/submodules/TelegramUI/Sources/ChatMessageContextControllerContentSource.swift +++ b/submodules/TelegramUI/Sources/ChatMessageContextControllerContentSource.swift @@ -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 diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index 2bb526a3d7..35cb176778 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -1000,7 +1000,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true @@ -1015,6 +1015,12 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let swipeToReplyNode = self.swipeToReplyNode { swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) + + if let (rect, containerSize) = self.absoluteRect { + let mappedRect = CGRect(origin: CGPoint(x: rect.minX + swipeToReplyNode.frame.minX, y: rect.minY + swipeToReplyNode.frame.minY), size: swipeToReplyNode.frame.size) + swipeToReplyNode.updateAbsoluteRect(mappedRect, within: containerSize) + } + if animateReplyNodeIn { swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12) swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) @@ -1328,6 +1334,22 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD var rect = rect rect.origin.y = containerSize.height - rect.maxY + self.insets.top + if let shareButtonNode = self.shareButtonNode { + var shareButtonNodeFrame = shareButtonNode.frame + shareButtonNodeFrame.origin.x += rect.minX + shareButtonNodeFrame.origin.y += rect.minY + + shareButtonNode.updateAbsoluteRect(shareButtonNodeFrame, within: containerSize) + } + + if let actionButtonsNode = self.actionButtonsNode { + var actionButtonsNodeFrame = actionButtonsNode.frame + actionButtonsNodeFrame.origin.x += rect.minX + actionButtonsNodeFrame.origin.y += rect.minY + + actionButtonsNode.updateAbsoluteRect(actionButtonsNodeFrame, within: containerSize) + } + if let reactionButtonsNode = self.reactionButtonsNode { var reactionButtonsNodeFrame = reactionButtonsNode.frame reactionButtonsNodeFrame.origin.x += rect.minX diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 547874fe48..df65a72313 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -177,7 +177,7 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs for attribute in lhs.attributes { if let attribute = attribute as? ReplyMarkupMessageAttribute { if attribute.flags.contains(.inline) && !attribute.rows.isEmpty { - upperStyle = ChatMessageMerge.semanticallyMerged.rawValue + upperStyle = ChatMessageMerge.none.rawValue } break } diff --git a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift index 917bb009a8..f9ae0f5c2f 100644 --- a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift @@ -479,7 +479,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { private var percentageImage: UIImage? private var titleNode: TextNode? private let buttonNode: HighlightTrackingButtonNode - private let separatorNode: ASDisplayNode + let separatorNode: ASDisplayNode private let resultBarNode: ASImageNode private let resultBarIconNode: ASImageNode var option: TelegramMediaPollOption? @@ -489,6 +489,8 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { var selectionUpdated: (() -> Void)? private var theme: PresentationTheme? + weak var previousOptionNode: ChatMessagePollOptionNode? + override init() { self.highlightedBackgroundNode = ASDisplayNode() self.highlightedBackgroundNode.alpha = 0.0 @@ -524,9 +526,21 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { if highlighted { strongSelf.highlightedBackgroundNode.layer.removeAnimation(forKey: "opacity") strongSelf.highlightedBackgroundNode.alpha = 1.0 + + strongSelf.separatorNode.layer.removeAnimation(forKey: "opacity") + strongSelf.separatorNode.alpha = 0.0 + + strongSelf.previousOptionNode?.separatorNode.layer.removeAnimation(forKey: "opacity") + strongSelf.previousOptionNode?.separatorNode.alpha = 0.0 } else { strongSelf.highlightedBackgroundNode.alpha = 0.0 strongSelf.highlightedBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3) + + strongSelf.separatorNode.alpha = 1.0 + strongSelf.separatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + + strongSelf.previousOptionNode?.separatorNode.alpha = 1.0 + strongSelf.previousOptionNode?.separatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) } } } @@ -1373,6 +1387,10 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { verticalOffset += size.height updatedOptionNodes.append(optionNode) optionNode.isUserInteractionEnabled = canVote && item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] == nil + + if i > 0 { + optionNode.previousOptionNode = updatedOptionNodes[i - 1] + } } for optionNode in strongSelf.optionNodes { if !updatedOptionNodes.contains(where: { $0 === optionNode }) { diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index a8f3362b55..6c3afc923d 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -277,6 +277,22 @@ class ChatMessageStickerItemNode: ChatMessageItemView { backgroundNode.update(rect: CGRect(origin: CGPoint(x: rect.minX + self.placeholderNode.frame.minX, y: rect.minY + self.placeholderNode.frame.minY), size: self.placeholderNode.frame.size), within: containerSize, transition: .immediate) } + if let shareButtonNode = self.shareButtonNode { + var shareButtonNodeFrame = shareButtonNode.frame + shareButtonNodeFrame.origin.x += rect.minX + shareButtonNodeFrame.origin.y += rect.minY + + shareButtonNode.updateAbsoluteRect(shareButtonNodeFrame, within: containerSize) + } + + if let actionButtonsNode = self.actionButtonsNode { + var actionButtonsNodeFrame = actionButtonsNode.frame + actionButtonsNodeFrame.origin.x += rect.minX + actionButtonsNodeFrame.origin.y += rect.minY + + actionButtonsNode.updateAbsoluteRect(actionButtonsNodeFrame, within: containerSize) + } + if let reactionButtonsNode = self.reactionButtonsNode { var reactionButtonsNodeFrame = reactionButtonsNode.frame reactionButtonsNodeFrame.origin.x += rect.minX @@ -1236,7 +1252,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if translation.x < -45.0, self.swipeToReplyNode == nil, let item = self.item { self.swipeToReplyFeedback?.impact() - let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) + let swipeToReplyNode = ChatMessageSwipeToReplyNode(fillColor: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), foregroundColor: bubbleVariableColor(variableColor: item.presentationData.theme.theme.chat.message.shareButtonForegroundColor, wallpaper: item.presentationData.theme.wallpaper), backgroundNode: item.controllerInteraction.presentationContext.backgroundNode, action: ChatMessageSwipeToReplyNode.Action(self.currentSwipeAction)) self.swipeToReplyNode = swipeToReplyNode self.addSubnode(swipeToReplyNode) animateReplyNodeIn = true @@ -1251,6 +1267,12 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let swipeToReplyNode = self.swipeToReplyNode { swipeToReplyNode.frame = CGRect(origin: CGPoint(x: bounds.size.width, y: floor((self.contentSize.height - 33.0) / 2.0)), size: CGSize(width: 33.0, height: 33.0)) + + if let (rect, containerSize) = self.absoluteRect { + let mappedRect = CGRect(origin: CGPoint(x: rect.minX + swipeToReplyNode.frame.minX, y: rect.minY + swipeToReplyNode.frame.minY), size: swipeToReplyNode.frame.size) + swipeToReplyNode.updateAbsoluteRect(mappedRect, within: containerSize) + } + if animateReplyNodeIn { swipeToReplyNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.12) swipeToReplyNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4) diff --git a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift index bbdee19c02..518ee18b0d 100644 --- a/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageSwipeToReplyNode.swift @@ -3,6 +3,7 @@ import UIKit import Display import AsyncDisplayKit import AppBundle +import WallpaperBackgroundNode final class ChatMessageSwipeToReplyNode: ASDisplayNode { enum Action { @@ -11,10 +12,14 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode { case unlike } + private var backgroundContent: WallpaperBubbleBackgroundNode? + private let backgroundNode: NavigationBackgroundNode private let foregroundNode: ASImageNode - init(fillColor: UIColor, enableBlur: Bool, foregroundColor: UIColor, action: ChatMessageSwipeToReplyNode.Action) { + private var absolutePosition: (CGRect, CGSize)? + + init(fillColor: UIColor, enableBlur: Bool, foregroundColor: UIColor, backgroundNode: WallpaperBackgroundNode?, action: ChatMessageSwipeToReplyNode.Action) { self.backgroundNode = NavigationBackgroundNode(color: fillColor, enableBlur: enableBlur) self.backgroundNode.isUserInteractionEnabled = false @@ -57,11 +62,49 @@ final class ChatMessageSwipeToReplyNode: ASDisplayNode { super.init() + self.allowsGroupOpacity = true + self.addSubnode(self.backgroundNode) self.addSubnode(self.foregroundNode) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0)) self.backgroundNode.update(size: self.backgroundNode.bounds.size, cornerRadius: self.backgroundNode.bounds.height / 2.0, transition: .immediate) self.foregroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 33.0, height: 33.0)) + + if backgroundNode?.hasExtraBubbleBackground() == true { + if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .free) { + backgroundContent.clipsToBounds = true + backgroundContent.allowsGroupOpacity = true + self.backgroundContent = backgroundContent + self.insertSubnode(backgroundContent, at: 0) + } + } else { + self.backgroundContent?.removeFromSupernode() + self.backgroundContent = nil + } + + if let backgroundContent = self.backgroundContent { + self.backgroundNode.isHidden = true + backgroundContent.cornerRadius = min(self.backgroundNode.bounds.width, self.backgroundNode.bounds.height) / 2.0 + backgroundContent.frame = self.backgroundNode.frame + if let (rect, containerSize) = self.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += containerSize.height - rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } + } else { + self.backgroundNode.isHidden = false + } + } + + func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + self.absolutePosition = (rect, containerSize) + if let backgroundContent = self.backgroundContent { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += containerSize.height - rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 7202f67970..b8c99d6a02 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -659,7 +659,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { let emptyFrame = CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: layout.size.height - navigationBarHeight - panelHeight)) transition.updateFrame(node: self.emptyNode, frame: emptyFrame) - self.emptyNode.updateLayout(size: emptyFrame.size, transition: transition) + self.emptyNode.update(rect: emptyFrame, within: layout.size) + self.emptyNode.updateLayout(backgroundNode: self.backgroundNode, size: emptyFrame.size, transition: transition) let contentBottomInset: CGFloat = panelHeight + 4.0 let listInsets = UIEdgeInsets(top: contentBottomInset, left: layout.safeInsets.right, bottom: insets.top, right: layout.safeInsets.left) diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsEmptyNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsEmptyNode.swift index 1588ddca37..9ad65f4aca 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsEmptyNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsEmptyNode.swift @@ -4,6 +4,7 @@ import Display import AsyncDisplayKit import TelegramCore import TelegramPresentationData +import WallpaperBackgroundNode private let titleFont = Font.medium(16.0) private let textFont = Font.regular(15.0) @@ -16,6 +17,11 @@ final class ChatRecentActionsEmptyNode: ASDisplayNode { private let titleNode: TextNode private let textNode: TextNode + private var wallpaperBackgroundNode: WallpaperBackgroundNode? + private var backgroundContent: WallpaperBubbleBackgroundNode? + + private var absolutePosition: (CGRect, CGSize)? + private var layoutParams: CGSize? private var title: String = "" @@ -36,6 +42,8 @@ final class ChatRecentActionsEmptyNode: ASDisplayNode { super.init() + self.allowsGroupOpacity = true + let graphics = PresentationResourcesChat.additionalGraphics(theme, wallpaper: chatWallpaper, bubbleCorners: chatBubbleCorners) self.backgroundNode.image = graphics.chatEmptyItemBackgroundImage @@ -44,7 +52,18 @@ final class ChatRecentActionsEmptyNode: ASDisplayNode { self.addSubnode(self.textNode) } - func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { + public func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) { + self.absolutePosition = (rect, containerSize) + if let backgroundContent = self.backgroundContent { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition) + } + } + + func updateLayout(backgroundNode: WallpaperBackgroundNode, size: CGSize, transition: ContainedViewLayoutTransition) { + self.wallpaperBackgroundNode = backgroundNode self.layoutParams = size let insets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0) @@ -68,14 +87,40 @@ final class ChatRecentActionsEmptyNode: ASDisplayNode { let _ = titleApply() let _ = textApply() + + if backgroundNode.hasExtraBubbleBackground() == true { + if self.backgroundContent == nil, let backgroundContent = backgroundNode.makeBubbleBackground(for: .free) { + backgroundContent.clipsToBounds = true + + self.backgroundContent = backgroundContent + self.insertSubnode(backgroundContent, at: 0) + } + } else { + self.backgroundContent?.removeFromSupernode() + self.backgroundContent = nil + } + + if let backgroundContent = self.backgroundContent { + self.backgroundNode.isHidden = true + backgroundContent.cornerRadius = 14.0 + backgroundContent.frame = backgroundFrame + if let (rect, containerSize) = self.absolutePosition { + var backgroundFrame = backgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } + } else { + self.backgroundNode.isHidden = false + } } func setup(title: String, text: String) { if self.title != title || self.text != text { self.title = title self.text = text - if let size = self.layoutParams { - self.updateLayout(size: size, transition: .immediate) + if let size = self.layoutParams, let wallpaperBackgroundNode = self.wallpaperBackgroundNode { + self.updateLayout(backgroundNode: wallpaperBackgroundNode, size: size, transition: .immediate) } } } diff --git a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift index 90e3bcdaa5..e97bcfff6a 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift @@ -80,6 +80,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode { } } + self.micButton.layer.allowsGroupOpacity = true self.view.addSubview(self.micButton) self.addSubnode(self.sendContainerNode) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 90f226dbb3..663e033788 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -243,7 +243,6 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode { } else if case .emoji = previousInputMode { animationName = "input_anim_smileToSticker" animationMode = .animating(loop: false) -// colorKeys = emojiColorKeys } else { animationName = "input_anim_keyToSticker" } @@ -258,7 +257,6 @@ private final class AccessoryItemIconButtonNode: HighlightTrackingButtonNode { } else if case .stickers = previousInputMode { animationName = "input_anim_stickerToSmile" animationMode = .animating(loop: false) -// colorKeys = emojiColorKeys } else { animationName = "input_anim_keyToSmile" } @@ -1085,7 +1083,13 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { let recognizer = TouchDownGestureRecognizer(target: self, action: #selector(self.textInputBackgroundViewTap(_:))) recognizer.touchDown = { [weak self] in if let strongSelf = self { - strongSelf.ensureFocusedOnTap() + if strongSelf.textInputNode?.isFirstResponder() == true { + Queue.mainQueue().after(0.05) { + strongSelf.ensureFocusedOnTap() + } + } else { + strongSelf.ensureFocusedOnTap() + } } } recognizer.waitForTouchUp = { [weak self] in @@ -3397,17 +3401,24 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { self.loadTextInputNode() } - self.textInputNode?.becomeFirstResponder() + if !self.switching { + self.textInputNode?.becomeFirstResponder() + } } + private var switching = false func ensureFocusedOnTap() { if self.textInputNode == nil { self.loadTextInputNode() } - self.textInputNode?.becomeFirstResponder() - - self.switchToTextInputIfNeeded?() + if !self.switching { + self.switching = true + self.textInputNode?.becomeFirstResponder() + + self.switchToTextInputIfNeeded?() + self.switching = false + } } func backwardsDeleteText() { diff --git a/submodules/TelegramUI/Sources/ChatUnreadItem.swift b/submodules/TelegramUI/Sources/ChatUnreadItem.swift index 67bf4357a7..432eb3e92d 100644 --- a/submodules/TelegramUI/Sources/ChatUnreadItem.swift +++ b/submodules/TelegramUI/Sources/ChatUnreadItem.swift @@ -187,7 +187,7 @@ class ChatUnreadItemNode: ListViewItemNode { if let backgroundContent = self.backgroundContent { var backgroundFrame = backgroundContent.frame backgroundFrame.origin.x += rect.minX - backgroundFrame.origin.y += rect.minY + backgroundFrame.origin.y += containerSize.height - rect.minY backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) } } diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 6c32e35454..4424cc560f 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -579,13 +579,13 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur if let navigationController = navigationController { let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, updatedPresentationData: updatedPresentationData, filter: filters, hasChatListSelector: true, hasContactSelector: false, title: presentationData.strings.WebApp_SelectChat)) controller.peerSelected = { peer in - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: bot.peer.id, payload: payload, justInstalled: false), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: peer.id), attachBotStart: ChatControllerInitialAttachBotStart(botId: bot.peer.id, payload: payload, justInstalled: false), keepStack: .never, useExisting: true)) } navigationController.pushViewController(controller) } } else { if let navigationController = navigationController, case let .chat(chatPeerId, _) = urlContext { - let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload, justInstalled: false), useExisting: true)) + let _ = context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(id: chatPeerId), attachBotStart: ChatControllerInitialAttachBotStart(botId: peerId, payload: payload, justInstalled: false), keepStack: .never, useExisting: true)) } else { presentError(presentationData.strings.WebApp_AddToAttachmentAlreadyAddedError) } diff --git a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift index c44d3945c9..9dfb49fd67 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/ListItems/PeerInfoScreenLabeledValueItem.swift @@ -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 = item.contextAction != nil + + 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 } @@ -543,7 +627,7 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode { } else { linkHighlightingNode = LinkHighlightingNode(color: theme.list.itemAccentColor.withAlphaComponent(0.5)) self.linkHighlightingNode = linkHighlightingNode - self.insertSubnode(linkHighlightingNode, belowSubnode: textNode) + self.contextSourceNode.contentNode.insertSubnode(linkHighlightingNode, belowSubnode: textNode) } linkHighlightingNode.frame = textNode.frame linkHighlightingNode.updateRects(rects) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 2074fd37f0..f89306478e 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -2023,7 +2023,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { var displayAvatarContextMenu: ((ASDisplayNode, ContextGesture?) -> Void)? var displayCopyContextMenu: ((ASDisplayNode, Bool, Bool) -> Void)? - var displayPremiumIntro: ((UIView, PeerEmojiStatus?, Signal<(TelegramMediaFile, String)?, NoError>, Bool) -> Void)? + var displayPremiumIntro: ((UIView, PeerEmojiStatus?, Signal<(TelegramMediaFile, LoadedStickerPack)?, NoError>, Bool) -> Void)? var navigationTransition: PeerInfoHeaderNavigationTransition? @@ -2034,7 +2034,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let animationRenderer: MultiAnimationRenderer var emojiStatusPackDisposable = MetaDisposable() - var emojiStatusFileAndPackTitle = Promise<(TelegramMediaFile, String)?>() + var emojiStatusFileAndPackTitle = Promise<(TelegramMediaFile, LoadedStickerPack)?>() init(context: AccountContext, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool) { self.context = context @@ -2392,9 +2392,9 @@ final class PeerInfoHeaderNode: ASDisplayNode { return false } } - |> mapToSignal { result -> Signal<(TelegramMediaFile, String)?, NoError> in - if case let .result(info, items, _) = result { - return .single(items.first.flatMap { ($0.file, info.title) }) + |> mapToSignal { result -> Signal<(TelegramMediaFile, LoadedStickerPack)?, NoError> in + if case let .result(_, items, _) = result { + return .single(items.first.flatMap { ($0.file, result) }) } else { return .complete() } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift index 1633da1ec1..30aa7d6e0c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoPaneContainerNode.swift @@ -457,6 +457,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat weak var parentController: ViewController? private let coveringBackgroundNode: NavigationBackgroundNode + private let additionalBackgroundNode: ASDisplayNode private let separatorNode: ASDisplayNode private let tabsContainerNode: PeerInfoPaneTabsContainerNode private let tabsSeparatorNode: ASDisplayNode @@ -514,6 +515,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat self.peerId = peerId self.isMediaOnly = isMediaOnly + self.additionalBackgroundNode = ASDisplayNode() + self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -528,6 +531,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat super.init() // self.addSubnode(self.separatorNode) + self.addSubnode(self.additionalBackgroundNode) self.addSubnode(self.coveringBackgroundNode) self.addSubnode(self.tabsContainerNode) self.addSubnode(self.tabsSeparatorNode) @@ -748,6 +752,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat self.backgroundColor = presentationData.theme.list.plainBackgroundColor self.coveringBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor, transition: .immediate) self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor + self.additionalBackgroundNode.backgroundColor = presentationData.theme.list.itemBlocksBackgroundColor self.tabsSeparatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor let isScrollingLockedAtTop = expansionFraction < 1.0 - CGFloat.ulpOfOne @@ -956,6 +961,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel - tabsOffset), size: CGSize(width: size.width, height: UIScreenPixel))) transition.updateFrame(node: self.coveringBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel - tabsOffset), size: CGSize(width: size.width, height: tabsHeight + UIScreenPixel))) self.coveringBackgroundNode.update(size: self.coveringBackgroundNode.bounds.size, transition: transition) + transition.updateFrame(node: self.additionalBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel - tabsOffset), size: CGSize(width: size.width, height: tabsHeight + UIScreenPixel))) transition.updateFrame(node: self.tabsSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: tabsHeight - tabsOffset), size: CGSize(width: size.width, height: UIScreenPixel))) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index ac5f5c6177..e0ea0145f7 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -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() @@ -3155,7 +3155,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } else { screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext) - self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPackTitle, white in + self.headerNode.displayPremiumIntro = { [weak self] sourceView, peerStatus, emojiStatusFileAndPack, white in guard let strongSelf = self else { return } @@ -3172,11 +3172,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } let source: Signal if let peerStatus = peerStatus { - source = emojiStatusFileAndPackTitle + source = emojiStatusFileAndPack |> take(1) - |> mapToSignal { emojiStatusFileAndPackTitle -> Signal in - if let (file, packTitle) = emojiStatusFileAndPackTitle { - return .single(.emojiStatus(strongSelf.peerId, peerStatus.fileId, file, packTitle)) + |> mapToSignal { emojiStatusFileAndPack -> Signal in + if let (file, pack) = emojiStatusFileAndPack { + return .single(.emojiStatus(strongSelf.peerId, peerStatus.fileId, file, pack)) } else { return .complete() } @@ -3185,7 +3185,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate source = .single(.profile(strongSelf.peerId)) } - let _ = source.start(next: { [weak self] source in + let _ = (source + |> deliverOnMainQueue).start(next: { [weak self] source in guard let strongSelf = self else { return } @@ -3509,9 +3510,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } var mediaReference: AnyMediaReference? - for m in message.media { - if let image = m as? TelegramMediaImage { + for media in message.media { + if let image = media as? TelegramMediaImage { mediaReference = AnyMediaReference.standalone(media: image) + } else if let file = media as? TelegramMediaFile { + mediaReference = AnyMediaReference.standalone(media: file) } } @@ -4889,39 +4892,82 @@ 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() + 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: "Chat/Context Menu/PhoneCall"), 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: "Chat/Context Menu/PhoneCall"), 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)) }) } @@ -8513,7 +8559,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 @@ -8811,6 +8857,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 diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 3e5c19e099..ef98633a45 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1507,8 +1507,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { return PremiumIntroScreen(context: context, source: mappedSource) } - public func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController { - return StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: mainStickerPack, stickerPacks: stickerPacks, parentNavigationController: parentNavigationController, sendSticker: sendSticker) + public func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], loadedStickerPacks: [LoadedStickerPack], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController { + return StickerPackScreen(context: context, updatedPresentationData: updatedPresentationData, mainStickerPack: mainStickerPack, stickerPacks: stickerPacks, loadedStickerPacks: loadedStickerPacks, parentNavigationController: parentNavigationController, sendSticker: sendSticker) } public func makeProxySettingsController(sharedContext: SharedAccountContext, account: UnauthorizedAccount) -> ViewController { diff --git a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift index 7d7a5d6aef..34690fd75f 100644 --- a/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/PresentationThemeSettings.swift @@ -524,6 +524,18 @@ public struct PresentationThemeAccentColor: PostboxCoding, Equatable { } } + public func colorFor(baseTheme: TelegramBaseTheme) -> UIColor { + if let value = self.accentColor { + return UIColor(rgb: UInt32(bitPattern: value)) + } else { + if baseTheme == .night && self.baseColor == .blue { + return UIColor(rgb: 0x3e88f7) + } else { + return self.baseColor.color + } + } + } + public var customBubbleColors: [UInt32] { return self.bubbleColors } diff --git a/submodules/TranslateUI/Sources/Translate.swift b/submodules/TranslateUI/Sources/Translate.swift index 36c0dc2c08..6ccec4617f 100644 --- a/submodules/TranslateUI/Sources/Translate.swift +++ b/submodules/TranslateUI/Sources/Translate.swift @@ -24,7 +24,7 @@ public var supportedTranslationLanguages = [ "bg", "ca", "ceb", - "zh-Hans", + "zh", // "zh-Hant", // "zh-CN", "zh" // "zh-TW" @@ -126,7 +126,7 @@ public var supportedTranslationLanguages = [ public var popularTranslationLanguages = [ "en", "ar", - "zh-Hans", + "zh", // "zh-Hant", "fr", "de",