1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-11 17:09:46 +01:00
Telegram/Telegraph/TGTextMessageModernViewModel.m

342 lines
14 KiB
Mathematica
Raw Normal View History

2014-07-10 16:11:09 +02:00
#import "TGTextMessageModernViewModel.h"
#import "TGTelegraphConversationMessageAssetsSource.h"
#import "TGImageUtils.h"
#import "TGDateUtils.h"
#import "TGStringUtils.h"
#import "TGFont.h"
#import "TGModernConversationItem.h"
#import "TGModernView.h"
#import "TGModernFlatteningViewModel.h"
#import "TGModernImageViewModel.h"
#import "TGModernTextViewModel.h"
#import "TGModernLabelViewModel.h"
#import "TGModernDateViewModel.h"
#import "TGModernRemoteImageViewModel.h"
#import "TGModernClockProgressViewModel.h"
#import "TGTextMessageBackgroundViewModel.h"
#import "TGReusableLabel.h"
#import "TGMessage.h"
#import "TGUser.h"
#import "TGDoubleTapGestureRecognizer.h"
@interface TGTextMessageModernViewModel () <UIGestureRecognizerDelegate, TGDoubleTapGestureRecognizerDelegate>
{
TGModernTextViewModel *_textModel;
bool _textIsRTL;
NSArray *_currentLinkSelectionViews;
}
@end
@implementation TGTextMessageModernViewModel
static CTFontRef textFontForSize(CGFloat size)
{
static CTFontRef font = NULL;
static int cachedSize = 0;
if ((int)size != cachedSize || font == NULL)
{
font = TGCoreTextSystemFontOfSize(size);
cachedSize = (int)size;
}
return font;
}
- (instancetype)initWithMessage:(TGMessage *)message author:(TGUser *)author context:(TGModernViewContext *)context
{
self = [super initWithMessage:message author:author context:context];
if (self != nil)
{
static TGTelegraphConversationMessageAssetsSource *assetsSource = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
assetsSource = [TGTelegraphConversationMessageAssetsSource instance];
});
_textModel = [[TGModernTextViewModel alloc] initWithText:message.text font:textFontForSize(TGGetMessageViewModelLayoutConstants()->textFontSize)];
_textModel.textCheckingResults = message.textCheckingResults;
_textModel.textColor = [assetsSource messageTextColor];
_textModel.layoutFlags = TGReusableLabelLayoutMultiline | TGReusableLabelLayoutHighlightLinks | TGReusableLabelLayoutDateSpacing | (_incoming ? 0 : TGReusableLabelLayoutExtendedDateSpacing);
[_contentModel addSubmodel:_textModel];
}
return self;
}
- (void)refreshMetrics
{
[_textModel setFont:textFontForSize(TGGetMessageViewModelLayoutConstants()->textFontSize)];
}
- (void)setIsUnsupported:(bool)isUnsupported
{
if (isUnsupported)
{
_textModel.text = TGLocalized(@"Conversation.UnsupportedMedia");
NSRange range = [_textModel.text rangeOfString:@"http://telegram.org/update"];
if (range.location != NSNotFound)
{
_textModel.textCheckingResults = @[[NSTextCheckingResult linkCheckingResultWithRange:range URL:[NSURL URLWithString:@"http://telegram.org/update"]]];
}
}
}
- (void)unbindView:(TGModernViewStorage *)viewStorage
{
[self clearLinkSelection];
[super unbindView:viewStorage];
}
- (void)messageDoubleTapGesture:(TGDoubleTapGestureRecognizer *)recognizer
{
if (recognizer.state != UIGestureRecognizerStateBegan)
{
[self clearLinkSelection];
if (recognizer.state == UIGestureRecognizerStateRecognized)
{
CGPoint point = [recognizer locationInView:[_contentModel boundView]];
NSString *linkCandidate = [_textModel linkAtPoint:CGPointMake(point.x - _textModel.frame.origin.x, point.y - _textModel.frame.origin.y) regionData:NULL];
if (recognizer.longTapped)
{
if (linkCandidate != nil)
[_context.companionHandle requestAction:@"openLinkWithOptionsRequested" options:@{@"url": linkCandidate}];
else
[_context.companionHandle requestAction:@"messageSelectionRequested" options:@{@"mid": @(_mid)}];
}
else if (recognizer.doubleTapped)
[_context.companionHandle requestAction:@"messageSelectionRequested" options:@{@"mid": @(_mid)}];
else if (linkCandidate != nil)
[_context.companionHandle requestAction:@"openLinkRequested" options:@{@"url": linkCandidate}];
else if (_forwardedHeaderModel && CGRectContainsPoint(_forwardedHeaderModel.frame, point))
[_context.companionHandle requestAction:@"userAvatarTapped" options:@{@"uid": @(_forwardedUid)}];
}
}
}
- (void)gestureRecognizer:(TGDoubleTapGestureRecognizer *)__unused recognizer didBeginAtPoint:(CGPoint)point
{
[self updateLinkSelection:point];
}
- (void)gestureRecognizerDidFail:(TGDoubleTapGestureRecognizer *)__unused recognizer
{
[self clearLinkSelection];
}
- (bool)gestureRecognizerShouldHandleLongTap:(TGDoubleTapGestureRecognizer *)__unused recognizer
{
return true;
}
- (int)gestureRecognizer:(TGDoubleTapGestureRecognizer *)__unused recognizer shouldFailTap:(CGPoint)point
{
if ([_textModel linkAtPoint:CGPointMake(point.x - _textModel.frame.origin.x, point.y - _textModel.frame.origin.y) regionData:NULL] != nil ||
(_forwardedHeaderModel && CGRectContainsPoint(_forwardedHeaderModel.frame, point)))
return 3;
return false;
}
- (void)clearLinkSelection
{
for (UIView *linkView in _currentLinkSelectionViews)
{
[linkView removeFromSuperview];
}
_currentLinkSelectionViews = nil;
}
- (void)updateLinkSelection:(CGPoint)point
{
if ([_contentModel boundView] != nil)
{
[self clearLinkSelection];
NSArray *regionData = nil;
NSString *link = [_textModel linkAtPoint:CGPointMake(point.x - _textModel.frame.origin.x, point.y - _textModel.frame.origin.y) regionData:&regionData];
if (link != nil)
{
CGRect topRegion = regionData.count > 0 ? [regionData[0] CGRectValue] : CGRectZero;
CGRect middleRegion = regionData.count > 1 ? [regionData[1] CGRectValue] : CGRectZero;
CGRect bottomRegion = regionData.count > 2 ? [regionData[2] CGRectValue] : CGRectZero;
UIImageView *topView = nil;
UIImageView *middleView = nil;
UIImageView *bottomView = nil;
UIImageView *topCornerLeft = nil;
UIImageView *topCornerRight = nil;
UIImageView *bottomCornerLeft = nil;
UIImageView *bottomCornerRight = nil;
NSMutableArray *linkHighlightedViews = [[NSMutableArray alloc] init];
topView = [[UIImageView alloc] init];
middleView = [[UIImageView alloc] init];
bottomView = [[UIImageView alloc] init];
topCornerLeft = [[UIImageView alloc] init];
topCornerRight = [[UIImageView alloc] init];
bottomCornerLeft = [[UIImageView alloc] init];
bottomCornerRight = [[UIImageView alloc] init];
if (topRegion.size.height != 0)
{
topView.hidden = false;
topView.frame = topRegion;
if (middleRegion.size.height == 0 && bottomRegion.size.height == 0)
topView.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkFull];
else
topView.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkFull];
}
else
{
topView.hidden = true;
topView.frame = CGRectZero;
}
if (middleRegion.size.height != 0)
{
middleView.hidden = false;
middleView.frame = middleRegion;
if (bottomRegion.size.height == 0)
middleView.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkFull];
else
middleView.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkFull];
}
else
{
middleView.hidden = true;
middleView.frame = CGRectZero;
}
if (bottomRegion.size.height != 0)
{
bottomView.hidden = false;
bottomView.frame = bottomRegion;
bottomView.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkFull];
}
else
{
bottomView.hidden = true;
bottomView.frame = CGRectZero;
}
topCornerLeft.hidden = true;
topCornerRight.hidden = true;
bottomCornerLeft.hidden = true;
bottomCornerRight.hidden = true;
if (topRegion.size.height != 0 && middleRegion.size.height != 0)
{
if (topRegion.origin.x == middleRegion.origin.x)
{
topCornerLeft.hidden = false;
topCornerLeft.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerLR];
topCornerLeft.frame = CGRectMake(topRegion.origin.x, topRegion.origin.y + topRegion.size.height - 3.5f, 4, 7);
}
else if (topRegion.origin.x < middleRegion.origin.x + middleRegion.size.width - 3.5f)
{
topCornerLeft.hidden = false;
topCornerLeft.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerBT];
topCornerLeft.frame = CGRectMake(topRegion.origin.x - 3.5f, topRegion.origin.y + topRegion.size.height - 4, 7, 4);
}
if (topRegion.origin.x + topRegion.size.width == middleRegion.origin.x + middleRegion.size.width)
{
topCornerRight.hidden = false;
topCornerRight.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerRL];
topCornerRight.frame = CGRectMake(topRegion.origin.x + topRegion.size.width - 4, topRegion.origin.y + topRegion.size.height - 3.5f, 4, 7);
}
else if (topRegion.origin.x + topRegion.size.width < middleRegion.origin.x + middleRegion.size.width - 3.5f)
{
topCornerRight.hidden = false;
topCornerRight.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerBT];
topCornerRight.frame = CGRectMake(topRegion.origin.x + topRegion.size.width - 3.5f, topRegion.origin.y + topRegion.size.height - 4, 7, 4);
}
else if (bottomRegion.size.height == 0 && topRegion.origin.x < middleRegion.origin.x + middleRegion.size.width - 3.5f && topRegion.origin.x + topRegion.size.width > middleRegion.origin.x + middleRegion.size.width + 3.5f)
{
topCornerRight.hidden = false;
topCornerRight.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerTB];
topCornerRight.frame = CGRectMake(middleRegion.origin.x + middleRegion.size.width - 3.5f, middleRegion.origin.y, 7, 4);
}
}
if (middleRegion.size.height != 0 && bottomRegion.size.height != 0)
{
if (middleRegion.origin.x == bottomRegion.origin.x)
{
bottomCornerLeft.hidden = false;
bottomCornerLeft.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerLR];
bottomCornerLeft.frame = CGRectMake(middleRegion.origin.x, middleRegion.origin.y + middleRegion.size.height - 3.5f, 4, 7);
}
if (bottomRegion.origin.x + bottomRegion.size.width < middleRegion.origin.x + middleRegion.size.width - 3.5f)
{
bottomCornerRight.hidden = false;
bottomCornerRight.image = [[TGTelegraphConversationMessageAssetsSource instance] messageLinkCornerTB];
bottomCornerRight.frame = CGRectMake(bottomRegion.origin.x + bottomRegion.size.width - 3.5f, bottomRegion.origin.y, 7, 4);
}
}
if (!topView.hidden)
[linkHighlightedViews addObject:topView];
if (!middleView.hidden)
[linkHighlightedViews addObject:middleView];
if (!bottomView.hidden)
[linkHighlightedViews addObject:bottomView];
if (!topCornerLeft.hidden)
[linkHighlightedViews addObject:topCornerLeft];
if (!topCornerRight.hidden)
[linkHighlightedViews addObject:topCornerRight];
if (!bottomCornerLeft.hidden)
[linkHighlightedViews addObject:bottomCornerLeft];
if (!bottomCornerRight.hidden)
[linkHighlightedViews addObject:bottomCornerRight];
for (UIView *partView in linkHighlightedViews)
{
partView.frame = CGRectOffset(partView.frame, _textModel.frame.origin.x, _textModel.frame.origin.y + 1);
[[_contentModel boundView] addSubview:partView];
}
_currentLinkSelectionViews = linkHighlightedViews;
}
}
}
- (void)layoutContentForHeaderHeight:(CGFloat)headerHeight
{
CGRect textFrame = _textModel.frame;
textFrame.origin = CGPointMake(1, headerHeight + TGGetMessageViewModelLayoutConstants()->textBubbleTextOffsetTop);
_textModel.frame = textFrame;
}
- (CGSize)contentSizeForContainerSize:(CGSize)containerSize needsContentsUpdate:(bool *)needsContentsUpdate
{
bool updateContents = [_textModel layoutNeedsUpdatingForContainerSize:containerSize];
if (updateContents)
[_textModel layoutForContainerSize:containerSize];
if (needsContentsUpdate != NULL)
*needsContentsUpdate = updateContents;
return _textModel.frame.size;
}
@end