2014-11-27 09:50:09 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 OpenMarket Ltd
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#import "RoomMessage.h"
|
|
|
|
|
|
|
|
#import "MatrixHandler.h"
|
|
|
|
#import "AppSettings.h"
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
static NSAttributedString *messageSeparator = nil;
|
2014-11-27 09:50:09 +00:00
|
|
|
|
|
|
|
@interface RoomMessage() {
|
2014-11-28 09:51:22 +00:00
|
|
|
// Array of RoomMessageComponent
|
|
|
|
NSMutableArray *messageComponents;
|
|
|
|
// Current text message reset at each component change (see attributedTextMessage property)
|
|
|
|
NSMutableAttributedString *currentAttributedTextMsg;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
+ (NSAttributedString *)messageSeparator;
|
2014-11-27 09:50:09 +00:00
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation RoomMessage
|
2015-01-07 09:45:35 +00:00
|
|
|
@synthesize uploadProgress;
|
2014-11-27 09:50:09 +00:00
|
|
|
|
|
|
|
- (id)initWithEvent:(MXEvent*)event andRoomState:(MXRoomState*)roomState {
|
|
|
|
if (self = [super init]) {
|
2014-12-09 09:39:56 +00:00
|
|
|
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
|
|
|
|
2014-11-27 09:50:09 +00:00
|
|
|
_senderId = event.userId;
|
2014-12-09 09:39:56 +00:00
|
|
|
_senderName = [mxHandler senderDisplayNameForEvent:event withRoomState:roomState];
|
|
|
|
_senderAvatarUrl = [mxHandler senderAvatarUrlForEvent:event withRoomState:roomState];
|
2014-12-10 17:49:04 +00:00
|
|
|
_maxTextViewWidth = ROOM_MESSAGE_DEFAULT_MAX_TEXTVIEW_WIDTH;
|
2014-11-27 09:50:09 +00:00
|
|
|
_contentSize = CGSizeZero;
|
2015-01-07 09:45:35 +00:00
|
|
|
self.uploadProgress = -1;
|
2014-11-28 09:51:22 +00:00
|
|
|
currentAttributedTextMsg = nil;
|
2014-11-27 09:50:09 +00:00
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
// Set message type (consider text by default), and check attachment if any
|
2014-11-27 09:50:09 +00:00
|
|
|
_messageType = RoomMessageTypeText;
|
|
|
|
if ([mxHandler isSupportedAttachment:event]) {
|
|
|
|
// Note: event.eventType is equal here to MXEventTypeRoomMessage
|
|
|
|
NSString *msgtype = event.content[@"msgtype"];
|
|
|
|
if ([msgtype isEqualToString:kMXMessageTypeImage]) {
|
|
|
|
_messageType = RoomMessageTypeImage;
|
2014-12-19 16:16:24 +00:00
|
|
|
// Retrieve content url/info
|
2014-11-27 09:50:09 +00:00
|
|
|
_attachmentURL = event.content[@"url"];
|
|
|
|
_attachmentInfo = event.content[@"info"];
|
2014-12-19 16:16:24 +00:00
|
|
|
// Handle thumbnail url/info
|
2014-11-27 09:50:09 +00:00
|
|
|
_thumbnailURL = event.content[@"thumbnail_url"];
|
|
|
|
_thumbnailInfo = event.content[@"thumbnail_info"];
|
2014-12-19 16:16:24 +00:00
|
|
|
if (!_thumbnailURL) {
|
2014-12-19 17:55:42 +00:00
|
|
|
if ([_attachmentURL hasPrefix:MX_PREFIX_CONTENT_URI]) {
|
2014-12-19 16:16:24 +00:00
|
|
|
// Build the url to get the well adapted thumbnail from server
|
2014-12-19 17:55:42 +00:00
|
|
|
_thumbnailURL = _attachmentURL;
|
|
|
|
NSString *mxThumbnailPrefix = [NSString stringWithFormat:@"%@%@/thumbnail/", [mxHandler homeServerURL], kMXMediaPathPrefix];
|
2014-12-19 16:16:24 +00:00
|
|
|
_thumbnailURL = [_thumbnailURL stringByReplacingOccurrencesOfString:MX_PREFIX_CONTENT_URI withString:mxThumbnailPrefix];
|
|
|
|
// Add parameters
|
2014-12-22 07:38:39 +00:00
|
|
|
_thumbnailURL = [NSString stringWithFormat:@"%@?width=%tu&height=%tu&method=scale", _thumbnailURL, (NSUInteger)self.contentSize.width, (NSUInteger)self.contentSize.height];
|
2014-12-19 16:16:24 +00:00
|
|
|
} else {
|
|
|
|
_thumbnailURL = _attachmentURL;
|
|
|
|
}
|
|
|
|
}
|
2014-11-27 09:50:09 +00:00
|
|
|
} else if ([msgtype isEqualToString:kMXMessageTypeAudio]) {
|
|
|
|
// Not supported yet
|
|
|
|
//_messageType = RoomMessageTypeAudio;
|
|
|
|
} else if ([msgtype isEqualToString:kMXMessageTypeVideo]) {
|
|
|
|
_messageType = RoomMessageTypeVideo;
|
2014-12-19 16:16:24 +00:00
|
|
|
// Retrieve content url/info
|
2014-11-27 09:50:09 +00:00
|
|
|
_attachmentURL = event.content[@"url"];
|
|
|
|
_attachmentInfo = event.content[@"info"];
|
|
|
|
if (_attachmentInfo) {
|
2014-12-19 16:16:24 +00:00
|
|
|
// Get video thumbnail info
|
2014-11-27 09:50:09 +00:00
|
|
|
_thumbnailURL = _attachmentInfo[@"thumbnail_url"];
|
|
|
|
_thumbnailInfo = _attachmentInfo[@"thumbnail_info"];
|
|
|
|
}
|
|
|
|
} else if ([msgtype isEqualToString:kMXMessageTypeLocation]) {
|
|
|
|
// Not supported yet
|
|
|
|
// _messageType = RoomMessageTypeLocation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
// Set first component of the current message
|
|
|
|
RoomMessageComponent *msgComponent = [[RoomMessageComponent alloc] initWithEvent:event andRoomState:roomState];
|
|
|
|
if (msgComponent) {
|
|
|
|
messageComponents = [NSMutableArray array];
|
|
|
|
[messageComponents addObject:msgComponent];
|
|
|
|
// Store the actual height of the text by removing textview margin from content height
|
|
|
|
msgComponent.height = self.contentSize.height - (2 * ROOM_MESSAGE_TEXTVIEW_MARGIN);
|
|
|
|
} else {
|
2014-11-27 09:50:09 +00:00
|
|
|
// Ignore this event
|
|
|
|
self = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc {
|
2014-11-28 09:51:22 +00:00
|
|
|
messageComponents = nil;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)addEvent:(MXEvent *)event withRoomState:(MXRoomState*)roomState {
|
|
|
|
// We group together text messages from the same user
|
|
|
|
if ([event.userId isEqualToString:_senderId] && (_messageType == RoomMessageTypeText)) {
|
|
|
|
// Attachments (image, video ...) cannot be added here
|
|
|
|
MatrixHandler *mxHandler = [MatrixHandler sharedHandler];
|
|
|
|
if ([mxHandler isSupportedAttachment:event]) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check sender information
|
2014-12-09 09:39:56 +00:00
|
|
|
NSString *eventSenderName = [mxHandler senderDisplayNameForEvent:event withRoomState:roomState];
|
|
|
|
NSString *eventSenderAvatar = [mxHandler senderAvatarUrlForEvent:event withRoomState:roomState];
|
|
|
|
if ((_senderName || eventSenderName) &&
|
|
|
|
([_senderName isEqualToString:eventSenderName] == NO)) {
|
2014-11-27 09:50:09 +00:00
|
|
|
return NO;
|
|
|
|
}
|
2014-12-09 09:39:56 +00:00
|
|
|
if ((_senderAvatarUrl || eventSenderAvatar) &&
|
|
|
|
([_senderAvatarUrl isEqualToString:eventSenderAvatar] == NO)) {
|
2014-11-27 09:50:09 +00:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
// Create new message component
|
|
|
|
RoomMessageComponent *addedComponent = [[RoomMessageComponent alloc] initWithEvent:event andRoomState:roomState];
|
|
|
|
if (addedComponent) {
|
2014-12-10 17:49:04 +00:00
|
|
|
[messageComponents addObject:addedComponent];
|
2014-12-16 13:00:37 +00:00
|
|
|
// Sort components and update resulting text message
|
|
|
|
[self sortComponents];
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
// else the event is ignored, we consider it as handled
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)removeEvent:(NSString *)eventId {
|
|
|
|
if (_messageType == RoomMessageTypeText) {
|
2014-11-28 09:51:22 +00:00
|
|
|
NSUInteger index = messageComponents.count;
|
2014-11-27 09:50:09 +00:00
|
|
|
while (index--) {
|
2014-12-10 17:49:04 +00:00
|
|
|
RoomMessageComponent* msgComponent = [messageComponents objectAtIndex:index];
|
|
|
|
if ([msgComponent.eventId isEqualToString:eventId]) {
|
|
|
|
[messageComponents removeObjectAtIndex:index];
|
2014-11-28 09:51:22 +00:00
|
|
|
// Force text message refresh
|
2014-12-10 17:49:04 +00:00
|
|
|
[self refreshMessageComponentsHeight];
|
2014-11-27 09:50:09 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 17:49:04 +00:00
|
|
|
// here the provided eventId has not been found
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)containsEventId:(NSString *)eventId {
|
2014-11-28 09:51:22 +00:00
|
|
|
for (RoomMessageComponent* msgComponent in messageComponents) {
|
|
|
|
if ([msgComponent.eventId isEqualToString:eventId]) {
|
2014-11-27 09:50:09 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2014-12-16 09:23:14 +00:00
|
|
|
- (void)hideComponent:(BOOL)isHidden withEventId:(NSString*)eventId {
|
|
|
|
for (RoomMessageComponent *msgComponent in messageComponents) {
|
|
|
|
if ([msgComponent.eventId isEqualToString:eventId]) {
|
|
|
|
msgComponent.hidden = isHidden;
|
|
|
|
// Force attributed string refresh
|
|
|
|
[self refreshMessageComponentsHeight];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-16 13:00:37 +00:00
|
|
|
- (BOOL)hasSameSenderAsRoomMessage:(RoomMessage*)roomMessage {
|
|
|
|
// NOTE: same sender means here same id, same name and same avatar
|
|
|
|
// Check first user id
|
|
|
|
if ([_senderId isEqualToString:roomMessage.senderId] == NO) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
// Check sender name
|
|
|
|
if ((_senderName.length || roomMessage.senderName.length) && ([_senderName isEqualToString:roomMessage.senderName] == NO)) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
// Check avatar url
|
|
|
|
if ((_senderAvatarUrl.length || roomMessage.senderAvatarUrl.length) && ([_senderAvatarUrl isEqualToString:roomMessage.senderAvatarUrl] == NO)) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
2014-12-16 09:23:14 +00:00
|
|
|
|
2014-12-16 13:00:37 +00:00
|
|
|
- (BOOL)mergeWithRoomMessage:(RoomMessage*)roomMessage {
|
|
|
|
if ([self hasSameSenderAsRoomMessage:roomMessage]) {
|
|
|
|
if ((_messageType == RoomMessageTypeText) && (roomMessage.messageType == RoomMessageTypeText)) {
|
|
|
|
// Add all components of the provided message
|
|
|
|
for (RoomMessageComponent* msgComponent in roomMessage.components) {
|
|
|
|
[messageComponents addObject:msgComponent];
|
|
|
|
}
|
|
|
|
// Sort components and update resulting text message
|
|
|
|
[self sortComponents];
|
|
|
|
return YES;
|
2014-12-16 09:23:14 +00:00
|
|
|
}
|
2014-12-10 17:49:04 +00:00
|
|
|
}
|
2014-12-16 13:00:37 +00:00
|
|
|
return NO;
|
2014-12-10 17:49:04 +00:00
|
|
|
}
|
|
|
|
|
2014-12-16 13:00:37 +00:00
|
|
|
#pragma mark - Properties
|
2014-11-27 09:50:09 +00:00
|
|
|
|
2014-12-10 17:49:04 +00:00
|
|
|
- (void)setMaxTextViewWidth:(CGFloat)maxTextViewWidth {
|
|
|
|
if (_messageType == RoomMessageTypeText) {
|
|
|
|
// Check change
|
|
|
|
if (_maxTextViewWidth != maxTextViewWidth) {
|
|
|
|
_maxTextViewWidth = maxTextViewWidth;
|
|
|
|
// Refresh height for all message components
|
|
|
|
[self refreshMessageComponentsHeight];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-27 09:50:09 +00:00
|
|
|
- (CGSize)contentSize {
|
|
|
|
if (CGSizeEqualToSize(_contentSize, CGSizeZero)) {
|
|
|
|
if (_messageType == RoomMessageTypeText) {
|
|
|
|
if (self.attributedTextMessage.length) {
|
|
|
|
// Use a TextView template to compute cell height
|
2014-12-10 17:49:04 +00:00
|
|
|
UITextView *dummyTextView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, _maxTextViewWidth, MAXFLOAT)];
|
2014-11-27 09:50:09 +00:00
|
|
|
dummyTextView.attributedText = self.attributedTextMessage;
|
|
|
|
_contentSize = [dummyTextView sizeThatFits:dummyTextView.frame.size];
|
|
|
|
}
|
|
|
|
} else if (_messageType == RoomMessageTypeImage || _messageType == RoomMessageTypeVideo) {
|
|
|
|
CGFloat width, height;
|
|
|
|
width = height = 40;
|
2014-12-19 16:16:24 +00:00
|
|
|
if (_thumbnailInfo || _attachmentInfo) {
|
|
|
|
if (_thumbnailInfo) {
|
|
|
|
width = [_thumbnailInfo[@"w"] integerValue];
|
|
|
|
height = [_thumbnailInfo[@"h"] integerValue];
|
|
|
|
} else {
|
|
|
|
width = [_attachmentInfo[@"w"] integerValue];
|
|
|
|
height = [_attachmentInfo[@"h"] integerValue];
|
|
|
|
}
|
|
|
|
|
2014-11-28 17:36:57 +00:00
|
|
|
if (width > ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH || height > ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH) {
|
2014-11-27 09:50:09 +00:00
|
|
|
if (width > height) {
|
2014-11-28 17:36:57 +00:00
|
|
|
height = (height * ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH) / width;
|
2014-11-27 09:50:09 +00:00
|
|
|
height = floorf(height / 2) * 2;
|
2014-11-28 17:36:57 +00:00
|
|
|
width = ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH;
|
2014-11-27 09:50:09 +00:00
|
|
|
} else {
|
2014-11-28 17:36:57 +00:00
|
|
|
width = (width * ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH) / height;
|
2014-11-27 09:50:09 +00:00
|
|
|
width = floorf(width / 2) * 2;
|
2014-11-28 17:36:57 +00:00
|
|
|
height = ROOM_MESSAGE_MAX_ATTACHMENTVIEW_WIDTH;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_contentSize = CGSizeMake(width, height);
|
|
|
|
} else {
|
|
|
|
_contentSize = CGSizeMake(40, 40);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return _contentSize;
|
|
|
|
}
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
- (NSArray*)components {
|
|
|
|
return [messageComponents copy];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setAttributedTextMessage:(NSAttributedString *)inAttributedTextMessage {
|
|
|
|
if (!inAttributedTextMessage.length) {
|
|
|
|
currentAttributedTextMsg = nil;
|
|
|
|
} else {
|
|
|
|
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:inAttributedTextMessage];
|
|
|
|
}
|
|
|
|
// Reset content size
|
|
|
|
_contentSize = CGSizeZero;
|
|
|
|
}
|
|
|
|
|
2014-11-27 09:50:09 +00:00
|
|
|
- (NSAttributedString*)attributedTextMessage {
|
2014-11-28 09:51:22 +00:00
|
|
|
if (!currentAttributedTextMsg && messageComponents.count) {
|
2014-11-27 09:50:09 +00:00
|
|
|
// Create attributed string
|
2014-11-28 09:51:22 +00:00
|
|
|
for (RoomMessageComponent* msgComponent in messageComponents) {
|
2014-12-16 09:23:14 +00:00
|
|
|
if (!msgComponent.isHidden) {
|
|
|
|
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:msgComponent.textMessage attributes:[msgComponent stringAttributes]];
|
|
|
|
if (!currentAttributedTextMsg) {
|
|
|
|
currentAttributedTextMsg = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
|
|
|
|
} else {
|
|
|
|
// Append attributed text
|
|
|
|
[currentAttributedTextMsg appendAttributedString:[RoomMessage messageSeparator]];
|
|
|
|
[currentAttributedTextMsg appendAttributedString:attributedString];
|
|
|
|
}
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-28 09:51:22 +00:00
|
|
|
return currentAttributedTextMsg;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)startsWithSenderName {
|
|
|
|
if (_messageType == RoomMessageTypeText) {
|
2014-12-16 20:28:50 +00:00
|
|
|
NSUInteger index = 0;
|
|
|
|
while (index < messageComponents.count) {
|
2014-12-16 09:23:14 +00:00
|
|
|
RoomMessageComponent *msgComponent = [messageComponents objectAtIndex:index];
|
|
|
|
if (!msgComponent.isHidden) {
|
|
|
|
return msgComponent.startsWithSenderName;
|
|
|
|
}
|
2014-12-16 20:28:50 +00:00
|
|
|
index++;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isUploadInProgress {
|
|
|
|
if (_messageType != RoomMessageTypeText) {
|
2014-11-28 09:51:22 +00:00
|
|
|
if (messageComponents.count) {
|
|
|
|
RoomMessageComponent *msgComponent = [messageComponents firstObject];
|
2014-12-02 15:48:26 +00:00
|
|
|
return (msgComponent.style == RoomMessageComponentStyleInProgress);
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2014-12-19 13:16:22 +00:00
|
|
|
- (BOOL)isHidden {
|
|
|
|
if (_messageType == RoomMessageTypeText) {
|
|
|
|
return (!self.attributedTextMessage.length);
|
|
|
|
} else if (messageComponents.count) {
|
|
|
|
RoomMessageComponent *msgComponent = [messageComponents firstObject];
|
|
|
|
return msgComponent.isHidden;
|
|
|
|
}
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2014-11-27 09:50:09 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
2014-12-16 13:00:37 +00:00
|
|
|
- (void)sortComponents {
|
|
|
|
// Sort components according to their date
|
|
|
|
[messageComponents sortUsingComparator:^NSComparisonResult(RoomMessageComponent *obj1, RoomMessageComponent *obj2) {
|
|
|
|
if (obj1.date) {
|
|
|
|
if (obj2.date) {
|
|
|
|
return [obj1.date compare:obj2.date];
|
|
|
|
} else {
|
|
|
|
return NSOrderedAscending;
|
|
|
|
}
|
|
|
|
} else if (obj2.date) {
|
|
|
|
return NSOrderedDescending;
|
|
|
|
}
|
|
|
|
return NSOrderedSame;
|
|
|
|
}];
|
|
|
|
|
|
|
|
// Force text message refresh after sorting
|
|
|
|
[self refreshMessageComponentsHeight];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)refreshMessageComponentsHeight {
|
|
|
|
NSMutableArray *components = messageComponents;
|
|
|
|
messageComponents = [NSMutableArray arrayWithCapacity:components.count];
|
|
|
|
self.attributedTextMessage = nil;
|
|
|
|
for (RoomMessageComponent *msgComponent in components) {
|
|
|
|
CGFloat previousTextViewHeight = self.contentSize.height ? self.contentSize.height : (2 * ROOM_MESSAGE_TEXTVIEW_MARGIN);
|
|
|
|
[messageComponents addObject:msgComponent];
|
|
|
|
if (msgComponent.isHidden) {
|
|
|
|
msgComponent.height = 0;
|
|
|
|
} else {
|
|
|
|
// Force text message refresh
|
|
|
|
self.attributedTextMessage = nil;
|
|
|
|
msgComponent.height = self.contentSize.height - previousTextViewHeight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-28 09:51:22 +00:00
|
|
|
+ (NSAttributedString *)messageSeparator {
|
2014-11-27 09:50:09 +00:00
|
|
|
@synchronized(self) {
|
2014-11-28 09:51:22 +00:00
|
|
|
if(messageSeparator == nil) {
|
|
|
|
messageSeparator = [[NSAttributedString alloc] initWithString:@"\r\n\r\n" attributes:@{NSForegroundColorAttributeName : [UIColor blackColor],
|
2014-11-27 09:50:09 +00:00
|
|
|
NSFontAttributeName: [UIFont systemFontOfSize:4]}];
|
|
|
|
}
|
|
|
|
}
|
2014-11-28 09:51:22 +00:00
|
|
|
return messageSeparator;
|
2014-11-27 09:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|