Merge commit '45128a87b9a8dd425d69666564cdd9654bae15e5'

This commit is contained in:
Ali 2022-09-28 12:15:10 +02:00
commit 012aacf202
49 changed files with 708 additions and 200 deletions

View File

@ -755,7 +755,7 @@ public protocol SharedAccountContext: AnyObject {
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource) -> ViewController
func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController
func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], loadedStickerPacks: [LoadedStickerPack], parentNavigationController: NavigationController?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)?) -> ViewController
func makeProxySettingsController(sharedContext: SharedAccountContext, account: UnauthorizedAccount) -> ViewController
@ -788,7 +788,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

View File

@ -2440,7 +2440,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
}
@ -2459,7 +2459,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

View File

@ -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()
})
}
}
}

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2722,10 +2722,14 @@ static CGPoint TGCameraControllerClampPointToScreenSize(__unused id self, __unus
default:
{
if (widescreenWidth == 932.0f)
return CGRectMake(0, 121, screenSize.width, screenSize.height - 121 - 234);
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, 121, screenSize.width, screenSize.height - 121 - 234);
else if (widescreenWidth == 844.0f)
return CGRectMake(0, 77, screenSize.width, screenSize.height - 77 - 191);
else if (widescreenWidth == 812.0f)

View File

@ -113,6 +113,17 @@
CGFloat shutterButtonWidth = 66.0f;
CGSize screenSize = TGScreenSize();
CGFloat widescreenWidth = MAX(screenSize.width, screenSize.height);
if (widescreenWidth == 932.0f)
{
_topPanelOffset = 34.0f;
_topPanelHeight = 48.0f;
_bottomPanelOffset = 94.0f;
_bottomPanelHeight = 140.0f;
_modeControlOffset = -2.0f;
_modeControlHeight = 66.0f;
_counterOffset = 7.0f;
shutterButtonWidth = 72.0f;
}
if (widescreenWidth == 926.0f)
{
_topPanelOffset = 34.0f;
@ -135,6 +146,17 @@
_counterOffset = 7.0f;
shutterButtonWidth = 72.0f;
}
else if (widescreenWidth == 852.0f)
{
_topPanelOffset = 33.0f;
_topPanelHeight = 44.0f;
_bottomPanelOffset = 63.0f;
_bottomPanelHeight = 128.0f;
_modeControlOffset = 3.0f;
_modeControlHeight = 40.0f;
_counterOffset = 7.0f;
shutterButtonWidth = 70.0f;
}
else if (widescreenWidth == 844.0f)
{
_topPanelOffset = 33.0f;

View File

@ -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)
{

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -1117,7 +1117,7 @@ static id<LegacyComponentsContext> _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()) {

View File

@ -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])
@ -2127,7 +2258,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
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 {
highlightableLinks = true
var packReference: StickerPackReference?
@ -2141,7 +2272,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 +2337,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: [], parentNavigationController: navigationController, sendSticker: { _, _, _ in
return false
})
presentController(controller)

View File

@ -14,6 +14,7 @@ swift_library(
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/AccountContext:AccountContext",
"//submodules/StringTransliteration:StringTransliteration",
],
visibility = [
"//visibility:public",

View File

@ -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<EnginePeer.Id>()
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
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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<PresentationData, NoError>)? = 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,

View File

@ -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<Void, NoError> {

View File

@ -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,

View File

@ -309,7 +309,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
}
let effectiveColors = themeSettings.themeSpecificAccentColors[effectiveTheme.index]
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], baseColor: effectiveColors?.baseColor) ?? defaultPresentationTheme
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.colorFor(baseTheme: preferredBaseTheme ?? .day), bubbleColors: effectiveColors?.customBubbleColors ?? [], baseColor: effectiveColors?.baseColor) ?? defaultPresentationTheme
let effectiveChatWallpaper: TelegramWallpaper = (themeSettings.themeSpecificChatWallpapers[coloredThemeIndex(reference: effectiveTheme, accentColor: effectiveColors)] ?? themeSettings.themeSpecificChatWallpapers[effectiveTheme.index]) ?? theme.chat.defaultWallpaper
@ -658,7 +658,7 @@ public func updatedPresentationData(accountManager: AccountManager<TelegramAccou
effectiveColors = nil
}
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.color, bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
let themeValue = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: effectiveTheme, baseTheme: preferredBaseTheme, accentColor: effectiveColors?.colorFor(baseTheme: preferredBaseTheme ?? .day), bubbleColors: effectiveColors?.customBubbleColors ?? [], wallpaper: effectiveColors?.wallpaper, baseColor: effectiveColors?.baseColor, serviceBackgroundColor: serviceBackgroundColor) ?? defaultPresentationTheme
if autoNightModeTriggered && !switchedToNightModeWallpaper {
switch effectiveChatWallpaper {

View File

@ -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.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)

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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
})

View File

@ -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?

View File

@ -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,16 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
node.backgroundBlurNode.isHidden = false
}
if position == .bottomSingle {
let rect = node.backgroundBlurNode.bounds
let maskPath = UIBezierPath(roundRect: rect, topLeftRadius: bubbleCorners.auxiliaryRadius, topRightRadius: bubbleCorners.auxiliaryRadius, bottomLeftRadius: bubbleCorners.mainRadius, bottomRightRadius: bubbleCorners.mainRadius)
let shape = CAShapeLayer()
shape.path = maskPath.cgPath
node.layer.mask = shape
} else {
node.layer.mask = nil
}
if iconImage != nil {
if node.iconNode == nil {
let iconNode = ASImageNode()
@ -326,7 +320,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 +373,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 {

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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 }) {

View File

@ -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)

View File

@ -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)
}
}
}

View File

@ -659,7 +659,7 @@ 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.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)

View File

@ -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)
}
}
}

View File

@ -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() {

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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<PremiumSource, NoError>
if let peerStatus = peerStatus {
source = emojiStatusFileAndPackTitle
source = emojiStatusFileAndPack
|> take(1)
|> mapToSignal { emojiStatusFileAndPackTitle -> Signal<PremiumSource, NoError> in
if let (file, packTitle) = emojiStatusFileAndPackTitle {
return .single(.emojiStatus(strongSelf.peerId, peerStatus.fileId, file, packTitle))
|> mapToSignal { emojiStatusFileAndPack -> Signal<PremiumSource, NoError> 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)
}
}

View File

@ -1515,8 +1515,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return PremiumIntroScreen(context: context, source: mappedSource)
}
public func makeStickerPackScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, 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<PresentationData, NoError>)?, 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 {

View File

@ -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
}

View File

@ -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",