mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
c06e869cd1
@ -1473,7 +1473,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
return ASEditableTextNodeTargetForAction(target: nil)
|
||||
}
|
||||
}
|
||||
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) {
|
||||
} else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) || action == #selector(self.formatAttributesQuote(_:)) {
|
||||
if case .format = self.inputMenu.state {
|
||||
return ASEditableTextNodeTargetForAction(target: self)
|
||||
} else {
|
||||
@ -1646,6 +1646,14 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
self.updateSpoilersRevealed(animated: animated)
|
||||
}
|
||||
|
||||
@objc func formatAttributesQuote(_ sender: Any) {
|
||||
self.inputMenu.back()
|
||||
|
||||
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||
return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.quote), inputMode)
|
||||
}
|
||||
}
|
||||
|
||||
public func chatInputTextNode(shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
guard let editableTextNode = self.textInputNode else {
|
||||
return true
|
||||
@ -1728,6 +1736,10 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
return true
|
||||
}
|
||||
|
||||
public func chatInputTextNodeTargetForAction(action: Selector) -> ChatInputTextNode.TargetForAction? {
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
||||
return self.chatInputTextNodeShouldPaste()
|
||||
}
|
||||
|
@ -554,6 +554,13 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe
|
||||
}
|
||||
}
|
||||
|
||||
@objc func formatAttributesQuote(_ sender: Any) {
|
||||
self.inputMenu.back()
|
||||
if let item = self.item {
|
||||
chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.quote)
|
||||
}
|
||||
}
|
||||
|
||||
public func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
if let item = self.item {
|
||||
if text.count > 1, let processPaste = item.processPaste {
|
||||
|
@ -947,7 +947,11 @@ public final class TextNodeLayout: NSObject {
|
||||
rects.append((lineFrame, CGRect(origin: CGPoint(x: lineFrame.minX + min(leftOffset, rightOffset) + self.insets.left, y: lineFrame.minY + self.insets.top), size: CGSize(width: width, height: lineFrame.size.height))))
|
||||
}
|
||||
}
|
||||
if !rects.isEmpty, let startEdge = startEdge, let endEdge = endEdge {
|
||||
if !rects.isEmpty, var startEdge = startEdge, var endEdge = endEdge {
|
||||
startEdge.x += self.insets.left
|
||||
startEdge.y += self.insets.top
|
||||
endEdge.x += self.insets.left
|
||||
endEdge.y += self.insets.top
|
||||
return (rects.map { $1 }, startEdge, endEdge)
|
||||
}
|
||||
return nil
|
||||
|
@ -207,18 +207,23 @@ void stickerThumbnailAlphaBlur(int imageWidth, int imageHeight, int imageStride,
|
||||
srcBuffer.rowBytes = imageStride;
|
||||
srcBuffer.data = pixels;
|
||||
|
||||
void *tempBytes = malloc(imageHeight * imageStride);
|
||||
|
||||
{
|
||||
vImage_Buffer dstBuffer;
|
||||
dstBuffer.width = imageWidth;
|
||||
dstBuffer.height = imageHeight;
|
||||
dstBuffer.rowBytes = imageStride;
|
||||
dstBuffer.data = pixels;
|
||||
dstBuffer.data = tempBytes;
|
||||
|
||||
int boxSize = 2;
|
||||
boxSize = boxSize - (boxSize % 2) + 1;
|
||||
|
||||
vImageBoxConvolve_ARGB8888(&srcBuffer, &dstBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
|
||||
}
|
||||
|
||||
memcpy(pixels, tempBytes, imageHeight * imageStride);
|
||||
free(tempBytes);
|
||||
}
|
||||
|
||||
static void modifyImage(void *pixels, unsigned int width, unsigned int height, unsigned int stride, int16_t * _Nonnull matrix)
|
||||
|
@ -387,6 +387,7 @@ public func chatMessageStickerPackThumbnail(postbox: Postbox, resource: MediaRes
|
||||
|
||||
public func chatMessageSticker(postbox: Postbox, userLocation: MediaResourceUserLocation, file: TelegramMediaFile, small: Bool, fetched: Bool = false, onlyFullSize: Bool = false, thumbnail: Bool = false, synchronousLoad: Bool = false, colorSpace: CGColorSpace? = nil) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal: Signal<Tuple3<Data?, Data?, Bool>, NoError>
|
||||
|
||||
if thumbnail {
|
||||
signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad)
|
||||
|> map { data -> Tuple3<Data?, Data?, Bool>in
|
||||
|
@ -27,8 +27,8 @@ public enum MessageTextEntityType: Equatable {
|
||||
}
|
||||
|
||||
public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
|
||||
public let range: Range<Int>
|
||||
public let type: MessageTextEntityType
|
||||
public var range: Range<Int>
|
||||
public var type: MessageTextEntityType
|
||||
|
||||
public init(range: Range<Int>, type: MessageTextEntityType) {
|
||||
self.range = range
|
||||
|
@ -17,6 +17,7 @@
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldCopy)();
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldPaste)();
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldRespondToAction)(SEL _Nullable);
|
||||
@property (nonatomic, copy) ChatInputTextViewImplTargetForAction * _Nullable (^ _Nullable targetForAction)(SEL _Nullable);
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldReturn)();
|
||||
@property (nonatomic, copy) void (^ _Nullable backspaceWhileEmpty)();
|
||||
@property (nonatomic, copy) void (^ _Nullable dropAutocorrectioniOS16)();
|
||||
|
@ -68,6 +68,13 @@
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
if (_targetForAction) {
|
||||
ChatInputTextViewImplTargetForAction *result = _targetForAction(action);
|
||||
if (result) {
|
||||
return result.target != nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (_shouldRespondToAction) {
|
||||
if (!_shouldRespondToAction(action)) {
|
||||
return false;
|
||||
@ -102,6 +109,13 @@
|
||||
}
|
||||
|
||||
- (id)targetForAction:(SEL)action withSender:(id)__unused sender {
|
||||
if (_targetForAction) {
|
||||
ChatInputTextViewImplTargetForAction *result = _targetForAction(action);
|
||||
if (result) {
|
||||
return result.target;
|
||||
}
|
||||
}
|
||||
|
||||
return [super targetForAction:action withSender:sender];
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,18 @@ public protocol ChatInputTextNodeDelegate: AnyObject {
|
||||
func chatInputTextNodeShouldPaste() -> Bool
|
||||
|
||||
func chatInputTextNodeShouldRespondToAction(action: Selector) -> Bool
|
||||
func chatInputTextNodeTargetForAction(action: Selector) -> ChatInputTextNode.TargetForAction?
|
||||
}
|
||||
|
||||
open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
public final class TargetForAction {
|
||||
public let target: Any?
|
||||
|
||||
public init(target: Any?) {
|
||||
self.target = target
|
||||
}
|
||||
}
|
||||
|
||||
public weak var delegate: ChatInputTextNodeDelegate? {
|
||||
didSet {
|
||||
self.textView.customDelegate = self.delegate
|
||||
@ -124,6 +133,18 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
return true
|
||||
}
|
||||
}
|
||||
self.textView.targetForAction = { [weak self] action in
|
||||
guard let self, let action else {
|
||||
return nil
|
||||
}
|
||||
if let delegate = self.delegate {
|
||||
return delegate.chatInputTextNodeTargetForAction(action: action).flatMap { value in
|
||||
return ChatInputTextViewImplTargetForAction(target: value.target)
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func resetInitialPrimaryLanguage() {
|
||||
|
@ -4699,7 +4699,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
if let backgroundType = self.backgroundType {
|
||||
let graphics = PresentationResourcesChat.principalGraphics(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
||||
|
||||
if self.highlightedState != nil {
|
||||
if self.highlightedState != nil, !(self.backgroundNode.layer.mask is SimpleLayer) {
|
||||
let backgroundHighlightNode: ChatMessageBackground
|
||||
if let current = self.backgroundHighlightNode {
|
||||
backgroundHighlightNode = current
|
||||
|
@ -27,6 +27,7 @@ import ChatMessageReplyInfoNode
|
||||
import InstantVideoRadialStatusNode
|
||||
import ChatInstantVideoMessageDurationNode
|
||||
import ChatControllerInteraction
|
||||
import WallpaperBackgroundNode
|
||||
|
||||
public struct ChatMessageInstantVideoItemLayoutResult {
|
||||
public let contentSize: CGSize
|
||||
@ -109,8 +110,9 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
|
||||
public var viaBotNode: TextNode?
|
||||
public var replyInfoNode: ChatMessageReplyInfoNode?
|
||||
public var replyBackgroundNode: NavigationBackgroundNode?
|
||||
public var replyBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
public var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||
public var forwardBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
||||
private var status: FileMediaResourceStatus?
|
||||
private var playerStatus: MediaPlayerStatus? {
|
||||
@ -240,7 +242,6 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
let viaBotLayout = TextNode.asyncLayout(self.viaBotNode)
|
||||
let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode)
|
||||
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
||||
let currentReplyBackgroundNode = self.replyBackgroundNode
|
||||
|
||||
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusDisplayType, automaticDownload, avatarInset in
|
||||
var secretVideoPlaceholderBackgroundImage: UIImage?
|
||||
@ -598,15 +599,14 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
|
||||
strongSelf.automaticDownload = automaticDownload
|
||||
|
||||
var updatedReplyBackgroundNode: NavigationBackgroundNode?
|
||||
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
||||
updatedReplyBackgroundNode = currentReplyBackgroundNode
|
||||
} else {
|
||||
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
|
||||
}
|
||||
|
||||
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: item.controllerInteraction.enableFullTranslucency && dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
|
||||
var needsReplyBackground = false
|
||||
if replyInfoApply != nil {
|
||||
needsReplyBackground = true
|
||||
}
|
||||
|
||||
var needsForwardBackground = false
|
||||
if viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||
needsForwardBackground = true
|
||||
}
|
||||
|
||||
if let updatedAudioTranscriptionState = updatedAudioTranscriptionState {
|
||||
@ -918,7 +918,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
if let telegramFile = updatedFile, previousAutomaticDownload != automaticDownload, automaticDownload {
|
||||
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: item.context, message: item.message, file: telegramFile, userInitiated: false).startStrict())
|
||||
}
|
||||
|
||||
|
||||
if let forwardInfo = item.message.forwardInfo, forwardInfo.flags.contains(.isImported) {
|
||||
strongSelf.dateAndStatusNode.pressed = {
|
||||
guard let strongSelf = self else {
|
||||
@ -930,42 +930,75 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
strongSelf.dateAndStatusNode.pressed = nil
|
||||
}
|
||||
|
||||
if let updatedReplyBackgroundNode = updatedReplyBackgroundNode {
|
||||
if strongSelf.replyBackgroundNode == nil {
|
||||
strongSelf.replyBackgroundNode = updatedReplyBackgroundNode
|
||||
strongSelf.addSubnode(updatedReplyBackgroundNode)
|
||||
}
|
||||
} else if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
replyBackgroundNode.removeFromSupernode()
|
||||
strongSelf.replyBackgroundNode = nil
|
||||
}
|
||||
|
||||
var messageInfoSize = CGSize()
|
||||
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
messageInfoSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
|
||||
}
|
||||
if let (forwardInfoSize, _) = forwardInfoSizeApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, forwardInfoSize.width + 2.0), height: 0.0)
|
||||
}
|
||||
if let (replyInfoSize, _) = replyInfoApply {
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: 0.0)
|
||||
}
|
||||
|
||||
var width = width
|
||||
if !scaleProgress.isZero {
|
||||
width += avatarInset
|
||||
}
|
||||
|
||||
if needsReplyBackground {
|
||||
if strongSelf.replyBackgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
backgroundContent.clipsToBounds = true
|
||||
strongSelf.replyBackgroundContent = backgroundContent
|
||||
strongSelf.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
} else {
|
||||
if let replyBackgroundContent = strongSelf.replyBackgroundContent {
|
||||
replyBackgroundContent.removeFromSupernode()
|
||||
strongSelf.replyBackgroundContent = nil
|
||||
}
|
||||
}
|
||||
|
||||
if needsForwardBackground {
|
||||
if strongSelf.forwardBackgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
|
||||
backgroundContent.clipsToBounds = true
|
||||
strongSelf.forwardBackgroundContent = backgroundContent
|
||||
strongSelf.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
} else {
|
||||
if let forwardBackgroundContent = strongSelf.forwardBackgroundContent {
|
||||
forwardBackgroundContent.removeFromSupernode()
|
||||
strongSelf.forwardBackgroundContent = nil
|
||||
}
|
||||
}
|
||||
|
||||
var headersOffset: CGFloat = 0.0
|
||||
|
||||
var forwardAreaSize = CGSize()
|
||||
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
forwardAreaSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
|
||||
}
|
||||
if let (forwardInfoSize, _) = forwardInfoSizeApply {
|
||||
forwardAreaSize = CGSize(width: max(forwardAreaSize.width, forwardInfoSize.width + 2.0), height: 0.0)
|
||||
}
|
||||
|
||||
var replyAreaSize = CGSize()
|
||||
if let (replyInfoSize, _) = replyInfoApply {
|
||||
replyAreaSize = CGSize(width: max(replyAreaSize.width, replyInfoSize.width), height: 0.0)
|
||||
}
|
||||
|
||||
let edgeInset: CGFloat = 4.0
|
||||
let leftInset: CGFloat = 0.0
|
||||
let rightInset: CGFloat = 0.0
|
||||
|
||||
var forwardAreaFrame: CGRect?
|
||||
var messageInfoSize = CGSize()
|
||||
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
|
||||
let viaBotNode = viaBotApply()
|
||||
if strongSelf.viaBotNode == nil {
|
||||
strongSelf.viaBotNode = viaBotNode
|
||||
strongSelf.addSubnode(viaBotNode)
|
||||
}
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (leftInset + edgeInset) : (width - rightInset - forwardAreaSize.width - edgeInset)), y: headersOffset + 8.0), size: viaBotLayout.size)
|
||||
|
||||
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.maxX - width + 6.0) : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0), size: viaBotLayout.size)
|
||||
animation.animator.updateFrame(layer: viaBotNode.layer, frame: viaBotFrame, completion: nil)
|
||||
viaBotNode.frame = viaBotFrame
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
|
||||
|
||||
if let forwardAreaFrameValue = forwardAreaFrame {
|
||||
forwardAreaFrame = forwardAreaFrameValue.union(viaBotFrame)
|
||||
} else {
|
||||
forwardAreaFrame = viaBotFrame
|
||||
}
|
||||
} else if let viaBotNode = strongSelf.viaBotNode {
|
||||
viaBotNode.removeFromSupernode()
|
||||
strongSelf.viaBotNode = nil
|
||||
@ -981,10 +1014,16 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.maxX - width + 6.0) : (width - messageInfoSize.width - bubbleEdgeInset - 8.0 + 10.0)), y: 8.0 + messageInfoSize.height), size: forwardInfoSize)
|
||||
animation.animator.updateFrame(layer: forwardInfoNode.layer, frame: forwardInfoFrame, completion: nil)
|
||||
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.minX - forwardAreaSize.width - 4.0) : (displayVideoFrame.maxX + 6.0)), y: headersOffset + 8.0 + messageInfoSize.height), size: forwardInfoSize)
|
||||
forwardInfoNode.frame = forwardInfoFrame
|
||||
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height - 1.0)
|
||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height + 8.0)
|
||||
|
||||
if let forwardAreaFrameValue = forwardAreaFrame {
|
||||
forwardAreaFrame = forwardAreaFrameValue.union(forwardInfoFrame)
|
||||
} else {
|
||||
forwardAreaFrame = forwardInfoFrame
|
||||
}
|
||||
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
if animation.isAnimated {
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
@ -999,9 +1038,18 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
var forwardBackgroundFrame: CGRect?
|
||||
if let forwardAreaFrame {
|
||||
forwardBackgroundFrame = forwardAreaFrame.insetBy(dx: -6.0, dy: -3.0)
|
||||
}
|
||||
|
||||
var replyBackgroundFrame: CGRect?
|
||||
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.maxX - width + 5.0) : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0 + messageInfoSize.height), size: replyInfoSize)
|
||||
if headersOffset != 0.0 {
|
||||
headersOffset += 6.0
|
||||
}
|
||||
|
||||
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (displayVideoFrame.minX - replyInfoSize.width) : (displayVideoFrame.maxX)), y: headersOffset + 8.0 + messageInfoSize.height), size: replyInfoSize)
|
||||
replyBackgroundFrame = replyInfoFrame
|
||||
|
||||
let replyInfoNode = replyInfoApply(replyInfoFrame.size, false, animation)
|
||||
@ -1009,7 +1057,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
strongSelf.replyInfoNode = replyInfoNode
|
||||
strongSelf.addSubnode(replyInfoNode)
|
||||
}
|
||||
animation.animator.updateFrame(layer: replyInfoNode.layer, frame: replyInfoFrame, completion: nil)
|
||||
replyInfoNode.frame = replyInfoFrame
|
||||
|
||||
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
|
||||
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
||||
@ -1017,20 +1065,25 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
strongSelf.replyInfoNode = nil
|
||||
}
|
||||
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode, let replyBackgroundFrame {
|
||||
let replyBackgroundFrame = replyBackgroundFrame
|
||||
animation.animator.updateFrame(layer: replyBackgroundNode.layer, frame: replyBackgroundFrame, completion: nil)
|
||||
|
||||
let cornerRadius = replyBackgroundNode.frame.height <= 22.0 ? replyBackgroundNode.frame.height / 2.0 : 8.0
|
||||
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: cornerRadius, transition: .immediate)
|
||||
if let backgroundContent = strongSelf.replyBackgroundContent, let replyBackgroundFrame {
|
||||
backgroundContent.cornerRadius = 4.0
|
||||
backgroundContent.frame = replyBackgroundFrame
|
||||
}
|
||||
|
||||
if let backgroundContent = strongSelf.forwardBackgroundContent, let forwardBackgroundFrame {
|
||||
backgroundContent.cornerRadius = 4.0
|
||||
backgroundContent.frame = forwardBackgroundFrame
|
||||
}
|
||||
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||
if let viaBotNode = strongSelf.viaBotNode {
|
||||
transition.updateAlpha(node: viaBotNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||
}
|
||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
||||
transition.updateAlpha(node: replyBackgroundNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||
if let replyBackgroundContent = strongSelf.replyBackgroundContent {
|
||||
transition.updateAlpha(node: replyBackgroundContent, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||
}
|
||||
if let forwardBackgroundContent = strongSelf.forwardBackgroundContent {
|
||||
transition.updateAlpha(node: forwardBackgroundContent, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||
}
|
||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||
transition.updateAlpha(node: forwardInfoNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||
@ -1761,8 +1814,11 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
viaBotNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
replyBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
if let replyBackgroundContent = self.replyBackgroundContent {
|
||||
replyBackgroundContent.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
}
|
||||
if let forwardBackgroundContent = self.replyBackgroundContent {
|
||||
forwardBackgroundContent.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
}
|
||||
if let forwardInfoNode = self.forwardInfoNode {
|
||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
@ -1866,8 +1922,11 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
if let viaBotNode = self.viaBotNode {
|
||||
viaBotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
}
|
||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
||||
replyBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
if let replyBackgroundContent = self.replyBackgroundContent {
|
||||
replyBackgroundContent.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
}
|
||||
if let forwardBackgroundContent = self.forwardBackgroundContent {
|
||||
forwardBackgroundContent.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
}
|
||||
if let forwardInfoNode = self.forwardInfoNode {
|
||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
|
@ -1201,7 +1201,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
textSelectionNode.enableQuote = enableQuote
|
||||
textSelectionNode.enableTranslate = enableOtherActions
|
||||
textSelectionNode.enableShare = enableOtherActions
|
||||
textSelectionNode.enableShare = enableOtherActions && enableCopy
|
||||
textSelectionNode.menuSkipCoordnateConversion = !enableOtherActions
|
||||
self.textSelectionNode = textSelectionNode
|
||||
self.containerNode.addSubnode(textSelectionNode)
|
||||
|
@ -735,7 +735,7 @@ public final class MessageInlineBlockBackgroundView: UIView {
|
||||
|
||||
let itemSize = CGSize(width: placement.size / 3.0, height: placement.size / 3.0)
|
||||
patternContentLayer.frame = CGRect(origin: CGPoint(x: size.width - placement.position.x / 3.0 - itemSize.width * 0.5, y: placement.position.y / 3.0 - itemSize.height * 0.5), size: itemSize)
|
||||
var alphaFraction = abs(placement.position.x) / min(500.0, size.width)
|
||||
var alphaFraction = abs(placement.position.x / 3.0) / min(500.0, size.width)
|
||||
alphaFraction = min(1.0, max(0.0, alphaFraction))
|
||||
patternContentLayer.opacity = 0.3 * Float(1.0 - alphaFraction)
|
||||
|
||||
|
@ -70,11 +70,12 @@ public func cacheStillSticker(path: String, width: Int, height: Int, writer: Ani
|
||||
UIGraphicsPushContext(c)
|
||||
|
||||
if let customColor = customColor {
|
||||
c.clip(to: CGRect(origin: CGPoint(), size: context.size), mask: image.cgImage!)
|
||||
c.setFillColor(customColor.cgColor)
|
||||
c.setBlendMode(.sourceIn)
|
||||
c.fill(CGRect(origin: CGPoint(), size: context.size))
|
||||
} else {
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: context.size))
|
||||
}
|
||||
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: context.size))
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
memcpy(surface.argb, context.bytes, surface.height * surface.bytesPerRow)
|
||||
|
@ -267,6 +267,31 @@ public class ShareRootControllerImpl {
|
||||
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false, removeDatabaseOnError: false)
|
||||
initializeAccountManagement()
|
||||
|
||||
do {
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var loggingSettings = LoggingSettings.defaultSettings
|
||||
if self.initializationData.appBuildType == .internal {
|
||||
loggingSettings = LoggingSettings(logToFile: true, logToConsole: false, redactSensitiveData: true)
|
||||
}
|
||||
let _ = (accountManager.transaction { transaction -> LoggingSettings? in
|
||||
if let value = transaction.getSharedData(SharedDataKeys.loggingSettings)?.get(LoggingSettings.self) {
|
||||
return value
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}).start(next: { value in
|
||||
if let value {
|
||||
loggingSettings = value
|
||||
}
|
||||
semaphore.signal()
|
||||
})
|
||||
semaphore.wait()
|
||||
|
||||
Logger.shared.logToFile = loggingSettings.logToFile
|
||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||
}
|
||||
|
||||
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let systemUserInterfaceStyle: WindowUserInterfaceStyle
|
||||
@ -306,7 +331,6 @@ public class ShareRootControllerImpl {
|
||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
Logger.shared.logToFile = loggingSettings.logToFile
|
||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||
|
||||
return combineLatest(sharedContext.activeAccountsWithInfo, accountManager.transaction { transaction -> (Set<AccountRecordId>, PeerId?) in
|
||||
|
@ -3338,6 +3338,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}, setupReply: { [weak self] messageId in
|
||||
self?.interfaceInteraction?.setupReplyMessage(messageId, { _, f in f() })
|
||||
}, canSetupReply: { [weak self] message in
|
||||
if message.adAttribute != nil {
|
||||
return .none
|
||||
}
|
||||
if !message.flags.contains(.Incoming) {
|
||||
if !message.flags.intersection([.Failed, .Sending, .Unsent]).isEmpty {
|
||||
return .none
|
||||
|
@ -772,10 +772,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
self.textInputViewInternalInsets = UIEdgeInsets(top: 1.0, left: 13.0, bottom: 1.0, right: 13.0)
|
||||
|
||||
var hasSpoilers = true
|
||||
var hasQuotes = true
|
||||
if presentationInterfaceState.chatLocation.peerId?.namespace == Namespaces.Peer.SecretChat {
|
||||
hasSpoilers = false
|
||||
hasQuotes = false
|
||||
}
|
||||
self.inputMenu = TextInputMenu(hasSpoilers: hasSpoilers)
|
||||
self.inputMenu = TextInputMenu(hasSpoilers: hasSpoilers, hasQuotes: hasQuotes)
|
||||
|
||||
self.clippingNode = ASDisplayNode()
|
||||
self.clippingNode.clipsToBounds = true
|
||||
@ -3954,18 +3956,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
}
|
||||
|
||||
public func chatInputTextNodeShouldRespondToAction(action: Selector) -> Bool {
|
||||
guard let textInputNode = self.textInputNode else {
|
||||
return true
|
||||
}
|
||||
let _ = textInputNode
|
||||
|
||||
/*if textInputNode.attributedText == nil || textInputNode.attributedText!.length == 0 || textInputNode.selectedRange.length == 0 {
|
||||
print("action: \(action)")
|
||||
}*/
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public func chatInputTextNodeTargetForAction(action: Selector) -> ChatInputTextNode.TargetForAction? {
|
||||
if let target = self.editableTextNodeTarget(forAction: action) {
|
||||
return ChatInputTextNode.TargetForAction(target: target.target)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func chatInputTextNodeShouldPaste() -> Bool {
|
||||
let pasteboard = UIPasteboard.general
|
||||
|
||||
|
@ -181,6 +181,35 @@ public func generateChatInputTextEntities(_ text: NSAttributedString, maxAnimate
|
||||
}
|
||||
}
|
||||
|
||||
while true {
|
||||
var hadReductions = false
|
||||
|
||||
scan: for i in 0 ..< entities.count {
|
||||
if case .BlockQuote = entities[i].type {
|
||||
inner: for j in 0 ..< entities.count {
|
||||
if j == i {
|
||||
continue inner
|
||||
}
|
||||
if case .BlockQuote = entities[j].type {
|
||||
if entities[i].range.upperBound == entities[j].range.lowerBound || entities[i].range.lowerBound == entities[j].range.upperBound {
|
||||
entities[i].range = min(entities[i].range.lowerBound, entities[j].range.lowerBound) ..< max(entities[i].range.upperBound, entities[j].range.upperBound)
|
||||
entities.remove(at: j)
|
||||
|
||||
hadReductions = true
|
||||
break scan
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break scan
|
||||
}
|
||||
}
|
||||
|
||||
if !hadReductions {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return entities
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,10 @@ public final class TextInputMenu {
|
||||
private var stringStrikethrough: String = "Strikethrough"
|
||||
private var stringUnderline: String = "Underline"
|
||||
private var stringSpoiler: String = "Spoiler"
|
||||
private var stringQuote: String = "Quote"
|
||||
|
||||
private let hasSpoilers: Bool
|
||||
private let hasQuotes: Bool
|
||||
|
||||
public private(set) var state: State = .inactive {
|
||||
didSet {
|
||||
@ -39,6 +41,9 @@ public final class TextInputMenu {
|
||||
if self.hasSpoilers {
|
||||
menuItems.insert(UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:"))), at: 0)
|
||||
}
|
||||
if self.hasQuotes {
|
||||
menuItems.insert(UIMenuItem(title: self.stringQuote, action: Selector(("formatAttributesQuote:"))), at: 0)
|
||||
}
|
||||
UIMenuController.shared.menuItems = menuItems
|
||||
}
|
||||
|
||||
@ -48,8 +53,9 @@ public final class TextInputMenu {
|
||||
|
||||
private var observer: NSObjectProtocol?
|
||||
|
||||
public init(hasSpoilers: Bool = false) {
|
||||
public init(hasSpoilers: Bool = false, hasQuotes: Bool = false) {
|
||||
self.hasSpoilers = hasSpoilers
|
||||
self.hasQuotes = hasQuotes
|
||||
self.observer = NotificationCenter.default.addObserver(forName: UIMenuController.didHideMenuNotification, object: nil, queue: nil, using: { [weak self] _ in
|
||||
self?.back()
|
||||
})
|
||||
@ -69,6 +75,7 @@ public final class TextInputMenu {
|
||||
self.stringStrikethrough = strings.TextFormat_Strikethrough
|
||||
self.stringUnderline = strings.TextFormat_Underline
|
||||
self.stringSpoiler = strings.TextFormat_Spoiler
|
||||
self.stringQuote = strings.TextFormat_Quote
|
||||
}
|
||||
|
||||
public func activate() {
|
||||
|
@ -589,7 +589,7 @@ public final class TextSelectionNode: ASDisplayNode {
|
||||
highlightOverlay.innerRadius = 2.0
|
||||
highlightOverlay.outerRadius = 2.0
|
||||
highlightOverlay.inset = 1.0
|
||||
highlightOverlay.useModernPathCalculation = true
|
||||
highlightOverlay.useModernPathCalculation = false
|
||||
|
||||
self.highlightOverlay = highlightOverlay
|
||||
self.highlightAreaNode.addSubnode(highlightOverlay)
|
||||
@ -597,8 +597,8 @@ public final class TextSelectionNode: ASDisplayNode {
|
||||
highlightOverlay.frame = self.bounds
|
||||
highlightOverlay.updateRects(rects)
|
||||
if let image = self.leftKnob.image {
|
||||
self.leftKnob.frame = CGRect(origin: CGPoint(x: floor(startEdge.x - image.size.width / 2.0), y: startEdge.y + 1.0 - 12.0), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + startEdge.height + 2.0))
|
||||
self.rightKnob.frame = CGRect(origin: CGPoint(x: floor(endEdge.x + 1.0 - image.size.width / 2.0), y: endEdge.y + endEdge.height + 3.0 - (endEdge.height + 2.0)), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + endEdge.height + 2.0))
|
||||
self.leftKnob.frame = CGRect(origin: CGPoint(x: floor(startEdge.x - image.size.width / 2.0), y: startEdge.y - self.theme.knobDiameter), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + startEdge.height))
|
||||
self.rightKnob.frame = CGRect(origin: CGPoint(x: floor(endEdge.x - image.size.width / 2.0), y: endEdge.y), size: CGSize(width: image.size.width, height: self.theme.knobDiameter + endEdge.height))
|
||||
}
|
||||
if self.leftKnob.alpha.isZero {
|
||||
highlightOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
|
@ -10,6 +10,11 @@
|
||||
return nil;
|
||||
}
|
||||
|
||||
UIImage *osImage = [[UIImage alloc] initWithData:imgData scale:1.0];
|
||||
if (osImage != nil) {
|
||||
return osImage;
|
||||
}
|
||||
|
||||
int width = 0, height = 0;
|
||||
if (!WebPGetInfo([imgData bytes], [imgData length], &width, &height)) {
|
||||
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "10.2",
|
||||
"app": "10.2.1",
|
||||
"bazel": "6.4.0",
|
||||
"xcode": "15.0"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user