chat: file transfer rework

This commit is contained in:
Gautier Pelloux-Prayer 2015-10-13 13:46:08 +02:00
parent 8db69e481d
commit 6a0aba483f
15 changed files with 316 additions and 466 deletions

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>

View file

@ -40,8 +40,12 @@
}
}
// also add current entry, if not listed
if (![_contacts containsObject:filter]) {
[_contacts insertObject:filter atIndex:0];
const LinphoneAddress *addr = linphone_core_interpret_url([LinphoneManager getLc], filter.UTF8String);
char *uri = linphone_address_as_string(addr);
NSString *nsuri = [NSString stringWithUTF8String:uri];
ms_free(uri);
if (![_contacts containsObject:nsuri]) {
[_contacts insertObject:nsuri atIndex:0];
}
}
@ -64,11 +68,17 @@
cell = [[UIChatCreateCell alloc] initWithIdentifier:kCellId];
}
cell.addressLabel.text = _contacts[indexPath.row];
const LinphoneAddress *addr =
linphone_core_interpret_url([LinphoneManager getLc], cell.addressLabel.text.UTF8String);
[ContactDisplay setDisplayNameLabel:cell.displayNameLabel forAddress:addr];
linphone_core_interpret_url([LinphoneManager getLc], ((NSString *)_contacts[indexPath.row]).UTF8String);
if (addr) {
char *uri = linphone_address_as_string(addr);
cell.addressLabel.text = [NSString stringWithUTF8String:uri];
ms_free(uri);
[ContactDisplay setDisplayNameLabel:cell.displayNameLabel forAddress:addr];
} else {
cell.displayNameLabel.text = _contacts[indexPath.row];
cell.addressLabel.text = NSLocalizedString(@"Invalid address", nil);
}
return cell;
}

View file

@ -25,8 +25,6 @@
@implementation ChatConversationTableView
@synthesize chatRoomDelegate;
#pragma mark - Lifecycle Functions
- (void)dealloc {
@ -181,7 +179,7 @@
cell = [[NSClassFromString(kCellId) alloc] initWithIdentifier:kCellId];
}
[cell setChatMessage:chat];
[cell setChatRoomDelegate:chatRoomDelegate];
[cell setChatRoomDelegate:_chatRoomDelegate];
[super accessoryForCell:cell atPath:indexPath];
return cell;
}

View file

@ -23,31 +23,21 @@
#import "UITextViewNoDefine.h"
#import "FileTransferDelegate.h"
#import "ChatConversationTableView.h"
#import "UIChatBubbleTextCell.h"
@interface UIChatBubblePhotoCell : UITableViewCell
@interface UIChatBubblePhotoCell : UIChatBubbleTextCell
//@property(nonatomic, strong) IBOutlet UIView *innerView;
//@property(nonatomic, strong) IBOutlet UIView *bubbleView;
//@property(nonatomic, strong) IBOutlet UIImageView *backgroundImage;
//@property(nonatomic, strong) IBOutlet UITextViewNoDefine *messageText;
//@property(nonatomic, strong) IBOutlet UILoadingImageView *messageImageView;
//@property(nonatomic, strong) IBOutlet UIButton *deleteButton;
//@property(nonatomic, strong) IBOutlet UILabel *dateLabel;
//@property(nonatomic, strong) IBOutlet UIImageView *statusImage;
//@property(nonatomic, strong) IBOutlet UIButton *downloadButton;
//@property(weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress;
//@property(weak, nonatomic) IBOutlet UIButton *cancelButton;
//@property(nonatomic, strong) id<ChatConversationDelegate> chatRoomDelegate;
//
//+ (CGFloat)height:(LinphoneChatMessage *)chatMessage width:(int)width;
//
//- (void)setChatMessage:(LinphoneChatMessage *)message;
//- (void)connectToFileDelegate:(FileTransferDelegate *)ftd;
//
//- (IBAction)onDeleteClick:(id)event;
//- (IBAction)onDownloadClick:(id)event;
//- (IBAction)onImageClick:(id)event;
//- (IBAction)onCancelDownloadClick:(id)sender;
//- (IBAction)onResendClick:(id)event;
@property(nonatomic, strong) IBOutlet UILoadingImageView *messageImageView;
@property(nonatomic, strong) IBOutlet UIButton *downloadButton;
@property(weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress;
@property(weak, nonatomic) IBOutlet UIButton *cancelButton;
@property(weak, nonatomic) IBOutlet UIView *imageSubView;
- (void)setChatMessage:(LinphoneChatMessage *)message;
- (void)connectToFileDelegate:(FileTransferDelegate *)ftd;
- (IBAction)onDownloadClick:(id)event;
- (IBAction)onImageClick:(id)event;
- (IBAction)onCancelClick:(id)sender;
- (IBAction)onResendClick:(id)event;
@end

View file

@ -25,247 +25,124 @@
#import <AssetsLibrary/ALAssetRepresentation.h>
@implementation UIChatBubblePhotoCell {
LinphoneChatMessage *message;
FileTransferDelegate *ftd;
}
#if 0
static const CGFloat CELL_MIN_HEIGHT = 50.0f;
static const CGFloat CELL_MIN_WIDTH = 150.0f;
static const CGFloat CELL_MESSAGE_X_MARGIN = 26.0f + 10.0f;
static const CGFloat CELL_MESSAGE_Y_MARGIN = 36.0f;
static const CGFloat CELL_FONT_SIZE = 17.0f;
static const CGFloat CELL_IMAGE_HEIGHT = 100.0f;
static const CGFloat CELL_IMAGE_WIDTH = 100.0f;
static UIFont *CELL_FONT = nil;
#pragma mark - Lifecycle Functions
- (id)initWithIdentifier:(NSString *)identifier {
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
#if 0
// shift message box, otherwise it will collide with the bubble
CGRect messageCoords = _messageText.frame;
messageCoords.origin.x += 2;
messageCoords.origin.y += 2;
messageCoords.size.width -= 5;
_messageText.frame = messageCoords;
_messageText.allowSelectAll = TRUE;
#endif
// TODO: remove text cell subview
NSArray *arrayOfViews =
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
// resize cell to match .nib size. It is needed when resized the cell to
// correctly adapt its height too
UIView *sub = nil;
for (int i = 0; i < arrayOfViews.count; i++) {
if ([arrayOfViews[i] isKindOfClass:UIView.class]) {
sub = arrayOfViews[i];
break;
}
}
[self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)];
[self addSubview:sub];
}
return self;
}
- (void)dealloc {
[self setChatMessage:NULL];
}
#pragma mark -
- (void)setChatMessage:(LinphoneChatMessage *)amessage {
if (amessage == message) {
if (amessage == self.message) {
return;
}
[self disconnectFromFileDelegate];
_messageImageView.image = nil;
_fileTransferProgress.progress = 0;
if (message) {
linphone_chat_message_unref(message);
linphone_chat_message_set_user_data(message, NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), NULL);
}
message = amessage;
if (amessage) {
linphone_chat_message_ref(message);
linphone_chat_message_set_user_data(message, (void *)CFBridgingRetain(self));
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), message_status);
const LinphoneContent *c = linphone_chat_message_get_file_transfer_information(message);
const LinphoneContent *c = linphone_chat_message_get_file_transfer_information(amessage);
if (c) {
const char *name = linphone_content_get_name(c);
for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) {
if (linphone_chat_message_get_file_transfer_information(aftd.message) &&
strcmp(name, linphone_content_get_name(
linphone_chat_message_get_file_transfer_information(aftd.message))) == 0) {
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message, aftd);
linphone_chat_message_get_file_transfer_information(amessage))) == 0) {
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", amessage, aftd);
[self connectToFileDelegate:aftd];
break;
}
}
}
[self update];
}
}
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message {
const char *text = linphone_chat_message_get_text(message);
return [NSString stringWithUTF8String:text] ?: [NSString stringWithCString:text encoding:NSASCIIStringEncoding]
?: NSLocalizedString(@"(invalid string)", nil);
}
- (NSString *)textMessage {
return [self.class TextMessageForChat:message];
[super setChatMessage:amessage];
}
- (void)update {
if (message == nil) {
LOGW(@"Cannot update message room cell: null message");
[super update];
if (self.message == nil) {
LOGW(@"Cannot update message room cell: NULL message");
return;
}
const char *url = linphone_chat_message_get_external_body_url(message);
LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) {
if (ftd) {
[ftd stopAndDestroy];
ftd = nil;
}
}
const char *url = linphone_chat_message_get_external_body_url(self.message);
BOOL is_external =
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(message);
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:message];
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(self.message);
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:self.message];
// this is an image (either to download or already downloaded)
if (is_external || localImage) {
if (localImage) {
if (_messageImageView.image == nil) {
NSURL *imageUrl = [NSURL URLWithString:localImage];
_messageText.hidden = YES;
[_messageImageView startLoading];
__block LinphoneChatMessage *achat = message;
[LinphoneManager.instance.photoLibrary assetForURL:imageUrl
resultBlock:^(ALAsset *asset) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
^(void) {
if (achat == message) { // Avoid glitch and scrolling
UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
dispatch_async(dispatch_get_main_queue(), ^{
[_messageImageView setImage:image];
[_messageImageView setFullImageUrl:asset];
[_messageImageView stopLoading];
_messageImageView.hidden = NO;
});
}
});
}
failureBlock:^(NSError *error) {
LOGE(@"Can't read image");
}];
}
if (ftd.message != nil) {
_cancelButton.hidden = NO;
_fileTransferProgress.hidden = NO;
_downloadButton.hidden = YES;
} else {
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES;
}
} else {
_messageText.hidden = YES;
_messageImageView.hidden = _cancelButton.hidden = _fileTransferProgress.hidden = (ftd.message == nil);
_downloadButton.hidden = !_cancelButton.hidden;
assert(is_external || localImage);
if (localImage) {
// we did not load the image yet, so start doing so
if (_messageImageView.image == nil) {
NSURL *imageUrl = [NSURL URLWithString:localImage];
[_messageImageView startLoading];
__block LinphoneChatMessage *achat = self.message;
[LinphoneManager.instance.photoLibrary assetForURL:imageUrl
resultBlock:^(ALAsset *asset) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
^(void) {
if (achat == self.message) { // Avoid glitch and scrolling
UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
dispatch_async(dispatch_get_main_queue(), ^{
[_messageImageView setImage:image];
[_messageImageView setFullImageUrl:asset];
[_messageImageView stopLoading];
_messageImageView.hidden = NO;
});
}
});
}
failureBlock:^(NSError *error) {
LOGE(@"Can't read image");
}];
}
// simple text message
} else {
[_messageText setHidden:FALSE];
/* We need to use an attributed string here so that data detector don't mess
* with the text style. See http://stackoverflow.com/a/20669356 */
NSAttributedString *attr_text =
[[NSAttributedString alloc] initWithString:self.textMessage
attributes:@{
NSFontAttributeName : [UIFont systemFontOfSize:17.0],
NSForegroundColorAttributeName : [UIColor darkGrayColor]
}];
_messageText.attributedText = attr_text;
_messageImageView.hidden = YES;
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES;
}
// Date
_dateLabel.text =
[LinphoneUtils timeToString:linphone_chat_message_get_time(message) withStyle:NSDateFormatterMediumStyle];
LinphoneChatMessageState state = linphone_chat_message_get_state(message);
BOOL outgoing = linphone_chat_message_is_outgoing(message);
if (!outgoing) {
[_statusImage setAccessibilityValue:@"incoming"];
_statusImage.hidden = TRUE; // not useful for incoming chats..
} else if (state == LinphoneChatMessageStateInProgress) {
[_statusImage setImage:[UIImage imageNamed:@"chat_message_inprogress.png"]];
[_statusImage setAccessibilityValue:@"in progress"];
_statusImage.hidden = FALSE;
} else if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateFileTransferDone) {
[_statusImage setImage:[UIImage imageNamed:@"chat_message_delivered.png"]];
[_statusImage setAccessibilityValue:@"delivered"];
_statusImage.hidden = FALSE;
} else {
[_statusImage setImage:[UIImage imageNamed:@"chat_message_not_delivered.png"]];
[_statusImage setAccessibilityValue:@"not delivered"];
_statusImage.hidden = FALSE;
NSAttributedString *resend_text =
[[NSAttributedString alloc] initWithString:NSLocalizedString(@"Resend", @"Resend")
attributes:@{NSForegroundColorAttributeName : [UIColor redColor]}];
[_dateLabel setAttributedText:resend_text];
}
if (outgoing) {
[_messageText setAccessibilityLabel:@"Outgoing message"];
} else {
[_messageText setAccessibilityLabel:@"Incoming message"];
}
}
- (void)setEditing:(BOOL)editing {
[self setEditing:editing animated:FALSE];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
}
_deleteButton.hidden = !editing;
if (animated) {
[UIView commitAnimations];
}
}
#pragma mark - View Functions
- (void)layoutSubviews {
[super layoutSubviews];
if (message != nil) {
BOOL is_outgoing = linphone_chat_message_is_outgoing(message);
CGRect innerFrame;
innerFrame.size = [self.class viewSize:message width:[self frame].size.width];
innerFrame.origin.y = 0.0f;
innerFrame.origin.x = is_outgoing ? self.frame.size.width - innerFrame.size.width : 0;
_innerView.frame = innerFrame;
CGRect messageFrame = _bubbleView.frame;
messageFrame.origin.y = (_innerView.frame.size.height - messageFrame.size.height) / 2;
if (!is_outgoing) {
messageFrame.origin.y += 5;
// we are uploading the image
if (ftd.message != nil) {
_cancelButton.hidden = NO;
_fileTransferProgress.hidden = NO;
_downloadButton.hidden = YES;
} else {
messageFrame.origin.y -= 5;
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES;
}
_backgroundImage.image =
is_outgoing ? [UIImage imageNamed:@"chat_bubble_outgoing"] : [UIImage imageNamed:@"chat_bubble_incoming"];
_bubbleView.frame = messageFrame;
}
}
#pragma mark - Action Functions
- (IBAction)onDeleteClick:(id)event {
if (message != NULL) {
[ftd cancel];
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
NSIndexPath *indexPath = [tableView indexPathForCell:self];
[tableView.dataSource tableView:tableView
commitEditingStyle:UITableViewCellEditingStyleDelete
forRowAtIndexPath:indexPath];
// we must download the image: either it has already started (show cancel button) or not yet (show download
// button)
} else {
// CGRect newFrame = _imageSubView.frame;
// newFrame.origin.y = _messageImageView.frame.origin.y + ((ftd.message == nil) ? 0 :
//_messageImageView.frame.size.height);
// _imageSubView.frame = newFrame;
_messageImageView.hidden = _cancelButton.hidden = (ftd.message == nil);
_downloadButton.hidden = !_cancelButton.hidden;
_fileTransferProgress.hidden = NO;
}
}
@ -273,20 +150,25 @@ static UIFont *CELL_FONT = nil;
[ftd cancel];
ftd = [[FileTransferDelegate alloc] init];
[self connectToFileDelegate:ftd];
[ftd download:message];
[ftd download:self.message];
_cancelButton.hidden = NO;
_downloadButton.hidden = YES;
}
- (IBAction)onCancelDownloadClick:(id)sender {
- (IBAction)onCancelClick:(id)sender {
FileTransferDelegate *tmp = ftd;
[self disconnectFromFileDelegate];
[tmp cancel];
_fileTransferProgress.progress = 0;
[self update];
}
- (void)onResendClick:(id)event {
[super onResendClick:event];
}
- (IBAction)onImageClick:(id)event {
LinphoneChatMessageState state = linphone_chat_message_get_state(message);
LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
if (state == LinphoneChatMessageStateNotDelivered) {
[self onResendClick:event];
} else {
@ -300,69 +182,6 @@ static UIFont *CELL_FONT = nil;
}
}
- (IBAction)onResendClick:(id)event {
if (message == nil)
return;
LinphoneChatMessageState state = linphone_chat_message_get_state(message);
if (state == LinphoneChatMessageStateNotDelivered) {
if (linphone_chat_message_get_file_transfer_information(message) != NULL) {
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:message];
NSURL *imageUrl = [NSURL URLWithString:localImage];
[self onDeleteClick:nil];
[[LinphoneManager instance]
.photoLibrary assetForURL:imageUrl
resultBlock:^(ALAsset *asset) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
^(void) {
UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
[_chatRoomDelegate startImageUpload:image url:imageUrl];
});
}
failureBlock:^(NSError *error) {
LOGE(@"Can't read image");
}];
} else {
[self onDeleteClick:nil];
double delayInSeconds = 0.4;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil];
});
}
}
}
#pragma mark - State changed handling
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
UIChatBubblePhotoCell *thiz = (__bridge UIChatBubblePhotoCell *)linphone_chat_message_get_user_data(msg);
LOGI(@"State for message [%p] changed to %s", msg, linphone_chat_message_state_to_string(state));
if (linphone_chat_message_get_file_transfer_information(msg) != NULL) {
if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) {
// we need to refresh the tableview because the filetransfer delegate unreffed
// the message message before state was LinphoneChatMessageStateFileTransferDone -
// if we are coming back from another view between unreffing and change of state,
// the transient message will not be found and it will not appear in the list of
// message, so we must refresh the table when we change to this state to ensure that
// all transient messages apppear
// ChatRoomViewController *controller = DYNAMIC_CAST(
// [PhoneMainView.instance changeCurrentView:ChatRoomViewController.compositeViewDescription
// push:TRUE],
// ChatRoomViewController);
// [controller.tableController setChatRoom:linphone_chat_message_get_chat_room(msg)];
// This is breaking interface too much, it must be fixed in file transfer cb.. meanwhile, disabling it.
if (thiz->ftd) {
[thiz->ftd stopAndDestroy];
thiz->ftd = nil;
}
}
}
[thiz update];
}
#pragma mark - LinphoneFileTransfer Notifications Handling
- (void)connectToFileDelegate:(FileTransferDelegate *)aftd {
@ -389,9 +208,9 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
if (state == LinphoneChatMessageStateInProgress) {
float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue];
// When uploading a file, the message file is first uploaded to the server,
// When uploading a file, the self.message file is first uploaded to the server,
// so we are in progress state. Then state goes to filetransfertdone. Then,
// the exact same message is sent to the other participant and we come
// the exact same self.message is sent to the other participant and we come
// back to in progress again. This second time is NOT an upload, so we must
// not update progress!
_fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress);
@ -410,6 +229,25 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
[self update];
}
}
#endif
- (CGSize)viewSizeWithWidth:(int)width {
static const CGFloat MARGIN_WIDTH = 60;
static const CGFloat MARGIN_HEIGHT = 19 + 16 /*this 16 is because textview add some top&bottom padding*/;
static const CGFloat IMAGE_HEIGHT = 100.0f;
static const CGFloat IMAGE_WIDTH = 100.0f;
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:self.message];
CGSize messageSize = (localImage != nil) ? CGSizeMake(IMAGE_WIDTH, IMAGE_HEIGHT) : CGSizeMake(50, 50);
CGSize dateSize = [self computeBoundingBox:self.contactDateLabel.text
size:self.contactDateLabel.frame.size
font:self.contactDateLabel.font];
CGSize bubbleSize;
bubbleSize.width = MAX(messageSize.width, dateSize.width + self.statusImage.frame.size.width + 5) + MARGIN_WIDTH;
bubbleSize.height = messageSize.height + MARGIN_HEIGHT;
return bubbleSize;
}
@end

View file

@ -1,102 +1,125 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIChatBubblePhotoCell">
<connections>
<outlet property="avatarImage" destination="hD2-19-7IH" id="N1B-Jn-wTo"/>
<outlet property="backgroundColorImage" destination="U2P-5n-gg8" id="1Hn-bx-mua"/>
<outlet property="bottomBarColor" destination="6dA-3U-OPW" id="xJX-pe-zlu"/>
<outlet property="bubbleView" destination="UGz-WT-BUv" id="8qr-kw-dSx"/>
<outlet property="cancelButton" destination="6dl-Nz-rdv" id="ygz-nv-omC"/>
<outlet property="contactDateLabel" destination="JyR-RQ-uwF" id="Tc4-9t-i5V"/>
<outlet property="downloadButton" destination="N75-gL-R6t" id="EgN-Ab-Ded"/>
<outlet property="fileTransferProgress" destination="USm-wC-GvG" id="POt-YD-NCG"/>
<outlet property="imageSubView" destination="GmN-7v-uuO" id="k9r-Xc-csv"/>
<outlet property="messageImageView" destination="yMW-cT-bpU" id="MNr-F2-abQ"/>
<outlet property="statusImage" destination="hSL-MF-B9b" id="cwm-bV-O3a"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="qHD-cv-2vc">
<rect key="frame" x="0.0" y="0.0" width="320" height="159"/>
<view contentMode="scaleToFill" id="UGz-WT-BUv">
<rect key="frame" x="0.0" y="0.0" width="334" height="140"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" usesAttributedText="YES" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="Tzq-H4-Xn9" userLabel="contactDateLabel">
<rect key="frame" x="66" y="8" width="246" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Contact name"/>
<attributedString key="attributedText">
<fragment content="11:35 John ">
<attributes>
<color key="NSColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<font key="NSFont" size="16" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="truncatingTail" baseWritingDirection="natural"/>
</attributes>
</fragment>
<fragment content="Doe">
<attributes>
<color key="NSColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<font key="NSFont" size="16" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="truncatingTail" baseWritingDirection="natural"/>
</attributes>
</fragment>
</attributedString>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="avatar.png" id="6V0-NH-dBG" userLabel="avatarImage" customClass="UIRoundedImageView">
<rect key="frame" x="8" y="5" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Contact avatar">
<accessibilityTraits key="traits" none="YES" image="YES" notEnabled="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
</imageView>
<view contentMode="scaleToFill" id="1ze-V7-Vi5" userLabel="textView">
<rect key="frame" x="66" y="30" width="246" height="129"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view clipsSubviews="YES" contentMode="scaleToFill" id="Y7i-Gm-AdY" userLabel="innerView">
<rect key="frame" x="6" y="5" width="322" height="130"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" text="Placeholder text is another very long ipsem lum dolorem...and it continues" id="Hnc-55-etE" userLabel="messageText">
<rect key="frame" x="0.0" y="0.0" width="246" height="121"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
</view>
<view hidden="YES" contentMode="scaleToFill" id="GmN-7v-uuO" userLabel="imageView">
<rect key="frame" x="66" y="30" width="246" height="129"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" id="USm-wC-GvG" userLabel="transferProgress">
<rect key="frame" x="4" y="93" width="238" height="2"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</progressView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="128 Ko / 172 Ko" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aaa-MV-yvm" userLabel="fileSizeLabel">
<rect key="frame" x="4" y="73" width="238" height="12"/>
<imageView userInteractionEnabled="NO" alpha="0.20000000298023224" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" id="U2P-5n-gg8" userLabel="backgroundColorImage">
<rect key="frame" x="0.0" y="0.0" width="322" height="130"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="avatar.png" id="hD2-19-7IH" userLabel="avatarImage" customClass="UIRoundedImageView">
<rect key="frame" x="7" y="1" width="40" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Contact avatar">
<accessibilityTraits key="traits" none="YES" image="YES" notEnabled="YES"/>
<bool key="isElement" value="YES"/>
</accessibility>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" usesAttributedText="YES" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="10" id="JyR-RQ-uwF" userLabel="contactDateLabel">
<rect key="frame" x="48" y="0.0" width="246" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" label="Contact name"/>
<attributedString key="attributedText">
<fragment content="11:35 John ">
<attributes>
<color key="NSColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<font key="NSFont" size="16" name="HelveticaNeue"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="truncatingTail" baseWritingDirection="natural"/>
</attributes>
</fragment>
<fragment content="Doe">
<attributes>
<color key="NSColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<font key="NSFont" size="16" name="HelveticaNeue-Bold"/>
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="truncatingTail" baseWritingDirection="natural"/>
</attributes>
</fragment>
</attributedString>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashscreen.png" id="yMW-cT-bpU" userLabel="image" customClass="UILoadingImageView">
<rect key="frame" x="48" y="24" width="274" height="67"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
<gestureRecognizers/>
</imageView>
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="128 Ko / 172 Ko" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aaa-MV-yvm" userLabel="fileSizeLabel">
<rect key="frame" x="24" y="59" width="274" height="12"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="splashscreen.png" id="yMW-cT-bpU" userLabel="image">
<rect key="frame" x="8" y="0.0" width="230" height="65"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<gestureRecognizers/>
<connections>
<outletCollection property="gestureRecognizers" destination="aDF-hC-ddO" appends="YES" id="4oe-Ga-fHE"/>
</connections>
<view contentMode="scaleToFill" id="GmN-7v-uuO" userLabel="imageSubView">
<rect key="frame" x="48" y="91" width="274" height="32.000000029802322"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
<subviews>
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" id="USm-wC-GvG" userLabel="transferProgress">
<rect key="frame" x="10" y="0.0" width="254" height="2"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
</progressView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="N75-gL-R6t" userLabel="transferButton" customClass="UIRoundBorderedButton">
<rect key="frame" x="75" y="4.0000000298023224" width="124" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" title="DOWNLOAD">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onDownloadClick:" destination="-1" eventType="touchUpInside" id="8BO-9E-iOX"/>
</connections>
</button>
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="6dl-Nz-rdv" userLabel="cancelButton" customClass="UIRoundBorderedButton">
<rect key="frame" x="75" y="4.0000000298023224" width="124" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" title="CANCEL">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onCancelClick:" destination="-1" eventType="touchUpInside" id="D9y-vf-I4Y"/>
</connections>
</button>
</subviews>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_message_inprogress.png" id="hSL-MF-B9b" userLabel="statusImage">
<rect key="frame" x="307" y="0.0" width="15" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" id="6dA-3U-OPW" userLabel="bottomBarColor">
<rect key="frame" x="0.0" y="129" width="322" height="1"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="N75-gL-R6t" userLabel="transferButton" customClass="UIRoundBorderedButton">
<rect key="frame" x="0.0" y="98" width="124" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="DOWNLOAD">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
</button>
</subviews>
<connections>
<outletCollection property="gestureRecognizers" destination="5ZI-Ip-lGl" appends="YES" id="zzJ-Rp-wx6"/>
</connections>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="chat_message_inprogress.png" id="x07-o6-6s0" userLabel="messageStatusImage">
<rect key="frame" x="305" y="0.0" width="15" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="339" y="43.5"/>
<point key="canvasLocation" x="-95" y="166"/>
</view>
<tapGestureRecognizer id="aDF-hC-ddO" userLabel="imageClick">
<connections>
@ -110,9 +133,10 @@
</tapGestureRecognizer>
</objects>
<resources>
<image name="avatar.png" width="261" height="261"/>
<image name="chat_message_inprogress.png" width="12" height="12"/>
<image name="splashscreen.png" width="185" height="169"/>
<image name="avatar.png" width="255" height="255"/>
<image name="chat_message_inprogress.png" width="11" height="12"/>
<image name="color_A.png" width="1" height="1"/>
<image name="splashscreen.png" width="181" height="165"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>

View file

@ -25,6 +25,7 @@
@interface UIChatBubbleTextCell : UITableViewCell
@property(readonly, nonatomic) LinphoneChatMessage *message;
@property(nonatomic, weak) IBOutlet UIImageView *backgroundColorImage;
@property(nonatomic, weak) IBOutlet UIRoundedImageView *avatarImage;
@property(nonatomic, weak) IBOutlet UILabel *contactDateLabel;
@ -40,7 +41,9 @@
- (IBAction)onDeleteClick:(id)event;
- (IBAction)onResendClick:(id)event;
- (void)update;
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message;
- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
@end

View file

@ -24,9 +24,7 @@
#import <AssetsLibrary/ALAsset.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
@implementation UIChatBubbleTextCell {
LinphoneChatMessage *message;
}
@implementation UIChatBubbleTextCell
#pragma mark - Lifecycle Functions
@ -50,60 +48,63 @@
#pragma mark -
- (void)setChatMessage:(LinphoneChatMessage *)amessage {
if (amessage == message) {
if (amessage == _message) {
return;
}
if (message) {
linphone_chat_message_unref(message);
linphone_chat_message_set_user_data(message, NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), NULL);
if (_message) {
linphone_chat_message_unref(_message);
linphone_chat_message_set_user_data(_message, NULL);
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), NULL);
}
message = amessage;
_message = amessage;
if (amessage) {
linphone_chat_message_ref(message);
linphone_chat_message_set_user_data(message, (void *)CFBridgingRetain(self));
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), message_status);
linphone_chat_message_ref(_message);
linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self));
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status);
[self update];
}
}
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message {
const char *text = linphone_chat_message_get_text(message);
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)_message {
const char *text = linphone_chat_message_get_text(_message) ?: "";
return [NSString stringWithUTF8String:text] ?: [NSString stringWithCString:text encoding:NSASCIIStringEncoding]
?: NSLocalizedString(@"(invalid string)", nil);
}
- (NSString *)textMessage {
return [self.class TextMessageForChat:message];
return [self.class TextMessageForChat:_message];
}
- (void)update {
if (message == nil) {
LOGW(@"Cannot update message room cell: null message");
if (_message == nil) {
LOGW(@"Cannot update _message room cell: null _message");
return;
}
[_messageText setHidden:FALSE];
/* We need to use an attributed string here so that data detector don't mess
* with the text style. See http://stackoverflow.com/a/20669356 */
NSAttributedString *attr_text =
[[NSAttributedString alloc] initWithString:self.textMessage
attributes:@{
NSFontAttributeName : _messageText.font,
NSForegroundColorAttributeName : [UIColor darkGrayColor]
}];
_messageText.attributedText = attr_text;
if (_messageText) {
[_messageText setHidden:FALSE];
/* We need to use an attributed string here so that data detector don't mess
* with the text style. See http://stackoverflow.com/a/20669356 */
NSAttributedString *attr_text =
[[NSAttributedString alloc] initWithString:self.textMessage
attributes:@{
NSFontAttributeName : _messageText.font,
NSForegroundColorAttributeName : [UIColor darkGrayColor]
}];
_messageText.attributedText = attr_text;
}
// Date
_contactDateLabel.text = [NSString
stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(message)
stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(_message)
withStyle:NSDateFormatterShortStyle],
[FastAddressBook displayNameForAddress:linphone_chat_message_get_peer_address(message)]];
[FastAddressBook displayNameForAddress:linphone_chat_message_get_peer_address(_message)]];
LinphoneChatMessageState state = linphone_chat_message_get_state(message);
BOOL outgoing = linphone_chat_message_is_outgoing(message);
LinphoneChatMessageState state = linphone_chat_message_get_state(_message);
BOOL outgoing = linphone_chat_message_is_outgoing(_message);
_backgroundColorImage.image = _bottomBarColor.image = [UIImage imageNamed:(outgoing ? @"color_A" : @"color_D")];
if (!outgoing) {
@ -129,9 +130,9 @@
}
if (outgoing) {
[_messageText setAccessibilityLabel:@"Outgoing message"];
[_messageText setAccessibilityLabel:@"Outgoing _message"];
} else {
[_messageText setAccessibilityLabel:@"Incoming message"];
[_messageText setAccessibilityLabel:@"Incoming _message"];
}
}
@ -146,7 +147,7 @@
#pragma mark - Action Functions
- (IBAction)onDeleteClick:(id)event {
if (message != NULL) {
if (_message != NULL) {
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
NSIndexPath *indexPath = [tableView indexPathForCell:self];
[tableView.dataSource tableView:tableView
@ -156,13 +157,13 @@
}
- (IBAction)onResendClick:(id)event {
if (message == nil)
if (_message == nil)
return;
LinphoneChatMessageState state = linphone_chat_message_get_state(message);
LinphoneChatMessageState state = linphone_chat_message_get_state(_message);
if (state == LinphoneChatMessageStateNotDelivered) {
if (linphone_chat_message_get_file_transfer_information(message) != NULL) {
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:message];
if (linphone_chat_message_get_file_transfer_information(_message) != NULL) {
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message];
NSURL *imageUrl = [NSURL URLWithString:localImage];
[self onDeleteClick:nil];
@ -199,56 +200,46 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
#pragma mark - Bubble size computing
- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 7) {
return [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{
NSFontAttributeName : font
}
context:nil]
.size;
}
#endif
{ return [text sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping]; }
}
- (CGSize)viewSizeWithWidth:(int)width {
static const CGFloat TEXT_MIN_HEIGHT = 32.;
static const CGFloat TEXT_MIN_WIDTH = 150.0f;
static const CGFloat MARGIN_WIDTH = 60;
static const CGFloat MARGIN_HEIGHT = 19 + 16 /*this 16 is because textview add some top&bottom padding*/;
static const CGFloat IMAGE_HEIGHT = 100.0f; // TODO: move that in bubblephoto
static const CGFloat IMAGE_HEIGHT = 100.0f;
static const CGFloat IMAGE_WIDTH = 100.0f;
static const CGFloat CHECK_BOX_WIDTH = 40;
CGSize messageSize, dateSize;
int messageAvailableWidth = width - MARGIN_WIDTH - CHECK_BOX_WIDTH;
const char *url = linphone_chat_message_get_external_body_url(message);
if (url == nil && linphone_chat_message_get_file_transfer_information(message) == NULL) {
NSString *text = [UIChatBubbleTextCell TextMessageForChat:message];
const char *url = linphone_chat_message_get_external_body_url(_message);
NSString *text = [UIChatBubbleTextCell TextMessageForChat:_message];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 7) {
messageSize =
[text boundingRectWithSize:CGSizeMake(messageAvailableWidth, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:@{
NSFontAttributeName : _messageText.font
}
context:nil]
.size;
dateSize = [_contactDateLabel.text boundingRectWithSize:_contactDateLabel.frame.size
options:(NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading)
attributes:@{
NSFontAttributeName : _contactDateLabel.font
}
context:nil]
.size;
} else
#endif
{
messageSize = [text sizeWithFont:_messageText.font
constrainedToSize:CGSizeMake(messageAvailableWidth, CGFLOAT_MAX)
lineBreakMode:NSLineBreakByCharWrapping];
dateSize = [_contactDateLabel.text sizeWithFont:_contactDateLabel.font
constrainedToSize:_contactDateLabel.frame.size
lineBreakMode:NSLineBreakByCharWrapping];
}
} else {
CGSize messageSize;
if (url != nil || linphone_chat_message_get_file_transfer_information(_message) != NULL) {
messageSize = CGSizeMake(IMAGE_WIDTH, IMAGE_HEIGHT);
} else {
messageSize =
[self computeBoundingBox:text size:CGSizeMake(messageAvailableWidth, CGFLOAT_MAX) font:_messageText.font];
messageSize.width = MAX(TEXT_MIN_WIDTH, ceil(messageSize.width));
messageSize.height = MAX(TEXT_MIN_HEIGHT, ceil(messageSize.height));
}
messageSize.width = MAX(TEXT_MIN_WIDTH, ceil(messageSize.width));
messageSize.height = MAX(TEXT_MIN_HEIGHT, ceil(messageSize.height));
CGSize dateSize =
[self computeBoundingBox:_contactDateLabel.text size:_contactDateLabel.frame.size font:_contactDateLabel.font];
CGSize bubbleSize;
bubbleSize.width = MAX(messageSize.width, dateSize.width + _statusImage.frame.size.width + 5) + MARGIN_WIDTH;
@ -259,9 +250,9 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
- (void)layoutSubviews {
[super layoutSubviews];
if (message != nil) {
if (_message != nil) {
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
BOOL is_outgoing = linphone_chat_message_is_outgoing(message);
BOOL is_outgoing = linphone_chat_message_is_outgoing(_message);
CGRect bubbleFrame = _bubbleView.frame;
bubbleFrame.size = [self viewSizeWithWidth:self.frame.size.width];
bubbleFrame.origin.x =

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>

View file

@ -124,6 +124,7 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m
// this is the last time we will be notified, so destroy ourselve
if (remaining <= size) {
LOGI(@"Upload ended");
linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(thiz.message), NULL);
thiz.message = NULL;
[thiz stopAndDestroy];
}

@ -1 +1 @@
Subproject commit 0efd4dfd5b37fb28ba1ecbabcc8d37defddfd517
Subproject commit c9e603882c3b6bd2b387f17ba8c003ffb4f218fe

@ -1 +1 @@
Subproject commit 4e3ea86c90cf125f1348dc4f296540d1696e5851
Subproject commit 34d3a0583b69946d35b4c7e968530e359423603f