Various fixes

This commit is contained in:
Ilya Laktyushin 2023-12-20 17:44:12 +04:00
parent 3ae64b399f
commit 90a1e9b688
10 changed files with 249 additions and 178 deletions

View File

@ -10776,3 +10776,4 @@ Sorry for the inconvenience.";
"ChatList.PremiumGiftInSettingsInfo" = "You can gift **Telegram Premium** to a friend later in **Settings**."; "ChatList.PremiumGiftInSettingsInfo" = "You can gift **Telegram Premium** to a friend later in **Settings**.";
"ChannelAppearance.BoostLevel" = "Level %@";

View File

@ -983,9 +983,9 @@ final class DrawingStickerEntititySelectionView: DrawingEntitySelectionView {
var count = 12 var count = 12
if case .message = entity.content { if case .message = entity.content {
cornerRadius *= 2.1 cornerRadius *= 2.1
count = 20 count = 24
} else if case .image = entity.content { } else if case .image = entity.content {
count = 20 count = 24
} }
let perimeter: CGFloat = 2.0 * (width + height - cornerRadius * (4.0 - .pi)) let perimeter: CGFloat = 2.0 * (width + height - cornerRadius * (4.0 - .pi))

View File

@ -491,9 +491,12 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
if remainingCutoutHeight > 0.0 { if remainingCutoutHeight > 0.0 {
cutout = TextNodeCutout(topRight: CGSize(width: cutoutWidth, height: remainingCutoutHeight)) cutout = TextNodeCutout(topRight: CGSize(width: cutoutWidth, height: remainingCutoutHeight))
} }
var maximumNumberOfLines: Int = 12
if isPreview {
maximumNumberOfLines = mediaAndFlags != nil ? 4 : 6
}
let textString = stringWithAppliedEntities(text, entities: entities ?? [], baseColor: messageTheme.primaryTextColor, linkColor: incoming ? mainColor : messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textBlockQuoteFont, message: nil, adjustQuoteFontSize: true) let textString = stringWithAppliedEntities(text, entities: entities ?? [], baseColor: messageTheme.primaryTextColor, linkColor: incoming ? mainColor : messageTheme.linkTextColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, boldItalicFont: textBoldItalicFont, fixedFont: textFixedFont, blockQuoteFont: textBlockQuoteFont, message: nil, adjustQuoteFontSize: true)
let textLayoutAndApplyValue = makeTextLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 12, truncationType: .end, constrainedSize: CGSize(width: maxContentsWidth, height: 10000.0), alignment: .natural, lineSpacing: textLineSpacing, cutout: cutout, insets: UIEdgeInsets())) let textLayoutAndApplyValue = makeTextLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: maximumNumberOfLines, truncationType: .end, constrainedSize: CGSize(width: maxContentsWidth, height: 10000.0), alignment: .natural, lineSpacing: textLineSpacing, cutout: cutout, insets: UIEdgeInsets()))
textLayoutAndApply = textLayoutAndApplyValue textLayoutAndApply = textLayoutAndApplyValue
remainingCutoutHeight -= textLayoutAndApplyValue.0.size.height remainingCutoutHeight -= textLayoutAndApplyValue.0.size.height

View File

@ -1862,6 +1862,9 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string, iconName: nil) badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string, iconName: nil)
} }
} }
let gifTitle = game != nil ? strings.Message_Game.uppercased() : strings.Message_Animation.uppercased()
var animated = animated var animated = animated
if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media { if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true, animateRotation: true) state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true, animateRotation: true)
@ -1916,8 +1919,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
} }
} }
let gifTitle = game != nil ? strings.Message_Game.uppercased() : strings.Message_Animation.uppercased()
let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator) let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator)
var media = self.media var media = self.media
@ -2079,7 +2080,11 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
} }
} }
} }
if isPreview, let _ = media as? TelegramMediaFile { if isPreview, let file = media as? TelegramMediaFile {
if let duration = file.duration, !file.isVideoSticker {
let durationString = file.isAnimated ? gifTitle : stringForDuration(Int32(duration), position: nil)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: nil, muted: false, active: false)
}
state = .play(messageTheme.mediaOverlayControlColors.foregroundColor) state = .play(messageTheme.mediaOverlayControlColors.foregroundColor)
} }
@ -2125,6 +2130,13 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
animated = true animated = true
} }
if isPreview {
if case .play = state {
} else {
state = .none
}
}
statusNode.transitionToState(state, animated: animated, completion: { [weak statusNode] in statusNode.transitionToState(state, animated: animated, completion: { [weak statusNode] in
if removeStatusNode { if removeStatusNode {
statusNode?.removeFromSupernode() statusNode?.removeFromSupernode()

View File

@ -521,6 +521,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
} else { } else {
maximumNumberOfLines = 6 maximumNumberOfLines = 6
} }
} else if let _ = item.message.media.first(where: { $0 is TelegramMediaWebpage }) as? TelegramMediaWebpage {
maximumNumberOfLines = 9
} else { } else {
maximumNumberOfLines = 12 maximumNumberOfLines = 12
} }

View File

@ -334,9 +334,18 @@ public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode
var patternArguments: PatternWallpaperArguments? var patternArguments: PatternWallpaperArguments?
var mediaContent = media.content var mediaContent = media.content
if case let .emoticon(emoticon) = mediaContent, let theme = item.associatedData.chatThemes.first(where: { $0.emoticon?.strippedEmoji == emoticon.strippedEmoji }), let themeWallpaper = theme.settings?.first?.wallpaper, let themeWallpaperContent = WallpaperPreviewMedia(wallpaper: themeWallpaper)?.content { if case let .emoticon(emoticon) = mediaContent, let theme = item.associatedData.chatThemes.first(where: { $0.emoticon?.strippedEmoji == emoticon.strippedEmoji }) {
let themeSettings: TelegramThemeSettings?
if let matching = theme.settings?.first(where: { $0.baseTheme == item.presentationData.theme.theme.referenceTheme.baseTheme }) {
themeSettings = matching
} else {
themeSettings = theme.settings?.first
}
if let themeWallpaper = themeSettings?.wallpaper, let themeWallpaperContent = WallpaperPreviewMedia(wallpaper: themeWallpaper)?.content {
mediaContent = themeWallpaperContent mediaContent = themeWallpaperContent
} }
}
switch mediaContent { switch mediaContent {
case let .file(file, patternColors, rotation, intensity, _, _): case let .file(file, patternColors, rotation, intensity, _, _):

View File

@ -77,33 +77,34 @@ public final class DrawingWallpaperRenderer {
} }
public final class DrawingMessageRenderer { public final class DrawingMessageRenderer {
class ContainerNode: ASDisplayNode {
private let context: AccountContext private let context: AccountContext
private let messages: [Message] private let messages: [Message]
private let isNight: Bool
private let containerNode: ASDisplayNode
private let messagesContainerNode: ASDisplayNode private let messagesContainerNode: ASDisplayNode
private var avatarHeaderNode: ListViewItemHeaderNode? private var avatarHeaderNode: ListViewItemHeaderNode?
private var messageNodes: [ListViewItemNode]? private var messageNodes: [ListViewItemNode]?
public init(context: AccountContext, messages: [Message]) { init(context: AccountContext, messages: [Message], isNight: Bool = false) {
self.context = context self.context = context
self.messages = messages self.messages = messages
self.isNight = isNight
self.containerNode = ASDisplayNode()
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.clipsToBounds = true self.messagesContainerNode.clipsToBounds = true
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0) self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.containerNode.addSubnode(self.messagesContainerNode) super.init()
self.addSubnode(self.messagesContainerNode)
} }
public func render(completion: @escaping (CGSize, UIImage?, UIImage?) -> Void) { public func render(completion: @escaping (CGSize, UIImage?) -> Void) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let defaultPresentationData = defaultPresentationData() let defaultPresentationData = defaultPresentationData()
let mockPresentationData = PresentationData( var mockPresentationData = PresentationData(
strings: presentationData.strings, strings: presentationData.strings,
theme: defaultPresentationTheme, theme: defaultPresentationTheme,
autoNightModeTriggered: false, autoNightModeTriggered: false,
@ -118,25 +119,24 @@ public final class DrawingMessageRenderer {
largeEmoji: true largeEmoji: true
) )
if self.isNight {
let darkTheme = defaultDarkColorPresentationTheme
mockPresentationData = mockPresentationData.withUpdated(theme: darkTheme).withUpdated(chatWallpaper: darkTheme.chat.defaultWallpaper)
}
let layout = ContainerViewLayout(size: CGSize(width: 360.0, height: 640.0), metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact, orientation: .portrait), deviceMetrics: .iPhoneX, intrinsicInsets: .zero, safeInsets: .zero, additionalInsets: .zero, statusBarHeight: 0.0, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false) let layout = ContainerViewLayout(size: CGSize(width: 360.0, height: 640.0), metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact, orientation: .portrait), deviceMetrics: .iPhoneX, intrinsicInsets: .zero, safeInsets: .zero, additionalInsets: .zero, statusBarHeight: 0.0, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false)
let size = self.updateMessagesLayout(layout: layout, presentationData: mockPresentationData) let size = self.updateMessagesLayout(layout: layout, presentationData: mockPresentationData)
Queue.mainQueue().after(0.01, { Queue.mainQueue().after(0.03, {
self.generate(size: size) { dayImage in self.generate(size: size) { image in
let darkTheme = defaultDarkColorPresentationTheme completion(size, image)
let darkPresentationData = mockPresentationData.withUpdated(theme: darkTheme)
let _ = self.updateMessagesLayout(layout: layout, presentationData: darkPresentationData)
self.generate(size: size) { nightImage in
completion(size, dayImage, nightImage)
}
} }
}) })
} }
private func generate(size: CGSize, completion: @escaping (UIImage) -> Void) { private func generate(size: CGSize, completion: @escaping (UIImage) -> Void) {
UIGraphicsBeginImageContextWithOptions(size, false, 3.0) UIGraphicsBeginImageContextWithOptions(size, false, 3.0)
self.containerNode.view.drawHierarchy(in: CGRect(origin: CGPoint(), size: size), afterScreenUpdates: true) self.view.drawHierarchy(in: CGRect(origin: CGPoint(), size: size), afterScreenUpdates: true)
let img = UIGraphicsGetImageFromCurrentImageContext() let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext() UIGraphicsEndImageContext()
@ -248,9 +248,46 @@ public final class DrawingMessageRenderer {
avatarHeaderNode.updateLayout(size: size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right) avatarHeaderNode.updateLayout(size: size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
let containerSize = CGSize(width: width + leftInset + 6.0, height: height) let containerSize = CGSize(width: width + leftInset + 6.0, height: height)
self.containerNode.frame = CGRect(origin: CGPoint(), size: containerSize) self.frame = CGRect(origin: CGPoint(), size: containerSize)
self.messagesContainerNode.frame = CGRect(origin: CGPoint(), size: containerSize) self.messagesContainerNode.frame = CGRect(origin: CGPoint(), size: containerSize)
return containerSize return containerSize
} }
} }
private let context: AccountContext
private let messages: [Message]
private let dayContainerNode: ContainerNode
private let nightContainerNode: ContainerNode
public init(context: AccountContext, messages: [Message]) {
self.context = context
self.messages = messages
self.dayContainerNode = ContainerNode(context: context, messages: messages)
self.nightContainerNode = ContainerNode(context: context, messages: messages, isNight: true)
}
public func render(completion: @escaping (CGSize, UIImage?, UIImage?) -> Void) {
var finalSize: CGSize = .zero
var dayImage: UIImage?
var nightImage: UIImage?
let completeIfReady = {
if let dayImage, let nightImage {
completion(finalSize, dayImage, nightImage)
}
}
self.dayContainerNode.render { size, image in
finalSize = size
dayImage = image
completeIfReady()
}
self.nightContainerNode.render { size, image in
finalSize = size
nightImage = image
completeIfReady()
}
}
}

View File

@ -258,8 +258,8 @@ final class ThemeGridControllerNode: ASDisplayNode {
if case let .peer(_, _, _, _, customLevel) = mode { if case let .peer(_, _, _, _, customLevel) = mode {
requiredCustomWallpaperLevel = customLevel requiredCustomWallpaperLevel = customLevel
} }
//TODO:localize
self.galleryItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Image"), color: presentationData.theme.list.itemAccentColor), title: presentationData.strings.Wallpaper_SetCustomBackground, additionalBadgeIcon: requiredCustomWallpaperLevel.flatMap { generateDisclosureActionBoostLevelBadgeImage(text: "Level \($0)") }, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .accent, editing: false, action: { self.galleryItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Image"), color: presentationData.theme.list.itemAccentColor), title: presentationData.strings.Wallpaper_SetCustomBackground, additionalBadgeIcon: requiredCustomWallpaperLevel.flatMap { generateDisclosureActionBoostLevelBadgeImage(text: presentationData.strings.ChannelAppearance_BoostLevel("\($0)").string) }, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .accent, editing: false, action: {
presentGallery() presentGallery()
}) })
self.galleryItemNode = ItemListPeerActionItemNode() self.galleryItemNode = ItemListPeerActionItemNode()
@ -684,7 +684,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
if case let .peer(_, _, _, _, customLevel) = mode { if case let .peer(_, _, _, _, customLevel) = mode {
requiredCustomWallpaperLevel = customLevel requiredCustomWallpaperLevel = customLevel
} }
self.galleryItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Image"), color: presentationData.theme.list.itemAccentColor), title: presentationData.strings.Wallpaper_SetCustomBackground, additionalBadgeIcon: requiredCustomWallpaperLevel.flatMap { generateDisclosureActionBoostLevelBadgeImage(text: "Level \($0)") }, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .accent, editing: false, action: { [weak self] in self.galleryItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Attach Menu/Image"), color: presentationData.theme.list.itemAccentColor), title: presentationData.strings.Wallpaper_SetCustomBackground, additionalBadgeIcon: requiredCustomWallpaperLevel.flatMap { generateDisclosureActionBoostLevelBadgeImage(text: presentationData.strings.ChannelAppearance_BoostLevel("\($0)").string) }, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .accent, editing: false, action: { [weak self] in
self?.presentGallery() self?.presentGallery()
}) })
self.removeItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.list.itemDestructiveColor), title: presentationData.strings.Wallpaper_ChannelRemoveBackground, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .destructive, editing: false, action: { [weak self] in self.removeItem = ItemListPeerActionItem(presentationData: ItemListPresentationData(presentationData), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: presentationData.theme.list.itemDestructiveColor), title: presentationData.strings.Wallpaper_ChannelRemoveBackground, alwaysPlain: false, hasSeparator: true, sectionId: 0, height: .generic, color: .destructive, editing: false, action: { [weak self] in
@ -805,7 +805,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
var hasCustomWallpaper = false var hasCustomWallpaper = false
if case let .peer(_, _, wallpaper, _, _) = self.mode { if case let .peer(_, _, wallpaper, _, _) = self.mode {
isChannel = true isChannel = true
if let wallpaper, !wallpaper.isPattern { if let wallpaper, !wallpaper.isEmoticon {
hasCustomWallpaper = true hasCustomWallpaper = true
} }
} }

View File

@ -979,7 +979,7 @@ public final class StoryItemSetContainerComponent: Component {
return abs(rotatedX) <= area.coordinates.width / 100.0 * referenceSize.width / 2.0 * 1.1 && abs(rotatedY) <= area.coordinates.height / 100.0 * referenceSize.height / 2.0 * 1.1 return abs(rotatedX) <= area.coordinates.width / 100.0 * referenceSize.width / 2.0 * 1.1 && abs(rotatedY) <= area.coordinates.height / 100.0 * referenceSize.height / 2.0 * 1.1
} }
for area in component.slice.item.storyItem.mediaAreas { for area in component.slice.item.storyItem.mediaAreas.reversed() {
if case .reaction = area { if case .reaction = area {
continue continue
} }

View File

@ -2415,14 +2415,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self, let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first { if let strongSelf = self, let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first {
let chatPresentationInterfaceState = strongSelf.presentationInterfaceState let chatPresentationInterfaceState = strongSelf.presentationInterfaceState
var warnAboutPrivate = false var warnAboutPrivate = false
var canShareToStory = false
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = message.peers[message.id.peerId] as? TelegramChannel { if case .peer = chatPresentationInterfaceState.chatLocation, let channel = message.peers[message.id.peerId] as? TelegramChannel {
canShareToStory = true
if channel.addressName == nil { if channel.addressName == nil {
warnAboutPrivate = true warnAboutPrivate = true
} }
} }
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), updatedPresentationData: strongSelf.updatedPresentationData, shareAsLink: true) let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), updatedPresentationData: strongSelf.updatedPresentationData, shareAsLink: true)
var canShareToStory = true
if let message = messages.first, message.media.contains(where: { media in if let message = messages.first, message.media.contains(where: { media in
if media is TelegramMediaContact || media is TelegramMediaPoll { if media is TelegramMediaContact || media is TelegramMediaPoll {
return true return true
@ -6376,7 +6377,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var useDarkAppearance = presentationData.theme.overallDarkAppearance var useDarkAppearance = presentationData.theme.overallDarkAppearance
if let wallpaper = chatWallpaper, case let .emoticon(wallpaperEmoticon) = wallpaper, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == wallpaperEmoticon.strippedEmoji }) { if let wallpaper = chatWallpaper, case let .emoticon(wallpaperEmoticon) = wallpaper, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == wallpaperEmoticon.strippedEmoji }) {
if let themeWallpaper = theme.settings?.first?.wallpaper { let themeSettings: TelegramThemeSettings?
if let matching = theme.settings?.first(where: { $0.baseTheme == presentationData.theme.referenceTheme.baseTheme }) {
themeSettings = matching
} else {
themeSettings = theme.settings?.first
}
if let themeWallpaper = themeSettings?.wallpaper {
chatWallpaper = themeWallpaper chatWallpaper = themeWallpaper
} }
} }