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)
|
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 {
|
if case .format = self.inputMenu.state {
|
||||||
return ASEditableTextNodeTargetForAction(target: self)
|
return ASEditableTextNodeTargetForAction(target: self)
|
||||||
} else {
|
} else {
|
||||||
@ -1646,6 +1646,14 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
self.updateSpoilersRevealed(animated: animated)
|
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 {
|
public func chatInputTextNode(shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||||
guard let editableTextNode = self.textInputNode else {
|
guard let editableTextNode = self.textInputNode else {
|
||||||
return true
|
return true
|
||||||
@ -1728,6 +1736,10 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func chatInputTextNodeTargetForAction(action: Selector) -> ChatInputTextNode.TargetForAction? {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
@objc public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
@objc public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
||||||
return self.chatInputTextNodeShouldPaste()
|
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 {
|
public func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
if text.count > 1, let processPaste = item.processPaste {
|
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))))
|
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 (rects.map { $1 }, startEdge, endEdge)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -207,18 +207,23 @@ void stickerThumbnailAlphaBlur(int imageWidth, int imageHeight, int imageStride,
|
|||||||
srcBuffer.rowBytes = imageStride;
|
srcBuffer.rowBytes = imageStride;
|
||||||
srcBuffer.data = pixels;
|
srcBuffer.data = pixels;
|
||||||
|
|
||||||
|
void *tempBytes = malloc(imageHeight * imageStride);
|
||||||
|
|
||||||
{
|
{
|
||||||
vImage_Buffer dstBuffer;
|
vImage_Buffer dstBuffer;
|
||||||
dstBuffer.width = imageWidth;
|
dstBuffer.width = imageWidth;
|
||||||
dstBuffer.height = imageHeight;
|
dstBuffer.height = imageHeight;
|
||||||
dstBuffer.rowBytes = imageStride;
|
dstBuffer.rowBytes = imageStride;
|
||||||
dstBuffer.data = pixels;
|
dstBuffer.data = tempBytes;
|
||||||
|
|
||||||
int boxSize = 2;
|
int boxSize = 2;
|
||||||
boxSize = boxSize - (boxSize % 2) + 1;
|
boxSize = boxSize - (boxSize % 2) + 1;
|
||||||
|
|
||||||
vImageBoxConvolve_ARGB8888(&srcBuffer, &dstBuffer, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
|
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)
|
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> {
|
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>
|
let signal: Signal<Tuple3<Data?, Data?, Bool>, NoError>
|
||||||
|
|
||||||
if thumbnail {
|
if thumbnail {
|
||||||
signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad)
|
signal = chatMessageStickerThumbnailData(postbox: postbox, userLocation: userLocation, file: file, synchronousLoad: synchronousLoad)
|
||||||
|> map { data -> Tuple3<Data?, Data?, Bool>in
|
|> map { data -> Tuple3<Data?, Data?, Bool>in
|
||||||
|
@ -27,8 +27,8 @@ public enum MessageTextEntityType: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
|
public struct MessageTextEntity: PostboxCoding, Codable, Equatable {
|
||||||
public let range: Range<Int>
|
public var range: Range<Int>
|
||||||
public let type: MessageTextEntityType
|
public var type: MessageTextEntityType
|
||||||
|
|
||||||
public init(range: Range<Int>, type: MessageTextEntityType) {
|
public init(range: Range<Int>, type: MessageTextEntityType) {
|
||||||
self.range = range
|
self.range = range
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
@property (nonatomic, copy) bool (^ _Nullable shouldCopy)();
|
@property (nonatomic, copy) bool (^ _Nullable shouldCopy)();
|
||||||
@property (nonatomic, copy) bool (^ _Nullable shouldPaste)();
|
@property (nonatomic, copy) bool (^ _Nullable shouldPaste)();
|
||||||
@property (nonatomic, copy) bool (^ _Nullable shouldRespondToAction)(SEL _Nullable);
|
@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) bool (^ _Nullable shouldReturn)();
|
||||||
@property (nonatomic, copy) void (^ _Nullable backspaceWhileEmpty)();
|
@property (nonatomic, copy) void (^ _Nullable backspaceWhileEmpty)();
|
||||||
@property (nonatomic, copy) void (^ _Nullable dropAutocorrectioniOS16)();
|
@property (nonatomic, copy) void (^ _Nullable dropAutocorrectioniOS16)();
|
||||||
|
@ -68,6 +68,13 @@
|
|||||||
|
|
||||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||||
{
|
{
|
||||||
|
if (_targetForAction) {
|
||||||
|
ChatInputTextViewImplTargetForAction *result = _targetForAction(action);
|
||||||
|
if (result) {
|
||||||
|
return result.target != nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_shouldRespondToAction) {
|
if (_shouldRespondToAction) {
|
||||||
if (!_shouldRespondToAction(action)) {
|
if (!_shouldRespondToAction(action)) {
|
||||||
return false;
|
return false;
|
||||||
@ -102,6 +109,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (id)targetForAction:(SEL)action withSender:(id)__unused sender {
|
- (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];
|
return [super targetForAction:action withSender:sender];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +22,18 @@ public protocol ChatInputTextNodeDelegate: AnyObject {
|
|||||||
func chatInputTextNodeShouldPaste() -> Bool
|
func chatInputTextNodeShouldPaste() -> Bool
|
||||||
|
|
||||||
func chatInputTextNodeShouldRespondToAction(action: Selector) -> Bool
|
func chatInputTextNodeShouldRespondToAction(action: Selector) -> Bool
|
||||||
|
func chatInputTextNodeTargetForAction(action: Selector) -> ChatInputTextNode.TargetForAction?
|
||||||
}
|
}
|
||||||
|
|
||||||
open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
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? {
|
public weak var delegate: ChatInputTextNodeDelegate? {
|
||||||
didSet {
|
didSet {
|
||||||
self.textView.customDelegate = self.delegate
|
self.textView.customDelegate = self.delegate
|
||||||
@ -124,6 +133,18 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
|||||||
return true
|
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() {
|
public func resetInitialPrimaryLanguage() {
|
||||||
|
@ -4699,7 +4699,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
if let backgroundType = self.backgroundType {
|
if let backgroundType = self.backgroundType {
|
||||||
let graphics = PresentationResourcesChat.principalGraphics(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper, bubbleCorners: item.presentationData.chatBubbleCorners)
|
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
|
let backgroundHighlightNode: ChatMessageBackground
|
||||||
if let current = self.backgroundHighlightNode {
|
if let current = self.backgroundHighlightNode {
|
||||||
backgroundHighlightNode = current
|
backgroundHighlightNode = current
|
||||||
|
@ -27,6 +27,7 @@ import ChatMessageReplyInfoNode
|
|||||||
import InstantVideoRadialStatusNode
|
import InstantVideoRadialStatusNode
|
||||||
import ChatInstantVideoMessageDurationNode
|
import ChatInstantVideoMessageDurationNode
|
||||||
import ChatControllerInteraction
|
import ChatControllerInteraction
|
||||||
|
import WallpaperBackgroundNode
|
||||||
|
|
||||||
public struct ChatMessageInstantVideoItemLayoutResult {
|
public struct ChatMessageInstantVideoItemLayoutResult {
|
||||||
public let contentSize: CGSize
|
public let contentSize: CGSize
|
||||||
@ -109,8 +110,9 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
|
|
||||||
public var viaBotNode: TextNode?
|
public var viaBotNode: TextNode?
|
||||||
public var replyInfoNode: ChatMessageReplyInfoNode?
|
public var replyInfoNode: ChatMessageReplyInfoNode?
|
||||||
public var replyBackgroundNode: NavigationBackgroundNode?
|
public var replyBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||||
public var forwardInfoNode: ChatMessageForwardInfoNode?
|
public var forwardInfoNode: ChatMessageForwardInfoNode?
|
||||||
|
public var forwardBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||||
|
|
||||||
private var status: FileMediaResourceStatus?
|
private var status: FileMediaResourceStatus?
|
||||||
private var playerStatus: MediaPlayerStatus? {
|
private var playerStatus: MediaPlayerStatus? {
|
||||||
@ -240,7 +242,6 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
let viaBotLayout = TextNode.asyncLayout(self.viaBotNode)
|
let viaBotLayout = TextNode.asyncLayout(self.viaBotNode)
|
||||||
let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode)
|
let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode)
|
||||||
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
|
||||||
let currentReplyBackgroundNode = self.replyBackgroundNode
|
|
||||||
|
|
||||||
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusDisplayType, automaticDownload, avatarInset in
|
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusDisplayType, automaticDownload, avatarInset in
|
||||||
var secretVideoPlaceholderBackgroundImage: UIImage?
|
var secretVideoPlaceholderBackgroundImage: UIImage?
|
||||||
@ -598,15 +599,14 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
|
|
||||||
strongSelf.automaticDownload = automaticDownload
|
strongSelf.automaticDownload = automaticDownload
|
||||||
|
|
||||||
var updatedReplyBackgroundNode: NavigationBackgroundNode?
|
var needsReplyBackground = false
|
||||||
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
|
if replyInfoApply != nil {
|
||||||
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
|
needsReplyBackground = true
|
||||||
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))
|
var needsForwardBackground = false
|
||||||
}
|
if viaBotApply != nil || forwardInfoSizeApply != nil {
|
||||||
|
needsForwardBackground = true
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let updatedAudioTranscriptionState = updatedAudioTranscriptionState {
|
if let updatedAudioTranscriptionState = updatedAudioTranscriptionState {
|
||||||
@ -918,7 +918,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
if let telegramFile = updatedFile, previousAutomaticDownload != automaticDownload, automaticDownload {
|
if let telegramFile = updatedFile, previousAutomaticDownload != automaticDownload, automaticDownload {
|
||||||
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: item.context, message: item.message, file: telegramFile, userInitiated: false).startStrict())
|
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) {
|
if let forwardInfo = item.message.forwardInfo, forwardInfo.flags.contains(.isImported) {
|
||||||
strongSelf.dateAndStatusNode.pressed = {
|
strongSelf.dateAndStatusNode.pressed = {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -930,42 +930,75 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
strongSelf.dateAndStatusNode.pressed = nil
|
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
|
var width = width
|
||||||
if !scaleProgress.isZero {
|
if !scaleProgress.isZero {
|
||||||
width += avatarInset
|
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 {
|
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
|
||||||
let viaBotNode = viaBotApply()
|
let viaBotNode = viaBotApply()
|
||||||
if strongSelf.viaBotNode == nil {
|
if strongSelf.viaBotNode == nil {
|
||||||
strongSelf.viaBotNode = viaBotNode
|
strongSelf.viaBotNode = viaBotNode
|
||||||
strongSelf.addSubnode(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)
|
viaBotNode.frame = viaBotFrame
|
||||||
animation.animator.updateFrame(layer: viaBotNode.layer, frame: viaBotFrame, completion: nil)
|
|
||||||
|
|
||||||
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
|
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 {
|
} else if let viaBotNode = strongSelf.viaBotNode {
|
||||||
viaBotNode.removeFromSupernode()
|
viaBotNode.removeFromSupernode()
|
||||||
strongSelf.viaBotNode = nil
|
strongSelf.viaBotNode = nil
|
||||||
@ -981,10 +1014,16 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
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)
|
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)
|
||||||
animation.animator.updateFrame(layer: forwardInfoNode.layer, frame: forwardInfoFrame, completion: nil)
|
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 {
|
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||||
if animation.isAnimated {
|
if animation.isAnimated {
|
||||||
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
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?
|
var replyBackgroundFrame: CGRect?
|
||||||
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
|
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
|
replyBackgroundFrame = replyInfoFrame
|
||||||
|
|
||||||
let replyInfoNode = replyInfoApply(replyInfoFrame.size, false, animation)
|
let replyInfoNode = replyInfoApply(replyInfoFrame.size, false, animation)
|
||||||
@ -1009,7 +1057,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
strongSelf.replyInfoNode = replyInfoNode
|
strongSelf.replyInfoNode = replyInfoNode
|
||||||
strongSelf.addSubnode(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)
|
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
|
||||||
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
} else if let replyInfoNode = strongSelf.replyInfoNode {
|
||||||
@ -1017,20 +1065,25 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
strongSelf.replyInfoNode = nil
|
strongSelf.replyInfoNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode, let replyBackgroundFrame {
|
if let backgroundContent = strongSelf.replyBackgroundContent, let replyBackgroundFrame {
|
||||||
let replyBackgroundFrame = replyBackgroundFrame
|
backgroundContent.cornerRadius = 4.0
|
||||||
animation.animator.updateFrame(layer: replyBackgroundNode.layer, frame: replyBackgroundFrame, completion: nil)
|
backgroundContent.frame = replyBackgroundFrame
|
||||||
|
}
|
||||||
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.forwardBackgroundContent, let forwardBackgroundFrame {
|
||||||
|
backgroundContent.cornerRadius = 4.0
|
||||||
|
backgroundContent.frame = forwardBackgroundFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
||||||
if let viaBotNode = strongSelf.viaBotNode {
|
if let viaBotNode = strongSelf.viaBotNode {
|
||||||
transition.updateAlpha(node: viaBotNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
transition.updateAlpha(node: viaBotNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||||
}
|
}
|
||||||
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
|
if let replyBackgroundContent = strongSelf.replyBackgroundContent {
|
||||||
transition.updateAlpha(node: replyBackgroundNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
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 {
|
if let forwardInfoNode = strongSelf.forwardInfoNode {
|
||||||
transition.updateAlpha(node: forwardInfoNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
transition.updateAlpha(node: forwardInfoNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
|
||||||
@ -1761,8 +1814,11 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
if let viaBotNode = self.viaBotNode {
|
if let viaBotNode = self.viaBotNode {
|
||||||
viaBotNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
viaBotNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||||
}
|
}
|
||||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
if let replyBackgroundContent = self.replyBackgroundContent {
|
||||||
replyBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
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 {
|
if let forwardInfoNode = self.forwardInfoNode {
|
||||||
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||||
@ -1866,8 +1922,11 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
if let viaBotNode = self.viaBotNode {
|
if let viaBotNode = self.viaBotNode {
|
||||||
viaBotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
viaBotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||||
}
|
}
|
||||||
if let replyBackgroundNode = self.replyBackgroundNode {
|
if let replyBackgroundContent = self.replyBackgroundContent {
|
||||||
replyBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
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 {
|
if let forwardInfoNode = self.forwardInfoNode {
|
||||||
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||||
|
@ -1201,7 +1201,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
|
|
||||||
textSelectionNode.enableQuote = enableQuote
|
textSelectionNode.enableQuote = enableQuote
|
||||||
textSelectionNode.enableTranslate = enableOtherActions
|
textSelectionNode.enableTranslate = enableOtherActions
|
||||||
textSelectionNode.enableShare = enableOtherActions
|
textSelectionNode.enableShare = enableOtherActions && enableCopy
|
||||||
textSelectionNode.menuSkipCoordnateConversion = !enableOtherActions
|
textSelectionNode.menuSkipCoordnateConversion = !enableOtherActions
|
||||||
self.textSelectionNode = textSelectionNode
|
self.textSelectionNode = textSelectionNode
|
||||||
self.containerNode.addSubnode(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)
|
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)
|
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))
|
alphaFraction = min(1.0, max(0.0, alphaFraction))
|
||||||
patternContentLayer.opacity = 0.3 * Float(1.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)
|
UIGraphicsPushContext(c)
|
||||||
|
|
||||||
if let customColor = customColor {
|
if let customColor = customColor {
|
||||||
|
c.clip(to: CGRect(origin: CGPoint(), size: context.size), mask: image.cgImage!)
|
||||||
c.setFillColor(customColor.cgColor)
|
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()
|
UIGraphicsPopContext()
|
||||||
}
|
}
|
||||||
memcpy(surface.argb, context.bytes, surface.height * surface.bytesPerRow)
|
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)
|
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: true, isReadOnly: false, useCaches: false, removeDatabaseOnError: false)
|
||||||
initializeAccountManagement()
|
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?
|
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
|
||||||
let semaphore = DispatchSemaphore(value: 0)
|
let semaphore = DispatchSemaphore(value: 0)
|
||||||
let systemUserInterfaceStyle: WindowUserInterfaceStyle
|
let systemUserInterfaceStyle: WindowUserInterfaceStyle
|
||||||
@ -306,7 +331,6 @@ public class ShareRootControllerImpl {
|
|||||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||||
Logger.shared.logToFile = loggingSettings.logToFile
|
Logger.shared.logToFile = loggingSettings.logToFile
|
||||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||||
|
|
||||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||||
|
|
||||||
return combineLatest(sharedContext.activeAccountsWithInfo, accountManager.transaction { transaction -> (Set<AccountRecordId>, PeerId?) in
|
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
|
}, setupReply: { [weak self] messageId in
|
||||||
self?.interfaceInteraction?.setupReplyMessage(messageId, { _, f in f() })
|
self?.interfaceInteraction?.setupReplyMessage(messageId, { _, f in f() })
|
||||||
}, canSetupReply: { [weak self] message in
|
}, canSetupReply: { [weak self] message in
|
||||||
|
if message.adAttribute != nil {
|
||||||
|
return .none
|
||||||
|
}
|
||||||
if !message.flags.contains(.Incoming) {
|
if !message.flags.contains(.Incoming) {
|
||||||
if !message.flags.intersection([.Failed, .Sending, .Unsent]).isEmpty {
|
if !message.flags.intersection([.Failed, .Sending, .Unsent]).isEmpty {
|
||||||
return .none
|
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)
|
self.textInputViewInternalInsets = UIEdgeInsets(top: 1.0, left: 13.0, bottom: 1.0, right: 13.0)
|
||||||
|
|
||||||
var hasSpoilers = true
|
var hasSpoilers = true
|
||||||
|
var hasQuotes = true
|
||||||
if presentationInterfaceState.chatLocation.peerId?.namespace == Namespaces.Peer.SecretChat {
|
if presentationInterfaceState.chatLocation.peerId?.namespace == Namespaces.Peer.SecretChat {
|
||||||
hasSpoilers = false
|
hasSpoilers = false
|
||||||
|
hasQuotes = false
|
||||||
}
|
}
|
||||||
self.inputMenu = TextInputMenu(hasSpoilers: hasSpoilers)
|
self.inputMenu = TextInputMenu(hasSpoilers: hasSpoilers, hasQuotes: hasQuotes)
|
||||||
|
|
||||||
self.clippingNode = ASDisplayNode()
|
self.clippingNode = ASDisplayNode()
|
||||||
self.clippingNode.clipsToBounds = true
|
self.clippingNode.clipsToBounds = true
|
||||||
@ -3954,18 +3956,17 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func chatInputTextNodeShouldRespondToAction(action: Selector) -> Bool {
|
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
|
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 {
|
func chatInputTextNodeShouldPaste() -> Bool {
|
||||||
let pasteboard = UIPasteboard.general
|
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
|
return entities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,8 +16,10 @@ public final class TextInputMenu {
|
|||||||
private var stringStrikethrough: String = "Strikethrough"
|
private var stringStrikethrough: String = "Strikethrough"
|
||||||
private var stringUnderline: String = "Underline"
|
private var stringUnderline: String = "Underline"
|
||||||
private var stringSpoiler: String = "Spoiler"
|
private var stringSpoiler: String = "Spoiler"
|
||||||
|
private var stringQuote: String = "Quote"
|
||||||
|
|
||||||
private let hasSpoilers: Bool
|
private let hasSpoilers: Bool
|
||||||
|
private let hasQuotes: Bool
|
||||||
|
|
||||||
public private(set) var state: State = .inactive {
|
public private(set) var state: State = .inactive {
|
||||||
didSet {
|
didSet {
|
||||||
@ -39,6 +41,9 @@ public final class TextInputMenu {
|
|||||||
if self.hasSpoilers {
|
if self.hasSpoilers {
|
||||||
menuItems.insert(UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:"))), at: 0)
|
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
|
UIMenuController.shared.menuItems = menuItems
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +53,9 @@ public final class TextInputMenu {
|
|||||||
|
|
||||||
private var observer: NSObjectProtocol?
|
private var observer: NSObjectProtocol?
|
||||||
|
|
||||||
public init(hasSpoilers: Bool = false) {
|
public init(hasSpoilers: Bool = false, hasQuotes: Bool = false) {
|
||||||
self.hasSpoilers = hasSpoilers
|
self.hasSpoilers = hasSpoilers
|
||||||
|
self.hasQuotes = hasQuotes
|
||||||
self.observer = NotificationCenter.default.addObserver(forName: UIMenuController.didHideMenuNotification, object: nil, queue: nil, using: { [weak self] _ in
|
self.observer = NotificationCenter.default.addObserver(forName: UIMenuController.didHideMenuNotification, object: nil, queue: nil, using: { [weak self] _ in
|
||||||
self?.back()
|
self?.back()
|
||||||
})
|
})
|
||||||
@ -69,6 +75,7 @@ public final class TextInputMenu {
|
|||||||
self.stringStrikethrough = strings.TextFormat_Strikethrough
|
self.stringStrikethrough = strings.TextFormat_Strikethrough
|
||||||
self.stringUnderline = strings.TextFormat_Underline
|
self.stringUnderline = strings.TextFormat_Underline
|
||||||
self.stringSpoiler = strings.TextFormat_Spoiler
|
self.stringSpoiler = strings.TextFormat_Spoiler
|
||||||
|
self.stringQuote = strings.TextFormat_Quote
|
||||||
}
|
}
|
||||||
|
|
||||||
public func activate() {
|
public func activate() {
|
||||||
|
@ -589,7 +589,7 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
highlightOverlay.innerRadius = 2.0
|
highlightOverlay.innerRadius = 2.0
|
||||||
highlightOverlay.outerRadius = 2.0
|
highlightOverlay.outerRadius = 2.0
|
||||||
highlightOverlay.inset = 1.0
|
highlightOverlay.inset = 1.0
|
||||||
highlightOverlay.useModernPathCalculation = true
|
highlightOverlay.useModernPathCalculation = false
|
||||||
|
|
||||||
self.highlightOverlay = highlightOverlay
|
self.highlightOverlay = highlightOverlay
|
||||||
self.highlightAreaNode.addSubnode(highlightOverlay)
|
self.highlightAreaNode.addSubnode(highlightOverlay)
|
||||||
@ -597,8 +597,8 @@ public final class TextSelectionNode: ASDisplayNode {
|
|||||||
highlightOverlay.frame = self.bounds
|
highlightOverlay.frame = self.bounds
|
||||||
highlightOverlay.updateRects(rects)
|
highlightOverlay.updateRects(rects)
|
||||||
if let image = self.leftKnob.image {
|
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.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 + 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.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 {
|
if self.leftKnob.alpha.isZero {
|
||||||
highlightOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
highlightOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||||
|
@ -10,6 +10,11 @@
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIImage *osImage = [[UIImage alloc] initWithData:imgData scale:1.0];
|
||||||
|
if (osImage != nil) {
|
||||||
|
return osImage;
|
||||||
|
}
|
||||||
|
|
||||||
int width = 0, height = 0;
|
int width = 0, height = 0;
|
||||||
if (!WebPGetInfo([imgData bytes], [imgData length], &width, &height)) {
|
if (!WebPGetInfo([imgData bytes], [imgData length], &width, &height)) {
|
||||||
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
|
NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "10.2",
|
"app": "10.2.1",
|
||||||
"bazel": "6.4.0",
|
"bazel": "6.4.0",
|
||||||
"xcode": "15.0"
|
"xcode": "15.0"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user