Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2024-05-25 02:30:29 +04:00
commit d90fc9b982
10 changed files with 85 additions and 32 deletions

View File

@ -12160,6 +12160,7 @@ Sorry for the inconvenience.";
"Chat.AdminActionSheet.BanFooterMultiple" = "Fully ban users"; "Chat.AdminActionSheet.BanFooterMultiple" = "Fully ban users";
"Chat.AdminActionSheet.RestrictFooterMultiple" = "Partially restrict users"; "Chat.AdminActionSheet.RestrictFooterMultiple" = "Partially restrict users";
"Chat.AdminActionSheet.PermissionsSectionHeader" = "WHAT CAN THIS USER DO?"; "Chat.AdminActionSheet.PermissionsSectionHeader" = "WHAT CAN THIS USER DO?";
"Chat.AdminActionSheet.PermissionsSectionHeaderMultiple" = "WHAT CAN THESE USERS DO?";
"Chat.AdminActionSheet.ActionButton" = "Proceed"; "Chat.AdminActionSheet.ActionButton" = "Proceed";
"Chat.AdminAction.ToastMessagesDeletedTitleSingle" = "Message Deleted"; "Chat.AdminAction.ToastMessagesDeletedTitleSingle" = "Message Deleted";

View File

@ -550,18 +550,24 @@ public struct ChatTextInputStateText: Codable, Equatable {
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .underline, range: range.location ..< (range.location + range.length))) parsedAttributes.append(ChatTextInputStateTextAttribute(type: .underline, range: range.location ..< (range.location + range.length)))
} else if key == ChatTextInputAttributes.spoiler { } else if key == ChatTextInputAttributes.spoiler {
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .spoiler, range: range.location ..< (range.location + range.length))) parsedAttributes.append(ChatTextInputStateTextAttribute(type: .spoiler, range: range.location ..< (range.location + range.length)))
} else if key == ChatTextInputAttributes.block, let value = value as? ChatTextInputTextQuoteAttribute {
switch value.kind {
case .quote:
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length)))
case let .code(language):
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length)))
}
} else if key == ChatTextInputAttributes.collapsedBlock, let value = value as? NSAttributedString {
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length)))
} }
} }
}) })
attributedText.enumerateAttribute(ChatTextInputAttributes.block, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in
if let value = value as? ChatTextInputTextQuoteAttribute {
switch value.kind {
case .quote:
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote(isCollapsed: value.isCollapsed), range: range.location ..< (range.location + range.length)))
case let .code(language):
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length)))
}
}
})
attributedText.enumerateAttribute(ChatTextInputAttributes.collapsedBlock, in: NSRange(location: 0, length: attributedText.length), options: [], using: { value, range, _ in
if let value = value as? NSAttributedString {
parsedAttributes.append(ChatTextInputStateTextAttribute(type: .collapsedQuote(text: ChatTextInputStateText(attributedText: value)), range: range.location ..< (range.location + range.length)))
}
})
self.attributes = parsedAttributes self.attributes = parsedAttributes
} }

View File

@ -470,7 +470,8 @@ public final class ChatInterfaceState: Codable, Equatable {
if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil { if self.composeInputState.inputText.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && self.replyMessageSubject == nil {
return nil return nil
} else { } else {
return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: self.composeInputState.inputText.string, entities: generateChatInputTextEntities(self.composeInputState.inputText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange) let sourceText = expandedInputStateAttributedString(self.composeInputState.inputText)
return SynchronizeableChatInputState(replySubject: self.replyMessageSubject?.subjectModel, text: sourceText.string, entities: generateChatInputTextEntities(sourceText), timestamp: self.timestamp, textSelection: self.composeInputState.selectionRange)
} }
} }

View File

@ -246,7 +246,7 @@ public final class StarsContext {
public let description: String? public let description: String?
public let photo: TelegramMediaWebFile? public let photo: TelegramMediaWebFile?
init( public init(
id: String, id: String,
count: Int64, count: Int64,
date: Int32, date: Int32,

View File

@ -1247,7 +1247,7 @@ private final class AdminUserActionsSheetComponent: Component {
theme: environment.theme, theme: environment.theme,
header: AnyComponent(MultilineTextComponent( header: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString( text: .plain(NSAttributedString(
string: environment.strings.Chat_AdminActionSheet_PermissionsSectionHeader, string: component.peers.count == 1 ? environment.strings.Chat_AdminActionSheet_PermissionsSectionHeader : environment.strings.Chat_AdminActionSheet_PermissionsSectionHeaderMultiple,
font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize),
textColor: environment.theme.list.freeTextColor textColor: environment.theme.list.freeTextColor
)), )),

View File

@ -16,6 +16,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl", "//submodules/TelegramUI/Components/Chat/ChatInputTextNode/ChatInputTextViewImpl",
"//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView", "//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView",
"//submodules/AccountContext", "//submodules/AccountContext",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -7,6 +7,7 @@ import ChatInputTextViewImpl
import MessageInlineBlockBackgroundView import MessageInlineBlockBackgroundView
import TextFormat import TextFormat
import AccountContext import AccountContext
import TextNodeWithEntities
public protocol ChatInputTextNodeDelegate: AnyObject { public protocol ChatInputTextNodeDelegate: AnyObject {
func chatInputTextNodeDidUpdateText() func chatInputTextNodeDidUpdateText()
@ -540,7 +541,19 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal
var startIndex = glyphRange.lowerBound var startIndex = glyphRange.lowerBound
while startIndex < glyphRange.upperBound { while startIndex < glyphRange.upperBound {
var effectiveRange = NSRange(location: NSNotFound, length: 0) var effectiveRange = NSRange(location: NSNotFound, length: 0)
let rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange) var rect = self.customLayoutManager.lineFragmentUsedRect(forGlyphAt: startIndex, effectiveRange: &effectiveRange)
let characterRange = self.customLayoutManager.characterRange(forGlyphRange: NSRange(location: startIndex, length: 1), actualGlyphRange: nil)
if characterRange.location != NSNotFound {
if let attribute = self.customTextStorage.attribute(NSAttributedString.Key("Attribute__Blockquote"), at: characterRange.location, effectiveRange: nil) {
let _ = attribute
rect.size.width += 13.0
} else if let attribute = self.customTextStorage.attribute(.attachment, at: characterRange.location, effectiveRange: nil) as? ChatInputTextCollapsedQuoteAttachment {
let _ = attribute
rect.size.width += 8.0
}
}
if boundingRect.isEmpty { if boundingRect.isEmpty {
boundingRect = rect boundingRect = rect
} else { } else {
@ -552,6 +565,7 @@ private final class ChatInputTextLegacyInternal: NSObject, ChatInputTextInternal
break break
} }
} }
return boundingRect return boundingRect
} }
@ -804,11 +818,12 @@ private let registeredViewProvider: Void = {
public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, ChatInputTextCollapsedQuoteAttachment { public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment, ChatInputTextCollapsedQuoteAttachment {
final class View: UIView { final class View: UIView {
let attachment: ChatInputTextCollapsedQuoteAttachmentImpl let attachment: ChatInputTextCollapsedQuoteAttachmentImpl
let textNode: ImmediateTextNode let textNode: ImmediateTextNodeWithEntities
init(attachment: ChatInputTextCollapsedQuoteAttachmentImpl) { init(attachment: ChatInputTextCollapsedQuoteAttachmentImpl) {
self.attachment = attachment self.attachment = attachment
self.textNode = ImmediateTextNode() self.textNode = ImmediateTextNodeWithEntities()
self.textNode.displaysAsynchronously = false
self.textNode.maximumNumberOfLines = 3 self.textNode.maximumNumberOfLines = 3
super.init(frame: CGRect()) super.init(frame: CGRect())
@ -825,10 +840,6 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
return CGSize(width: 10.0, height: 10.0) return CGSize(width: 10.0, height: 10.0)
} }
/*let renderingText = NSMutableAttributedString(attributedString: attachment.text)
renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length))
renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/
let renderingText = textAttributedStringForStateText( let renderingText = textAttributedStringForStateText(
context: context, context: context,
stateText: attachment.text, stateText: attachment.text,
@ -846,11 +857,11 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
textNode.maximumNumberOfLines = 3 textNode.maximumNumberOfLines = 3
textNode.attributedText = renderingText textNode.attributedText = renderingText
textNode.cutout = TextNodeCutout(topRight: CGSize(width: 40.0, height: 10.0)) textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0))
let layoutInfo = textNode.updateLayoutFullInfo(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height)) let layoutSize = textNode.updateLayout(CGSize(width: constrainedSize.width - 9.0, height: constrainedSize.height))
return CGSize(width: constrainedSize.width, height: 8.0 + layoutInfo.size.height + 8.0) return CGSize(width: constrainedSize.width, height: 8.0 + layoutSize.height + 8.0)
} }
override func layoutSubviews() { override func layoutSubviews() {
@ -876,13 +887,24 @@ public final class ChatInputTextCollapsedQuoteAttachmentImpl: NSTextAttachment,
renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length)) renderingText.addAttribute(.font, value: attachment.attributes.font, range: NSRange(location: 0, length: renderingText.length))
renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/ renderingText.addAttribute(.foregroundColor, value: attachment.attributes.textColor, range: NSRange(location: 0, length: renderingText.length))*/
self.textNode.arguments = TextNodeWithEntities.Arguments(
context: context,
cache: context.animationCache,
renderer: context.animationRenderer,
placeholderColor: .gray,
attemptSynchronous: true
)
self.textNode.attributedText = renderingText self.textNode.attributedText = renderingText
self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 10.0, height: 8.0)) self.textNode.cutout = TextNodeCutout(topRight: CGSize(width: 30.0, height: 10.0))
self.textNode.displaySpoilerEffect = true
self.textNode.visibility = true
let maxTextSize = CGSize(width: self.bounds.size.width - 9.0, height: self.bounds.size.height) let maxTextSize = CGSize(width: self.bounds.size.width - 9.0, height: self.bounds.size.height)
let layoutInfo = self.textNode.updateLayoutFullInfo(maxTextSize) let layoutSize = self.textNode.updateLayout(maxTextSize)
self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutInfo.size) self.textNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 8.0), size: layoutSize)
} }
} }
@ -1450,16 +1472,17 @@ private final class QuoteBackgroundView: UIView {
self.iconView.frame = CGRect(origin: CGPoint(x: size.width - 4.0 - quoteIcon.size.width, y: 4.0), size: quoteIcon.size) self.iconView.frame = CGRect(origin: CGPoint(x: size.width - 4.0 - quoteIcon.size.width, y: 4.0), size: quoteIcon.size)
let collapseButtonSize = CGSize(width: 18.0, height: 18.0) let collapseButtonSize = CGSize(width: 18.0, height: 18.0)
self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize)
if isCollapsed { if isCollapsed {
self.collapseButtonIconView.image = quoteExpandImage self.collapseButtonIconView.image = quoteExpandImage
self.collapseButton.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size)
} else { } else {
self.collapseButtonIconView.image = quoteCollapseImage self.collapseButtonIconView.image = quoteCollapseImage
self.collapseButton.frame = CGRect(origin: CGPoint(x: size.width - 2.0 - collapseButtonSize.width, y: 2.0), size: collapseButtonSize)
} }
if let image = self.collapseButtonIconView.image { if let image = self.collapseButtonIconView.image {
let iconSize = image.size.aspectFitted(collapseButtonSize) let iconSize = image.size.aspectFitted(collapseButtonSize)
self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize) self.collapseButtonIconView.frame = CGRect(origin: CGPoint(x: self.collapseButton.bounds.width - 2.0 - collapseButtonSize.width + floorToScreenPixels((collapseButtonSize.width - iconSize.width) * 0.5), y: 2.0 + floorToScreenPixels((collapseButtonSize.height - iconSize.height) * 0.5)), size: iconSize)
} }
var primaryColor: UIColor var primaryColor: UIColor
@ -1469,7 +1492,7 @@ private final class QuoteBackgroundView: UIView {
switch kind { switch kind {
case .quote: case .quote:
if size.height >= 100.0 || isCollapsed { if size.height >= 60.0 || isCollapsed {
self.iconView.isHidden = true self.iconView.isHidden = true
self.collapseButton.isHidden = false self.collapseButton.isHidden = false
} else { } else {

View File

@ -45,7 +45,7 @@ private func generateBlockMaskImage() -> UIImage {
gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
context.setBlendMode(.destinationIn) context.setBlendMode(.destinationIn)
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 7.0), options: CGGradientDrawingOptions()) context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: size.height), end: CGPoint(x: 0.0, y: size.height - 18.0), options: CGGradientDrawingOptions())
})!.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: size.height - 1.0, right: size.width - 1.0), resizingMode: .stretch) })!.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: size.height - 1.0, right: size.width - 1.0), resizingMode: .stretch)
} }

View File

@ -1212,13 +1212,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
let result = NSMutableAttributedString(attributedString: current.inputText) let result = NSMutableAttributedString(attributedString: current.inputText)
var selectionRange = current.selectionRange
if let _ = result.attribute(ChatTextInputAttributes.block, at: range.lowerBound, effectiveRange: nil) as? ChatTextInputTextQuoteAttribute { if let _ = result.attribute(ChatTextInputAttributes.block, at: range.lowerBound, effectiveRange: nil) as? ChatTextInputTextQuoteAttribute {
let blockString = result.attributedSubstring(from: range) let blockString = NSMutableAttributedString(attributedString: result.attributedSubstring(from: range))
blockString.removeAttribute(ChatTextInputAttributes.block, range: NSRange(location: 0, length: blockString.length))
result.replaceCharacters(in: range, with: "") result.replaceCharacters(in: range, with: "")
result.insert(NSAttributedString(string: " ", attributes: [ result.insert(NSAttributedString(string: " ", attributes: [
ChatTextInputAttributes.collapsedBlock: blockString ChatTextInputAttributes.collapsedBlock: blockString
]), at: range.lowerBound) ]), at: range.lowerBound)
if selectionRange.lowerBound >= range.lowerBound && selectionRange.upperBound < range.upperBound {
selectionRange = range.lowerBound ..< range.lowerBound
} else if selectionRange.lowerBound >= range.upperBound {
let deltaLength = 1 - range.length
selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength)
}
} else if let current = result.attribute(ChatTextInputAttributes.collapsedBlock, at: range.lowerBound, effectiveRange: nil) as? NSAttributedString { } else if let current = result.attribute(ChatTextInputAttributes.collapsedBlock, at: range.lowerBound, effectiveRange: nil) as? NSAttributedString {
result.replaceCharacters(in: range, with: "") result.replaceCharacters(in: range, with: "")
@ -1226,13 +1236,24 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
updatedBlockString.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote, isCollapsed: false), range: NSRange(location: 0, length: updatedBlockString.length)) updatedBlockString.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote, isCollapsed: false), range: NSRange(location: 0, length: updatedBlockString.length))
result.insert(updatedBlockString, at: range.lowerBound) result.insert(updatedBlockString, at: range.lowerBound)
if selectionRange.lowerBound >= range.upperBound {
let deltaLength = updatedBlockString.length - 1
selectionRange = (selectionRange.lowerBound + deltaLength) ..< (selectionRange.lowerBound + deltaLength)
}
} }
let stateResult = stateAttributedStringForText(result) let stateResult = stateAttributedStringForText(result)
if selectionRange.lowerBound < 0 {
selectionRange = 0 ..< selectionRange.upperBound
}
if selectionRange.upperBound > stateResult.length {
selectionRange = selectionRange.lowerBound ..< stateResult.length
}
return (ChatTextInputState( return (ChatTextInputState(
inputText: stateResult, inputText: stateResult,
selectionRange: current.selectionRange selectionRange: selectionRange
), inputMode) ), inputMode)
} }
} }

View File

@ -179,7 +179,7 @@ public struct ChatTextFontAttributes: OptionSet, Hashable, Sequence {
public func textAttributedStringForStateText(context: AnyObject, stateText: NSAttributedString, fontSize: CGFloat, textColor: UIColor, accentTextColor: UIColor, writingDirection: NSWritingDirection?, spoilersRevealed: Bool, availableEmojis: Set<String>, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, makeCollapsedQuoteAttachment: ((NSAttributedString, ChatInputTextCollapsedQuoteAttributes) -> ChatInputTextCollapsedQuoteAttachment)?) -> NSAttributedString { public func textAttributedStringForStateText(context: AnyObject, stateText: NSAttributedString, fontSize: CGFloat, textColor: UIColor, accentTextColor: UIColor, writingDirection: NSWritingDirection?, spoilersRevealed: Bool, availableEmojis: Set<String>, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, makeCollapsedQuoteAttachment: ((NSAttributedString, ChatInputTextCollapsedQuoteAttributes) -> ChatInputTextCollapsedQuoteAttachment)?) -> NSAttributedString {
let quoteAttributes = ChatInputTextCollapsedQuoteAttributes( let quoteAttributes = ChatInputTextCollapsedQuoteAttributes(
context: context, context: context,
fontSize: fontSize, fontSize: round(fontSize * 0.8235294117647058),
textColor: textColor, textColor: textColor,
accentTextColor: accentTextColor accentTextColor: accentTextColor
) )