Merge commit '057a7cc148fb77bcb8f58b8135c8ccb99725b5d4'

This commit is contained in:
Ali 2022-01-11 23:34:55 +04:00
commit 1831f1e84b
24 changed files with 221 additions and 56 deletions

Binary file not shown.

View File

@ -535,7 +535,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@ -569,7 +569,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@ -965,7 +965,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let leftInset: CGFloat = params.leftInset + avatarLeftInset
enum ContentData {
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String)
case chat(itemPeer: EngineRenderedPeer, peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?)
case group(peers: [EngineChatList.GroupItem.Item])
}
@ -974,14 +974,14 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var hideAuthor = false
switch contentPeer {
case let .chat(itemPeer):
var (peer, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
var (peer, initialHideAuthor, messageText, spoilers) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText {
initialHideAuthor = true
messageText = psaText
}
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText)
contentData = .chat(itemPeer: itemPeer, peer: peer, hideAuthor: hideAuthor, messageText: messageText, spoilers: spoilers)
hideAuthor = initialHideAuthor
case let .group(groupPeers):
contentData = .group(peers: groupPeers)
@ -1012,7 +1012,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var contentImageSpecs: [(message: EngineMessage, media: EngineMedia, size: CGSize)] = []
switch contentData {
case let .chat(itemPeer, _, _, text):
case let .chat(itemPeer, _, _, text, spoilers):
var isUser = false
if case .user = itemPeer.chatMainPeer {
isUser = true
@ -1039,7 +1039,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
messageText = currentChatListText.1
chatListText = currentChatListText
} else {
messageText = foldLineBreaks(text)
if let spoilers = spoilers, !spoilers.isEmpty {
messageText = text
} else {
messageText = foldLineBreaks(text)
}
chatListText = (text, messageText)
}
@ -1053,6 +1057,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else if let message = messages.last {
var composedString: NSMutableAttributedString
if let peerText = peerText {
authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor)
}
let entities = (message._asMessage().textEntitiesAttribute?.entities ?? []).filter { entity in
if case .Spoiler = entity.type {
return true
@ -1062,7 +1070,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
let messageString: NSAttributedString
if !message.text.isEmpty && entities.count > 0 {
messageString = stringWithAppliedEntities(message.text, entities: entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
messageString = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: authorAttributedString == nil ? 2 : 1), entities: entities, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
} else if let spoilers = spoilers {
let mutableString = NSMutableAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
for range in spoilers {
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
}
messageString = mutableString
} else {
messageString = NSAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
}
@ -1109,9 +1123,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
attributedText = composedString
if let peerText = peerText {
authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor)
}
var displayMediaPreviews = true
if message._asMessage().containsSecretMedia {
@ -1202,7 +1214,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
switch contentData {
case let .chat(itemPeer, _, _, _):
case let .chat(itemPeer, _, _, _, _):
if let message = messages.last, case let .user(author) = message.author, displayAsMessage {
titleAttributedString = NSAttributedString(string: author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer.user(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: titleFont, textColor: theme.titleColor)
} else if isPeerGroup {

View File

@ -44,13 +44,14 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType {
return currentType
}
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String) {
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?) {
let peer: EnginePeer?
let message = messages.last
var hideAuthor = false
var messageText: String
var spoilers: [NSRange]?
if let message = message {
if let messageMain = messageMainPeer(message) {
peer = messageMain
@ -268,12 +269,13 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
}
default:
hideAuthor = true
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
if let (text, textSpoilers) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
messageText = text
spoilers = textSpoilers
}
}
case _ as TelegramMediaExpiredContent:
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
if let (text, _) = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: true) {
messageText = text
}
case let poll as TelegramMediaPoll:
@ -312,5 +314,5 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
}
}
return (peer, hideAuthor, messageText)
return (peer, hideAuthor, messageText, spoilers)
}

View File

@ -409,8 +409,15 @@ open class NavigationController: UINavigationController, ContainableController,
let overlayContainerLayout = layout
if let inCallStatusBar = self.inCallStatusBar {
var inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(layout.statusBarHeight ?? 0.0, max(40.0, layout.safeInsets.top))))
if layout.deviceMetrics.hasTopNotch {
let isLandscape = layout.size.width > layout.size.height
var minHeight: CGFloat
if case .compact = layout.metrics.widthClass, isLandscape {
minHeight = 22.0
} else {
minHeight = 40.0
}
var inCallStatusBarFrame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: max(layout.statusBarHeight ?? 0.0, max(minHeight, layout.safeInsets.top))))
if layout.deviceMetrics.hasTopNotch && !isLandscape {
inCallStatusBarFrame.size.height += 12.0
}
if inCallStatusBar.frame.isEmpty {

View File

@ -182,10 +182,12 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
}
func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
var nodeHeight: CGFloat = (self.peerNodes.isEmpty ? 264.0 : 364.0)
let showPeers = !self.peerNodes.isEmpty && !isLandscape
var nodeHeight: CGFloat = (!showPeers ? 236.0 : 320.0)
let paddedSize = CGSize(width: size.width - 60.0, height: size.height)
self.peersScrollNode.isHidden = !showPeers
var aboutSize: CGSize?
var descriptionSize: CGSize?
if self.aboutNode.supernode != nil {
@ -210,14 +212,16 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
descriptionSize = measuredSize
}
let constrainSize = CGSize(width: size.width - 32.0, height: size.height)
let titleSize = self.titleNode.measure(constrainSize)
nodeHeight += titleSize.height
let verticalOrigin = size.height - nodeHeight
let avatarSize: CGFloat = 100.0
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: floor((size.width - avatarSize) / 2.0), y: verticalOrigin + 32.0), size: CGSize(width: avatarSize, height: avatarSize)))
let constrainSize = CGSize(width: size.width - 32.0, height: size.height)
let titleSize = self.titleNode.measure(constrainSize)
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: verticalOrigin + 27.0 + avatarSize + 15.0), size: titleSize))
let countSize = self.countNode.measure(constrainSize)
@ -246,9 +250,9 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
}
self.peersScrollNode.view.contentSize = CGSize(width: CGFloat(self.peerNodes.count) * peerSize.width + (self.moreNode != nil ? peerSize.width : 0.0) + peerInset * 2.0, height: peerSize.height)
transition.updateFrame(node: self.peersScrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin + 210.0), size: CGSize(width: size.width, height: peerSize.height)))
transition.updateFrame(node: self.peersScrollNode, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOrigin + 27.0 + avatarSize + 15.0 + titleSize.height + 3.0 + countSize.height + 12.0), size: CGSize(width: size.width, height: peerSize.height)))
if !self.peerNodes.isEmpty {
if showPeers {
verticalOffset += 100.0
}

View File

@ -95,6 +95,8 @@ swift_library(
"//submodules/Components/ReactionImageComponent:ReactionImageComponent",
"//submodules/Translate:Translate",
"//submodules/QrCodeUI:QrCodeUI",
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
],
visibility = [
"//visibility:public",

View File

@ -13,6 +13,15 @@ enum PrivacyIntroControllerMode {
case passcode
case twoStepVerification
var animationName: String? {
switch self {
case .passcode:
return "Passcode"
case .twoStepVerification:
return nil
}
}
func icon(theme: PresentationTheme) -> UIImage? {
switch self {
case .passcode:

View File

@ -8,6 +8,8 @@ import SwiftSignalKit
import TelegramPresentationData
import AccountContext
import AuthorizationUI
import AnimatedStickerNode
import TelegramAnimatedStickerNode
private func generateButtonImage(backgroundColor: UIColor, highlightColor: UIColor?) -> UIImage? {
return generateImage(CGSize(width: 24.0, height: 44.0), contextGenerator: { size, context in
@ -39,6 +41,7 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
private let proceedAction: () -> Void
private let iconNode: ASImageNode
private let animationNode: AnimatedStickerNode
private let titleNode: ASTextNode
private let textNode: ASTextNode
private let buttonNode: HighlightTrackingButtonNode
@ -55,6 +58,8 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
self.proceedAction = proceedAction
self.iconNode = ASImageNode()
self.animationNode = AnimatedStickerNode()
self.titleNode = ASTextNode()
self.textNode = ASTextNode()
self.buttonNode = HighlightTrackingButtonNode()
@ -68,7 +73,19 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
super.init()
if let animationName = mode.animationName {
self.iconNode.isHidden = true
self.animationNode.isHidden = false
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animationName), width: 380, height: 380, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
self.animationNode.visibility = true
} else {
self.iconNode.isHidden = false
self.animationNode.isHidden = true
}
self.addSubnode(self.iconNode)
self.addSubnode(self.animationNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.textNode)
self.addSubnode(self.buttonBackgroundNode)
@ -98,7 +115,9 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
self.presentationData = presentationData
self.backgroundColor = presentationData.theme.list.blocksBackgroundColor
self.iconNode.image = self.mode.icon(theme: presentationData.theme)
if self.animationNode.isHidden {
self.iconNode.image = self.mode.icon(theme: presentationData.theme)
}
self.titleNode.attributedText = NSAttributedString(string: self.mode.title(strings: presentationData.strings), font: titleFont, textColor: presentationData.theme.list.sectionHeaderTextColor, paragraphAlignment: .center)
self.textNode.attributedText = NSAttributedString(string: self.mode.text(strings: presentationData.strings), font: textFont, textColor: presentationData.theme.list.freeTextColor, paragraphAlignment: .center)
self.noticeNode.attributedText = NSAttributedString(string: self.mode.notice(strings: presentationData.strings), font: textFont, textColor: presentationData.theme.list.freeTextColor, paragraphAlignment: .center)
@ -120,7 +139,18 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
insets.top += navigationBarHeight
var iconSize = CGSize()
if let size = self.iconNode.image?.size {
var animationSize = CGSize()
if !self.animationNode.isHidden {
animationSize = CGSize(width: 180.0, height: 180.0)
self.animationNode.updateLayout(size: animationSize)
var iconAlpha: CGFloat = 1.0
if case .compact = layout.metrics.widthClass, layout.size.width > layout.size.height {
iconAlpha = 0.0
iconSize = CGSize()
}
transition.updateAlpha(node: self.animationNode, alpha: iconAlpha)
} else if let size = self.iconNode.image?.size {
iconSize = size
var iconAlpha: CGFloat = 1.0
@ -142,9 +172,10 @@ final class PrivacyIntroControllerNode: ViewControllerTracingNode {
} else {
buttonInset = 0.0
}
let items: [AuthorizationLayoutItem] = [
AuthorizationLayoutItem(node: self.iconNode, size: iconSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
AuthorizationLayoutItem(node: self.animationNode, size: animationSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 20.0, maxValue: 30.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
AuthorizationLayoutItem(node: self.textNode, size: textSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 16.0, maxValue: 16.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
AuthorizationLayoutItem(node: self.buttonNode, size: CGSize(width: layout.size.width - buttonInset * 2.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 40.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),

View File

@ -200,17 +200,17 @@ private final class CallVideoNode: ASDisplayNode, PreviewVideoNode {
case .rotation90:
rotationAngle = CGFloat.pi / 2.0
case .rotation180:
if isCompactLayout {
// if isCompactLayout {
rotationAngle = CGFloat.pi
} else {
rotationAngle = 0.0
}
// } else {
// rotationAngle = 0.0
// }
case .rotation270:
if isCompactLayout {
// if isCompactLayout {
rotationAngle = -CGFloat.pi / 2.0
} else {
rotationAngle = CGFloat.pi / 2.0
}
// } else {
// rotationAngle = CGFloat.pi / 2.0
// }
}
var additionalAngle: CGFloat = 0.0

View File

@ -165,7 +165,7 @@ public func mediaContentKind(_ media: EngineMedia, message: EngineMessage? = nil
}
case .action:
if let message = message, let strings = strings, let nameDisplayOrder = nameDisplayOrder, let accountPeerId = accountPeerId {
return .text(plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat ?? PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), message: message, accountPeerId: accountPeerId, forChatList: false) ?? "")
return .text(plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat ?? PresentationDateTimeFormat(timeFormat: .military, dateFormat: .dayFirst, dateSeparator: ".", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), message: message, accountPeerId: accountPeerId, forChatList: false)?.0 ?? "")
} else {
return nil
}
@ -253,3 +253,20 @@ public func foldLineBreaks(_ text: String) -> String {
}
return result
}
public func trimToLineCount(_ text: String, lineCount: Int) -> String {
if lineCount < 1 {
return ""
}
let lines = text.split { $0.isNewline }
var result = ""
for line in lines.prefix(lineCount) {
if !result.isEmpty {
result += "\n"
}
result += line
}
return result
}

View File

@ -11,6 +11,10 @@ import Markdown
private let titleFont = Font.regular(13.0)
private let titleBoldFont = Font.bold(13.0)
private func spoilerAttributes(primaryTextColor: UIColor) -> MarkdownAttributeSet {
return MarkdownAttributeSet(font: titleFont, textColor: primaryTextColor, additionalAttributes: [TelegramTextAttributes.Spoiler: true])
}
private func peerMentionAttributes(primaryTextColor: UIColor, peerId: EnginePeer.Id) -> MarkdownAttributeSet {
return MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [TelegramTextAttributes.PeerMention: TelegramPeerMention(peerId: peerId, mention: "")])
}
@ -25,8 +29,18 @@ private func peerMentionsAttributes(primaryTextColor: UIColor, peerIds: [(Int, E
return result
}
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> String? {
return universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList)?.string
public func plainServiceMessageString(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> (String, [NSRange])? {
if let attributedString = universalServiceMessageString(presentationData: nil, strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: forChatList) {
var ranges: [NSRange] = []
attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: [], using: { attributes, range, _ in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)] {
ranges.append(range)
}
})
return (attributedString.string, ranges)
} else {
return nil
}
}
public func universalServiceMessageString(presentationData: (PresentationTheme, TelegramWallpaper)?, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id, forChatList: Bool) -> NSAttributedString? {
@ -137,7 +151,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
case .pinnedMessageUpdated:
enum PinnnedMediaType {
case text(String)
case text(String, [MessageTextEntity])
case game
case photo
case video
@ -160,8 +174,15 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
var type: PinnnedMediaType
if let pinnedMessage = pinnedMessage {
type = .text(pinnedMessage.text)
if let pinnedMessage = pinnedMessage?._asMessage() {
let entities = (pinnedMessage.textEntitiesAttribute?.entities ?? []).filter { entity in
if case .Spoiler = entity.type {
return true
} else {
return false
}
}
type = .text(pinnedMessage.text, entities)
inner: for media in pinnedMessage.media {
if media is TelegramMediaGame {
type = .game
@ -213,8 +234,13 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
}
switch type {
case let .text(text):
var clippedText = text.replacingOccurrences(of: "\n", with: " ")
case let .text(text, entities):
var clippedText = text
if !entities.isEmpty {
clippedText = trimToLineCount(clippedText, lineCount: 1)
} else {
clippedText = clippedText.replacingOccurrences(of: "\n", with: " ")
}
if clippedText.count > 14 {
clippedText = "\(clippedText[...clippedText.index(clippedText.startIndex, offsetBy: 14)])..."
}
@ -224,7 +250,21 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} else {
textWithRanges = strings.Notification_PinnedTextMessage(authorName, clippedText)
}
attributedString = addAttributesToStringWithRanges(textWithRanges._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
let string = textWithRanges._tuple.0
let stringLength = (clippedText as NSString).length
var ranges = textWithRanges._tuple.1
let entityOffset = ranges.first(where: { $0.0 == 1 })?.1.location ?? 0
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
for entity in entities {
if entity.range.startIndex >= stringLength {
continue
}
let index = ranges.count
ranges.append((ranges.count, NSRange(location: entityOffset + entity.range.startIndex, length: entity.range.count)))
attributes[index] = spoilerAttributes(primaryTextColor: primaryTextColor)
}
attributedString = addAttributesToStringWithRanges((string, ranges), body: bodyAttributes, argumentAttributes: attributes)
case .game:
attributedString = addAttributesToStringWithRanges(strings.Message_AuthorPinnedGame(authorName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
case .photo:

File diff suppressed because one or more lines are too long

View File

@ -3961,7 +3961,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
var renderedPeer: RenderedPeer?
var contactStatus: ChatContactStatus?
var copyProtectionEnabled: Bool = false
if let peer = peerView.peers[peerView.peerId] {
copyProtectionEnabled = peer.isCopyProtectionEnabled
if let cachedData = peerView.cachedData as? CachedUserData {
contactStatus = ChatContactStatus(canAddContact: !peerView.peerIsContact, canReportIrrelevantLocation: false, peerStatusSettings: cachedData.peerStatusSettings, invitedBy: nil)
} else if let cachedData = peerView.cachedData as? CachedGroupData {
@ -4087,6 +4089,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return $0.updatedPeer { _ in
return renderedPeer
}.updatedIsNotAccessible(isNotAccessible).updatedContactStatus(contactStatus).updatedHasBots(hasBots).updatedIsArchived(isArchived).updatedPeerIsMuted(peerIsMuted).updatedPeerDiscussionId(peerDiscussionId).updatedPeerGeoLocation(peerGeoLocation).updatedExplicitelyCanPinMessages(explicitelyCanPinMessages).updatedHasScheduledMessages(false).updatedCurrentSendAsPeerId(currentSendAsPeerId)
.updatedCopyProtectionEnabled(copyProtectionEnabled)
})
if !strongSelf.didSetChatLocationInfoReady {
strongSelf.didSetChatLocationInfoReady = true
@ -8715,7 +8718,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
interfaceState = interfaceState.withUpdatedHistoryScrollState(scrollState)
}
interfaceState = interfaceState.withUpdatedInputLanguage(self.chatDisplayNode.currentTextInputLanguage)
if interfaceState.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
if interfaceState.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && interfaceState.replyMessageId == nil {
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: "")))
}
let _ = ChatInterfaceState.update(engine: self.context.engine, peerId: peerId, threadId: threadId, { _ in

View File

@ -277,6 +277,12 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if attribute is ViewCountMessageAttribute{
return false
}
if attribute is ForwardCountMessageAttribute {
return false
}
if attribute is ReactionsMessageAttribute {
return false
}
return true
})

View File

@ -17,6 +17,7 @@ import UniversalMediaPlayer
import TelegramUniversalVideoContent
import GalleryUI
import WallpaperBackgroundNode
import InvisibleInkDustNode
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, accountPeerId: PeerId) -> NSAttributedString? {
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: false)
@ -24,6 +25,7 @@ private func attributedServiceMessageString(theme: ChatPresentationThemeData, st
class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
let labelNode: TextNode
private var dustNode: InvisibleInkDustNode?
var backgroundNode: WallpaperBubbleBackgroundNode?
var backgroundColorNode: ASDisplayNode
let backgroundMaskNode: ASImageNode
@ -277,6 +279,25 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
strongSelf.labelNode.frame = labelFrame
strongSelf.backgroundColorNode.backgroundColor = selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper)
if !labelLayout.spoilers.isEmpty {
let dustColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
let dustNode: InvisibleInkDustNode
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode.isUserInteractionEnabled = false
strongSelf.dustNode = dustNode
strongSelf.insertSubnode(dustNode, aboveSubnode: strongSelf.labelNode)
}
dustNode.frame = labelFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 1.0)
dustNode.update(size: dustNode.frame.size, color: dustColor, textColor: dustColor, rects: labelLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: labelLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
} else if let dustNode = strongSelf.dustNode {
dustNode.removeFromSupernode()
strongSelf.dustNode = nil
}
let baseBackgroundFrame = labelFrame.offsetBy(dx: 0.0, dy: -11.0)
if let (offset, image) = backgroundMaskImage {

View File

@ -206,7 +206,7 @@ final class ChatMessageAccessibilityData {
if let chatPeer = message.peers[item.message.id.peerId] {
let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
let (_, _, messageText, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
var text = messageText

View File

@ -876,6 +876,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
self.votersNode.contentMode = .topLeft
self.votersNode.contentsScale = UIScreenScale
self.votersNode.displaysAsynchronously = false
self.votersNode.clipsToBounds = true
var displaySolution: (() -> Void)?
self.solutionButtonNode = SolutionButtonNode(pressed: {

View File

@ -106,7 +106,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
}
}
if entities.count > 0 {
messageText = stringWithAppliedEntities(message.text, entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
messageText = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
} else {
messageText = NSAttributedString(string: textString, font: textFont, textColor: textColor)
}

View File

@ -468,7 +468,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
}
let textColor = theme.chat.inputPanel.primaryTextColor
if entities.count > 0 {
messageText = stringWithAppliedEntities(message.text, entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
messageText = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
} else {
messageText = NSAttributedString(string: foldLineBreaks(textString), font: textFont, textColor: textColor)
}

View File

@ -1597,9 +1597,9 @@ private class QrContentNode: ASDisplayNode, ContentNode {
self.codeTextNode.attributedText = NSAttributedString(string: self.codeTextNode.attributedText?.string ?? "", font: Font.with(size: fontSize, design: .round, weight: .bold, traits: []), textColor: .black)
let codeBackgroundWidth = size.width - codeInset * 2.0
let codeBackgroundWidth = min(300.0, size.width - codeInset * 2.0)
let codeBackgroundHeight = floor(codeBackgroundWidth * 1.1)
let codeBackgroundFrame = CGRect(x: codeInset, y: topInset + floor((size.height - bottomInset - codeBackgroundHeight) / 2.0), width: codeBackgroundWidth, height: codeBackgroundHeight)
let codeBackgroundFrame = CGRect(x: floor((size.width - codeBackgroundWidth) / 2.0), y: topInset + floor((size.height - bottomInset - codeBackgroundHeight) / 2.0), width: codeBackgroundWidth, height: codeBackgroundHeight)
transition.updateFrame(node: self.codeBackgroundNode, frame: codeBackgroundFrame)
transition.updateFrame(node: self.codeForegroundNode, frame: codeBackgroundFrame)
transition.updateFrame(node: self.codeMaskNode, frame: CGRect(origin: CGPoint(), size: codeBackgroundFrame.size))

View File

@ -49,6 +49,9 @@ private func chatInputStateString(attributedString: NSAttributedString) -> NSAtt
string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range)
}
}
if let value = attributes[.backgroundColor] as? UIColor, value.rgb == UIColor.gray.rgb {
string.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: range)
}
if let _ = attributes[.strikethroughStyle] {
string.addAttribute(ChatTextInputAttributes.strikethrough, value: true as NSNumber, range: range)
}

View File

@ -135,7 +135,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
let textColor = strongSelf.theme.chat.inputPanel.primaryTextColor
if entities.count > 0 {
messageText = stringWithAppliedEntities(message.text, entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
messageText = stringWithAppliedEntities(trimToLineCount(message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false)
} else {
messageText = NSAttributedString(string: text, font: textFont, textColor: isMedia ? strongSelf.theme.chat.inputPanel.secondaryTextColor : strongSelf.theme.chat.inputPanel.primaryTextColor)
}

View File

@ -69,7 +69,9 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
if nsString == nil {
nsString = text as NSString
}
if range.location + range.length > stringLength {
if range.location > stringLength {
continue
} else if range.location + range.length > stringLength {
range.location = max(0, stringLength - range.length)
range.length = stringLength - range.location
}
@ -226,7 +228,11 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti
}
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard), value: nsString!.substring(with: range), range: range)
case .Spoiler:
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true as NSNumber, range: range)
if external {
string.addAttribute(NSAttributedString.Key.backgroundColor, value: UIColor.gray, range: range)
} else {
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true as NSNumber, range: range)
}
case let .Custom(type):
if type == ApplicationSpecificEntityType.Timecode {
string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range)

View File

@ -11,11 +11,12 @@ private final class LinkHelperClass: NSObject {
public var supportedTranslationLanguages = [
"en",
"ar",
"zh",
"zh-Hans",
"zh-Hant",
"fr",
"de",
"it",
"jp",
"ja",
"ko",
"pt",
"ru",