mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
Various improvements
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldRespondToAction)(SEL _Nullable);
|
||||
@property (nonatomic, copy) bool (^ _Nullable shouldReturn)();
|
||||
@property (nonatomic, copy) void (^ _Nullable backspaceWhileEmpty)();
|
||||
@property (nonatomic, copy) void (^ _Nullable dropAutocorrectioniOS16)();
|
||||
|
||||
- (instancetype _Nonnull)initWithFrame:(CGRect)frame textContainer:(NSTextContainer * _Nullable)textContainer disableTiling:(bool)disableTiling;
|
||||
|
||||
|
||||
@@ -12,6 +12,12 @@
|
||||
|
||||
@end
|
||||
|
||||
@interface ChatInputTextViewImpl () <UIGestureRecognizerDelegate> {
|
||||
UIGestureRecognizer *_tapRecognizer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ChatInputTextViewImpl
|
||||
|
||||
- (instancetype _Nonnull)initWithFrame:(CGRect)frame textContainer:(NSTextContainer * _Nullable)textContainer disableTiling:(bool)disableTiling {
|
||||
@@ -26,10 +32,40 @@
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
if (@available(iOS 17.0, *)) {
|
||||
} else {
|
||||
_tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(workaroundTapGesture:)];
|
||||
_tapRecognizer.cancelsTouchesInView = false;
|
||||
_tapRecognizer.delaysTouchesBegan = false;
|
||||
_tapRecognizer.delaysTouchesEnded = false;
|
||||
_tapRecognizer.delegate = self;
|
||||
[self addGestureRecognizer:_tapRecognizer];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)workaroundTapGesture:(UITapGestureRecognizer *)recognizer {
|
||||
if (recognizer.state == UIGestureRecognizerStateEnded) {
|
||||
static Class promptClass = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
promptClass = NSClassFromString([[NSString alloc] initWithFormat:@"%@AutocorrectInlinePrompt", @"UI"]);
|
||||
});
|
||||
UIView *result = [self hitTest:[recognizer locationInView:self] withEvent:nil];
|
||||
if (result != nil && [result class] == promptClass) {
|
||||
if (_dropAutocorrectioniOS16) {
|
||||
_dropAutocorrectioniOS16();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
|
||||
{
|
||||
if (_shouldRespondToAction) {
|
||||
|
||||
@@ -32,7 +32,6 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
}
|
||||
|
||||
private var selectionChangedForEditedText: Bool = false
|
||||
private var isPreservingSelection: Bool = false
|
||||
|
||||
public var textView: ChatInputTextView {
|
||||
return self.view as! ChatInputTextView
|
||||
@@ -81,20 +80,7 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
get {
|
||||
return self.textView.attributedText
|
||||
} set(value) {
|
||||
if self.textView.attributedText != value {
|
||||
let selectedRange = self.textView.selectedRange;
|
||||
let preserveSelectedRange = selectedRange.location != self.textView.textStorage.length
|
||||
|
||||
self.textView.attributedText = value ?? NSAttributedString()
|
||||
|
||||
if preserveSelectedRange {
|
||||
self.isPreservingSelection = true
|
||||
self.textView.selectedRange = selectedRange
|
||||
self.isPreservingSelection = false
|
||||
}
|
||||
|
||||
self.textView.updateTextContainerInset()
|
||||
}
|
||||
self.textView.attributedText = value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +150,7 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
}
|
||||
|
||||
@objc public func textViewDidChangeSelection(_ textView: UITextView) {
|
||||
if self.isPreservingSelection {
|
||||
if self.textView.isPreservingSelection {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -187,6 +173,9 @@ open class ChatInputTextNode: ASDisplayNode, UITextViewDelegate {
|
||||
guard let delegate = self.delegate else {
|
||||
return true
|
||||
}
|
||||
if self.textView.isPreservingText {
|
||||
return false
|
||||
}
|
||||
return delegate.chatInputTextNode(shouldChangeTextIn: range, replacementText: text)
|
||||
}
|
||||
|
||||
@@ -306,6 +295,30 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele
|
||||
}
|
||||
}
|
||||
|
||||
override public var attributedText: NSAttributedString? {
|
||||
get {
|
||||
return super.attributedText
|
||||
} set(value) {
|
||||
if self.attributedText != value {
|
||||
let selectedRange = self.selectedRange
|
||||
let preserveSelectedRange = selectedRange.location != self.textStorage.length
|
||||
|
||||
super.attributedText = value ?? NSAttributedString()
|
||||
|
||||
if preserveSelectedRange {
|
||||
self.isPreservingSelection = true
|
||||
self.selectedRange = selectedRange
|
||||
self.isPreservingSelection = false
|
||||
}
|
||||
|
||||
self.updateTextContainerInset()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var isPreservingSelection: Bool = false
|
||||
fileprivate var isPreservingText: Bool = false
|
||||
|
||||
public weak var customDelegate: ChatInputTextNodeDelegate?
|
||||
|
||||
public var theme: Theme? {
|
||||
@@ -391,6 +404,27 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele
|
||||
self.customTextStorage.delegate = self
|
||||
self.measurementTextStorage.delegate = self
|
||||
|
||||
self.dropAutocorrectioniOS16 = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.isPreservingSelection = true
|
||||
self.isPreservingText = true
|
||||
|
||||
let rangeCopy = self.selectedRange
|
||||
var fakeRange = rangeCopy
|
||||
if fakeRange.location != 0 {
|
||||
fakeRange.location -= 1
|
||||
}
|
||||
self.unmarkText()
|
||||
self.selectedRange = fakeRange
|
||||
self.selectedRange = rangeCopy
|
||||
|
||||
self.isPreservingSelection = false
|
||||
self.isPreservingText = false
|
||||
}
|
||||
|
||||
self.shouldCopy = { [weak self] in
|
||||
guard let self else {
|
||||
return true
|
||||
@@ -542,7 +576,7 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele
|
||||
|
||||
if self.measurementTextStorage != self.attributedText || self.measurementTextContainer.size != measureSize || self.measurementTextContainer.rightInset != rightInset {
|
||||
self.measurementTextContainer.rightInset = rightInset
|
||||
self.measurementTextStorage.setAttributedString(self.attributedText)
|
||||
self.measurementTextStorage.setAttributedString(self.attributedText ?? NSAttributedString())
|
||||
self.measurementTextContainer.size = measureSize
|
||||
self.measurementLayoutManager.invalidateLayout(forCharacterRange: NSRange(location: 0, length: self.measurementTextStorage.length), actualCharacterRange: nil)
|
||||
self.measurementLayoutManager.ensureLayout(for: self.measurementTextContainer)
|
||||
|
||||
@@ -547,7 +547,15 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
var adjustedConstrainedTextSize = contrainedTextSize
|
||||
var textCutout: TextNodeCutout?
|
||||
var textCutoutWidth: CGFloat = 0.0
|
||||
if arguments.quote != nil || arguments.replyForward?.quote != nil {
|
||||
|
||||
var isQuote = false
|
||||
if arguments.quote != nil {
|
||||
isQuote = true
|
||||
} else if let replyForward = arguments.replyForward, replyForward.quote != nil, replyForward.isQuote {
|
||||
isQuote = true
|
||||
}
|
||||
|
||||
if isQuote {
|
||||
additionalTitleWidth += 10.0
|
||||
maxTitleNumberOfLines = 2
|
||||
maxTextNumberOfLines = 5
|
||||
@@ -770,7 +778,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode {
|
||||
animation: animation
|
||||
)
|
||||
|
||||
if arguments.quote != nil || arguments.replyForward?.quote != nil {
|
||||
if isQuote {
|
||||
let quoteIconView: UIImageView
|
||||
if let current = node.quoteIconView {
|
||||
quoteIconView = current
|
||||
|
||||
Reference in New Issue
Block a user