#import "TGNeoAttachmentViewModel.h" #import "TGNeoImageViewModel.h" #import "TGNeoLabelViewModel.h" #import "TGStringUtils.h" #import "TGBridgeMessage.h" #import "TGBridgeUser.h" @interface TGNeoAttachmentViewModel () { TGNeoImageViewModel *_iconModel; TGNeoLabelViewModel *_textModel; } @end @implementation TGNeoAttachmentViewModel - (instancetype)initWithAttachments:(NSArray *)attachments author:(TGBridgeUser *)author forChannel:(bool)forChannel users:(NSDictionary *)users font:(UIFont *)font subTitleColor:(UIColor *)subTitleColor normalColor:(UIColor *)normalColor compact:(bool)compact { bool hasAttachment = false; NSString *messageText = nil; NSMutableAttributedString *attributedText = nil; NSString *messageIcon = nil; bool useNormalColor = false; CGFloat fontSize = font.pointSize; for (TGBridgeMediaAttachment *attachment in attachments) { if ([attachment isKindOfClass:[TGBridgeImageMediaAttachment class]]) { hasAttachment = true; TGBridgeImageMediaAttachment *imageAttachment = (TGBridgeImageMediaAttachment *)attachment; if (imageAttachment.caption.length > 0) { messageText = imageAttachment.caption; if (compact) useNormalColor = true; } else { messageText = TGLocalized(@"Message.Photo"); } if (!(useNormalColor && compact)) messageIcon = @"MediaPhoto"; } else if ([attachment isKindOfClass:[TGBridgeVideoMediaAttachment class]]) { hasAttachment = true; TGBridgeVideoMediaAttachment *videoAttachment = (TGBridgeVideoMediaAttachment *)attachment; if (videoAttachment.caption.length > 0) { messageText = videoAttachment.caption; if (compact) useNormalColor = true; } else { messageText = TGLocalized(@"Message.Video"); } if (!(useNormalColor && compact)) messageIcon = @"MediaVideo"; } else if ([attachment isKindOfClass:[TGBridgeAudioMediaAttachment class]]) { hasAttachment = true; messageText = TGLocalized(@"Message.Audio"); messageIcon = @"MediaAudio"; } else if ([attachment isKindOfClass:[TGBridgeDocumentMediaAttachment class]]) { hasAttachment = true; TGBridgeDocumentMediaAttachment *documentAttachment = (TGBridgeDocumentMediaAttachment *)attachment; if (documentAttachment.isSticker) { if (documentAttachment.stickerAlt.length > 0) messageText = [NSString stringWithFormat:@"%@ %@", documentAttachment.stickerAlt, TGLocalized(@"Message.Sticker")]; else messageText = TGLocalized(@"Message.Sticker"); } else if (documentAttachment.isAudio && documentAttachment.isVoice) { messageText = TGLocalized(@"Message.Audio"); messageIcon = @"MediaAudio"; } else { if (documentAttachment.fileName.length > 0) messageText = documentAttachment.fileName; else messageText = TGLocalized(@"Message.File"); messageIcon = @"MediaDocument"; } } else if ([attachment isKindOfClass:[TGBridgeLocationMediaAttachment class]]) { hasAttachment = true; messageText = TGLocalized(@"Message.Location"); messageIcon = @"MediaLocation"; } else if ([attachment isKindOfClass:[TGBridgeContactMediaAttachment class]]) { hasAttachment = true; messageText = TGLocalized(@"Message.Contact"); } else if ([attachment isKindOfClass:[TGBridgeActionMediaAttachment class]]) { hasAttachment = true; TGBridgeActionMediaAttachment *actionAttachment = (TGBridgeActionMediaAttachment *)attachment; NSString *actionText = nil; NSArray *additionalAttributes = nil; switch (actionAttachment.actionType) { case TGBridgeMessageActionChatEditTitle: { if (forChannel) { messageText = TGLocalized(@"Notification.RenamedChannel"); } else { NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false]; NSString *formatString = TGLocalized(@"Notification.RenamedChat"); actionText = [NSString stringWithFormat:formatString, authorName]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } } break; case TGBridgeMessageActionChatEditPhoto: { NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false]; bool changed = actionAttachment.actionData[@"photo"]; if (forChannel) { messageText = changed ? TGLocalized(@"Channel.MessagePhotoUpdated") : TGLocalized(@"Channel.MessagePhotoRemoved"); } else { NSString *formatString = changed ? TGLocalized(@"Notification.ChangedGroupPhoto") : TGLocalized(@"Notification.RemovedGroupPhoto"); actionText = [NSString stringWithFormat:formatString, authorName]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } } break; case TGBridgeMessageActionUserChangedPhoto: { } break; case TGBridgeMessageActionChatAddMember: case TGBridgeMessageActionChatDeleteMember: { NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false]; TGBridgeUser *user = users[@([actionAttachment.actionData[@"uid"] int32Value])]; if (user.identifier == author.identifier) { NSString *formatString = (actionAttachment.actionType == TGBridgeMessageActionChatAddMember) ? TGLocalized(@"Notification.JoinedChat") : TGLocalized(@"Notification.LeftChat"); actionText = [[NSString alloc] initWithFormat:formatString, authorName]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } else { NSString *userName = [TGStringUtils initialsForFirstName:user.firstName lastName:user.lastName single:false]; NSString *formatString = (actionAttachment.actionType == TGBridgeMessageActionChatAddMember) ? TGLocalized(@"Notification.Invited") : TGLocalized(@"Notification.Kicked"); actionText = [[NSString alloc] initWithFormat:formatString, authorName, userName]; NSRange formatNameRangeFirst = [formatString rangeOfString:@"%@"]; NSRange formatNameRangeSecond = formatNameRangeFirst.location != NSNotFound ? [formatString rangeOfString:@"%@" options:0 range:NSMakeRange(formatNameRangeFirst.location + formatNameRangeFirst.length, formatString.length - (formatNameRangeFirst.location + formatNameRangeFirst.length))] : NSMakeRange(NSNotFound, 0); if (formatNameRangeFirst.location != NSNotFound && formatNameRangeSecond.location != NSNotFound) { NSMutableArray *array = [[NSMutableArray alloc] init]; NSRange rangeFirst = NSMakeRange(formatNameRangeFirst.location, authorName.length); [array addObjectsFromArray:[TGNeoAttachmentViewModel _mediumFontAttributeForRange:rangeFirst fontSize:fontSize]]; [array addObjectsFromArray:[TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(rangeFirst.length - formatNameRangeFirst.length + formatNameRangeSecond.location, userName.length) fontSize:fontSize]]; additionalAttributes = array; } } } break; case TGBridgeMessageActionJoinedByLink: { NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false]; NSString *formatString = TGLocalizedStatic(@"Notification.JoinedGroupByLink"); actionText = [[NSString alloc] initWithFormat:formatString, authorName, actionAttachment.actionData[@"title"]]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } break; case TGBridgeMessageActionCreateChat: { NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false]; NSString *formatString = TGLocalizedStatic(@"Notification.CreatedChatWithTitle"); actionText = [[NSString alloc] initWithFormat:formatString, authorName, actionAttachment.actionData[@"title"]]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } break; case TGBridgeMessageActionContactRegistered: { messageText = TGLocalized(@"Watch.Notification.Joined"); } break; case TGBridgeMessageActionChannelCreated: { messageText = TGLocalized(@"Notification.CreatedChannel"); } break; case TGBridgeMessageActionChannelInviter: { TGBridgeUser *user = users[@([actionAttachment.actionData[@"uid"] int32Value])]; NSString *authorName = [TGStringUtils initialsForFirstName:user.firstName lastName:user.lastName single:false]; NSString *formatString = TGLocalizedStatic(@"Notification.ChannelInviter"); actionText = [[NSString alloc] initWithFormat:formatString, authorName]; NSRange formatNameRange = [formatString rangeOfString:@"%@"]; if (formatNameRange.location != NSNotFound) { additionalAttributes = [TGNeoAttachmentViewModel _mediumFontAttributeForRange:NSMakeRange(formatNameRange.location, authorName.length) fontSize:fontSize]; } } break; case TGBridgeMessageActionGroupMigratedTo: { messageText = TGLocalized(@"Notification.GroupMigratedToChannel"); } break; case TGBridgeMessageActionGroupActivated: { messageText = TGLocalized(@"Notification.GroupActivated"); } break; case TGBridgeMessageActionGroupDeactivated: { messageText = TGLocalized(@"Notification.GroupDeactivated"); } break; case TGBridgeMessageActionChannelMigratedFrom: { messageText = TGLocalized(@"Notification.ChannelMigratedFrom"); } break; default: break; } if (actionText != nil) { attributedText = [[NSMutableAttributedString alloc] initWithString:actionText attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:fontSize weight:UIFontWeightRegular], NSForegroundColorAttributeName: subTitleColor }]; if (additionalAttributes != nil) { NSUInteger count = additionalAttributes.count; for (NSUInteger i = 0; i < count; i += 2) { NSRange range = NSMakeRange(0, 0); [(NSValue *)[additionalAttributes objectAtIndex:i] getValue:&range]; NSDictionary *attributes = [additionalAttributes objectAtIndex:i + 1]; if (range.location + range.length <= attributedText.length) [attributedText addAttributes:attributes range:range]; } } _inhibitsInitials = true; } } else if ([attachment isKindOfClass:[TGBridgeUnsupportedMediaAttachment class]]) { hasAttachment = true; messageText = TGLocalized(@"Message.Unsupported"); } } if (!hasAttachment) return nil; self = [super init]; if (self != nil) { if (attributedText != nil) { _textModel = [[TGNeoLabelViewModel alloc] initWithAttributedText:attributedText]; _textModel.multiline = false; [self addSubmodel:_textModel]; } else { if (messageIcon != nil && !compact) { _iconModel = [[TGNeoImageViewModel alloc] initWithImage:[UIImage imageNamed:messageIcon] tintColor:subTitleColor]; if (!compact) _iconModel.frame = CGRectMake(0, 0.5f, 17, 18); else _iconModel.frame = CGRectMake(0, -2, 17, 18); [self addSubmodel:_iconModel]; } CGFloat textOffset = 0; if (_iconModel != nil) textOffset = CGRectGetMaxX(_iconModel.frame) + 2; UIColor *color = useNormalColor ? normalColor : subTitleColor; _textModel = [[TGNeoLabelViewModel alloc] initWithText:messageText font:font color:color attributes:nil]; _textModel.multiline = false; [self addSubmodel:_textModel]; } } return self; } - (void)setFrame:(CGRect)frame { [super setFrame:frame]; CGFloat textOffset = 0; if (_iconModel != nil) textOffset = CGRectGetMaxX(_iconModel.frame) + 2; _textModel.frame = CGRectMake(textOffset, 0, frame.size.width - textOffset, 20); } - (CGSize)contentSizeWithContainerSize:(CGSize)containerSize { CGFloat textOffset = 0; if (_iconModel != nil) textOffset = CGRectGetMaxX(_iconModel.frame) + 2; CGSize textSize = [_textModel contentSizeWithContainerSize:CGSizeMake(self.frame.size.width - textOffset, FLT_MAX)]; CGSize contentSize = CGSizeZero; contentSize.width = CGRectGetMaxX(self.frame); contentSize.height = textSize.height; return contentSize; } + (NSArray *)_mediumFontAttributeForRange:(NSRange)range fontSize:(CGFloat)fontSize { NSDictionary *fontAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:fontSize weight:UIFontWeightMedium], NSForegroundColorAttributeName: [UIColor whiteColor] }; return [[NSArray alloc] initWithObjects:[[NSValue alloc] initWithBytes:&range objCType:@encode(NSRange)], fontAttributes, nil]; } @end