forked from mirrors/linphone-iphone
ChatConversation: optimize conversation loading and fix UI tests
This commit is contained in:
parent
94bdcd7676
commit
50f0a56a4f
12 changed files with 146 additions and 128 deletions
|
|
@ -148,7 +148,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="75" height="66"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delete all"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<inset key="titleEdgeInsets" minX="0.0" minY="18" maxX="0.0" maxY="0.0"/>
|
||||
<state key="normal" image="cancel_edit_default.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
|
|||
|
|
@ -179,6 +179,9 @@
|
|||
cell = [[NSClassFromString(kCellId) alloc] initWithIdentifier:kCellId];
|
||||
}
|
||||
[cell setChatMessage:chat];
|
||||
if (chat) {
|
||||
[cell update];
|
||||
}
|
||||
[cell setChatRoomDelegate:_chatRoomDelegate];
|
||||
[super accessoryForCell:cell atPath:indexPath];
|
||||
return cell;
|
||||
|
|
@ -204,8 +207,8 @@
|
|||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIChatBubbleTextCell *cell = (UIChatBubbleTextCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
|
||||
return [cell viewSizeWithWidth:self.view.frame.size.width].height;
|
||||
LinphoneChatMessage *chat = ms_list_nth_data(messageList, (int)[indexPath row]);
|
||||
return [UIChatBubbleTextCell ViewSizeForMessage:chat withWidth:self.view.frame.size.width].height;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,11 +26,11 @@ typedef enum _ContactSections {
|
|||
ContactSections_None = 0, // first section is empty because we cannot set header for first section
|
||||
ContactSections_First_Name,
|
||||
ContactSections_Last_Name,
|
||||
ContactSections_Number,
|
||||
ContactSections_Sip,
|
||||
ContactSections_Number,
|
||||
ContactSections_Email,
|
||||
ContactSections_MAX
|
||||
} ContactSections_e;
|
||||
} ContactSections;
|
||||
|
||||
@interface ContactDetailsTableView : UITableViewController <UITextFieldDelegate> {
|
||||
@private
|
||||
|
|
|
|||
|
|
@ -48,10 +48,6 @@
|
|||
|
||||
@implementation ContactDetailsTableView
|
||||
|
||||
static const ContactSections_e contactSections[ContactSections_MAX] = {
|
||||
ContactSections_None, ContactSections_First_Name, ContactSections_Last_Name,
|
||||
ContactSections_Sip, ContactSections_Number, ContactSections_Email};
|
||||
|
||||
@synthesize contactDetailsDelegate;
|
||||
@synthesize contact;
|
||||
|
||||
|
|
@ -102,11 +98,11 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
}
|
||||
|
||||
- (NSMutableArray *)getSectionData:(NSInteger)section {
|
||||
if (contactSections[section] == ContactSections_Number) {
|
||||
if (section == ContactSections_Number) {
|
||||
return [dataCache objectAtIndex:0];
|
||||
} else if (contactSections[section] == ContactSections_Sip) {
|
||||
} else if (section == ContactSections_Sip) {
|
||||
return [dataCache objectAtIndex:1];
|
||||
} else if (contactSections[section] == ContactSections_Email) {
|
||||
} else if (section == ContactSections_Email) {
|
||||
if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_contacts_emails_preference"] == true) {
|
||||
return [dataCache objectAtIndex:2];
|
||||
} else {
|
||||
|
|
@ -116,7 +112,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
return nil;
|
||||
}
|
||||
|
||||
- (ABPropertyID)propertyIDForSection:(ContactSections_e)section {
|
||||
- (ABPropertyID)propertyIDForSection:(ContactSections)section {
|
||||
switch (section) {
|
||||
case ContactSections_First_Name:
|
||||
return kABPersonFirstNameProperty;
|
||||
|
|
@ -313,7 +309,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
NSUInteger count = [sectionArray count];
|
||||
CFErrorRef error = NULL;
|
||||
bool added = TRUE;
|
||||
if (contactSections[section] == ContactSections_Number) {
|
||||
if (section == ContactSections_Number) {
|
||||
ABMultiValueIdentifier identifier;
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
|
||||
ABMutableMultiValueRef lMap;
|
||||
|
|
@ -336,7 +332,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
LOGI(@"Can't add entry: %@", [(__bridge NSError *)error localizedDescription]);
|
||||
}
|
||||
CFRelease(lMap);
|
||||
} else if (contactSections[section] == ContactSections_Sip) {
|
||||
} else if (section == ContactSections_Sip) {
|
||||
Entry *entry = [self setOrCreateSipContactEntry:nil withValue:value];
|
||||
if (entry) {
|
||||
[sectionArray addObject:entry];
|
||||
|
|
@ -345,7 +341,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
added = false;
|
||||
LOGE(@"Can't add entry for value: %@", value);
|
||||
}
|
||||
} else if (contactSections[section] == ContactSections_Email) {
|
||||
} else if (section == ContactSections_Email) {
|
||||
ABMultiValueIdentifier identifier;
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
|
||||
ABMutableMultiValueRef lMap;
|
||||
|
|
@ -392,7 +388,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
if (row >= 0) {
|
||||
Entry *entry = [sectionDict objectAtIndex:row];
|
||||
|
||||
ABPropertyID property = [self propertyIDForSection:contactSections[section]];
|
||||
ABPropertyID property = [self propertyIDForSection:(ContactSections)section];
|
||||
if (property != kABInvalidPropertyType) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, property);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
|
|
@ -425,7 +421,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
- (void)removeEntry:(UITableView *)tableview path:(NSIndexPath *)indexPath animated:(BOOL)animated {
|
||||
NSMutableArray *sectionArray = [self getSectionData:[indexPath section]];
|
||||
Entry *entry = [sectionArray objectAtIndex:[indexPath row]];
|
||||
ABPropertyID property = [self propertyIDForSection:contactSections[indexPath.section]];
|
||||
ABPropertyID property = [self propertyIDForSection:(ContactSections)indexPath.section];
|
||||
|
||||
if (property != kABInvalidPropertyType) {
|
||||
ABMultiValueRef lcMap = ABRecordCopyValue(contact, property);
|
||||
|
|
@ -459,22 +455,22 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
}
|
||||
|
||||
- (void)addPhoneField:(NSString *)number {
|
||||
int i = 0;
|
||||
while (i < ContactSections_MAX && contactSections[i] != ContactSections_Number)
|
||||
ContactSections i = 0;
|
||||
while (i != ContactSections_MAX && i != ContactSections_Number)
|
||||
++i;
|
||||
[self addEntry:[self tableView] section:i animated:FALSE value:number];
|
||||
}
|
||||
|
||||
- (void)addSipField:(NSString *)address {
|
||||
int i = 0;
|
||||
while (i < ContactSections_MAX && contactSections[i] != ContactSections_Sip)
|
||||
ContactSections i = 0;
|
||||
while (i != ContactSections_MAX && i != ContactSections_Sip)
|
||||
++i;
|
||||
[self addEntry:[self tableView] section:i animated:FALSE value:address];
|
||||
}
|
||||
|
||||
- (void)addEmailField:(NSString *)address {
|
||||
int i = 0;
|
||||
while (i < ContactSections_MAX && contactSections[i] != ContactSections_Email)
|
||||
ContactSections i = 0;
|
||||
while (i != ContactSections_MAX && i != ContactSections_Email)
|
||||
++i;
|
||||
[self addEntry:[self tableView] section:i animated:FALSE value:address];
|
||||
}
|
||||
|
|
@ -486,8 +482,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
if (contactSections[section] == ContactSections_First_Name ||
|
||||
contactSections[section] == ContactSections_Last_Name) {
|
||||
if (section == ContactSections_First_Name || section == ContactSections_Last_Name) {
|
||||
return (self.tableView.isEditing) ? 1 : 0 /*no first and last name when not editting */;
|
||||
} else {
|
||||
return [[self getSectionData:section] count];
|
||||
|
|
@ -510,17 +505,17 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
NSString *label = [FastAddressBook localizedLabel:[labelArray objectAtIndex:0]];
|
||||
|
||||
[cell hideDeleteButton:NO];
|
||||
if (contactSections[indexPath.section] == ContactSections_First_Name) {
|
||||
if (indexPath.section == ContactSections_First_Name) {
|
||||
value =
|
||||
(__bridge NSString *)(ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_First_Name]));
|
||||
label = nil;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if (contactSections[indexPath.section] == ContactSections_Last_Name) {
|
||||
} else if (indexPath.section == ContactSections_Last_Name) {
|
||||
value =
|
||||
(__bridge NSString *)(ABRecordCopyValue(contact, [self propertyIDForSection:ContactSections_Last_Name]));
|
||||
label = nil;
|
||||
[cell hideDeleteButton:YES];
|
||||
} else if (contactSections[[indexPath section]] == ContactSections_Number) {
|
||||
} else if ([indexPath section] == ContactSections_Number) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonPhoneProperty);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
NSString *labelRef = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(lMap, index));
|
||||
|
|
@ -532,7 +527,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
value = [FastAddressBook localizedLabel:valueRef];
|
||||
}
|
||||
CFRelease(lMap);
|
||||
} else if (contactSections[[indexPath section]] == ContactSections_Sip) {
|
||||
} else if ([indexPath section] == ContactSections_Sip) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonInstantMessageProperty);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
|
||||
|
|
@ -556,7 +551,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
}
|
||||
CFRelease(lDict);
|
||||
CFRelease(lMap);
|
||||
} else if (contactSections[[indexPath section]] == ContactSections_Email) {
|
||||
} else if ([indexPath section] == ContactSections_Email) {
|
||||
ABMultiValueRef lMap = ABRecordCopyValue(contact, kABPersonEmailProperty);
|
||||
NSInteger index = ABMultiValueGetIndexForIdentifier(lMap, [entry identifier]);
|
||||
NSString *labelRef = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(lMap, index));
|
||||
|
|
@ -570,11 +565,11 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
CFRelease(lMap);
|
||||
}
|
||||
[cell setAddress:value];
|
||||
if (contactSections[[indexPath section]] == ContactSections_Number) {
|
||||
if ([indexPath section] == ContactSections_Number) {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypePhonePad];
|
||||
} else if (contactSections[[indexPath section]] == ContactSections_Sip) {
|
||||
} else if ([indexPath section] == ContactSections_Sip) {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
|
||||
} else if (contactSections[[indexPath section]] == ContactSections_Email) {
|
||||
} else if ([indexPath section] == ContactSections_Email) {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeASCIICapable];
|
||||
} else {
|
||||
[cell.editTextfield setKeyboardType:UIKeyboardTypeDefault];
|
||||
|
|
@ -588,7 +583,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
Entry *entry = [sectionDict objectAtIndex:[indexPath row]];
|
||||
if ([self isEditing]) {
|
||||
NSString *key = nil;
|
||||
ABPropertyID property = [self propertyIDForSection:contactSections[indexPath.section]];
|
||||
ABPropertyID property = [self propertyIDForSection:(ContactSections)indexPath.section];
|
||||
|
||||
if (property != kABInvalidPropertyType && property != kABPersonFirstNameProperty &&
|
||||
property != kABPersonLastNameProperty) {
|
||||
|
|
@ -629,8 +624,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
if (editing) {
|
||||
// add phone/SIP/email entries so that the user can add new data
|
||||
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
|
||||
if (contactSections[section] == ContactSections_Number || contactSections[section] == ContactSections_Sip ||
|
||||
(showEmails && contactSections[section] == ContactSections_Email)) {
|
||||
if (section == ContactSections_Number || section == ContactSections_Sip ||
|
||||
(showEmails && section == ContactSections_Email)) {
|
||||
[self addEntry:self.tableView section:section animated:animated];
|
||||
}
|
||||
}
|
||||
|
|
@ -639,8 +634,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
// remove empty phone numbers
|
||||
for (int section = 0; section < [self numberOfSectionsInTableView:[self tableView]]; ++section) {
|
||||
// remove phony entries that were not filled by the user
|
||||
if (contactSections[section] == ContactSections_Number || contactSections[section] == ContactSections_Sip ||
|
||||
(showEmails && contactSections[section] == ContactSections_Email)) {
|
||||
if (section == ContactSections_Number || section == ContactSections_Sip ||
|
||||
(showEmails && section == ContactSections_Email)) {
|
||||
|
||||
[self removeEmptyEntry:self.tableView section:section animated:animated];
|
||||
if ([[self getSectionData:section] count] == 0 && animated) { // the section is empty -> remove titles
|
||||
|
|
@ -665,20 +660,20 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
NSString *text = nil;
|
||||
BOOL canAddEntry = self.tableView.isEditing;
|
||||
NSString *addEntryName = nil;
|
||||
if (contactSections[section] == ContactSections_First_Name && self.tableView.isEditing) {
|
||||
if (section == ContactSections_First_Name && self.tableView.isEditing) {
|
||||
text = NSLocalizedString(@"First name", nil);
|
||||
canAddEntry = NO;
|
||||
} else if (contactSections[section] == ContactSections_Last_Name && self.tableView.isEditing) {
|
||||
} else if (section == ContactSections_Last_Name && self.tableView.isEditing) {
|
||||
text = NSLocalizedString(@"Last name", nil);
|
||||
canAddEntry = NO;
|
||||
} else if ([self getSectionData:section].count > 0 || self.tableView.isEditing) {
|
||||
if (contactSections[section] == ContactSections_Number) {
|
||||
if (section == ContactSections_Number) {
|
||||
text = NSLocalizedString(@"Phone numbers", nil);
|
||||
addEntryName = NSLocalizedString(@"Add new phone number", nil);
|
||||
} else if (contactSections[section] == ContactSections_Sip) {
|
||||
} else if (section == ContactSections_Sip) {
|
||||
text = NSLocalizedString(@"SIP addresses", nil);
|
||||
addEntryName = NSLocalizedString(@"Add new SIP address", nil);
|
||||
} else if (contactSections[section] == ContactSections_Email &&
|
||||
} else if (section == ContactSections_Email &&
|
||||
[LinphoneManager.instance lpConfigBoolForKey:@"show_contacts_emails_preference"]) {
|
||||
text = NSLocalizedString(@"Email addresses", nil);
|
||||
addEntryName = NSLocalizedString(@"Add new email", nil);
|
||||
|
|
@ -780,7 +775,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
NSIndexPath *path = [self.tableView indexPathForCell:cell];
|
||||
NSMutableArray *sectionDict = [self getSectionData:[path section]];
|
||||
Entry *entry = [sectionDict objectAtIndex:[path row]];
|
||||
ContactSections_e sect = contactSections[[path section]];
|
||||
ContactSections sect = (ContactSections)[path section];
|
||||
|
||||
ABPropertyID property = [self propertyIDForSection:sect];
|
||||
NSString *value = [textField text];
|
||||
|
|
@ -844,8 +839,8 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {
|
|||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
||||
if (section == 0 || (!self.tableView.isEditing && (contactSections[section] == ContactSections_First_Name ||
|
||||
contactSections[section] == ContactSections_Last_Name))) {
|
||||
if (section == 0 || (!self.tableView.isEditing &&
|
||||
(section == ContactSections_First_Name || section == ContactSections_Last_Name))) {
|
||||
return 1e-5;
|
||||
}
|
||||
return [self tableView:tableView viewForHeaderInSection:section].frame.size.height;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
@property(weak, nonatomic) IBOutlet UIButton *cancelButton;
|
||||
@property(weak, nonatomic) IBOutlet UIView *imageSubView;
|
||||
@property(weak, nonatomic) IBOutlet UIView *totalView;
|
||||
@property(strong, nonatomic) IBOutlet UITapGestureRecognizer *imageGestureRecognizer;
|
||||
|
||||
- (void)setChatMessage:(LinphoneChatMessage *)message;
|
||||
- (void)connectToFileDelegate:(FileTransferDelegate *)ftd;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#import <AssetsLibrary/ALAssetRepresentation.h>
|
||||
|
||||
@implementation UIChatBubblePhotoCell {
|
||||
FileTransferDelegate *ftd;
|
||||
FileTransferDelegate *_ftd;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
|
@ -53,10 +53,7 @@
|
|||
#pragma mark -
|
||||
|
||||
- (void)setChatMessage:(LinphoneChatMessage *)amessage {
|
||||
if (amessage == self.message) {
|
||||
return;
|
||||
}
|
||||
|
||||
_imageGestureRecognizer.enabled = NO;
|
||||
_messageImageView.image = nil;
|
||||
_fileTransferProgress.progress = 0;
|
||||
[self disconnectFromFileDelegate];
|
||||
|
|
@ -70,10 +67,8 @@
|
|||
(linphone_chat_message_is_outgoing(aftd.message) == linphone_chat_message_is_outgoing(amessage)) &&
|
||||
strcmp(name, linphone_content_get_name(
|
||||
linphone_chat_message_get_file_transfer_information(aftd.message))) == 0) {
|
||||
if (ftd != aftd) {
|
||||
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", amessage, aftd);
|
||||
[self connectToFileDelegate:aftd];
|
||||
}
|
||||
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", amessage, aftd);
|
||||
[self connectToFileDelegate:aftd];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -113,6 +108,7 @@
|
|||
[_messageImageView setFullImageUrl:asset];
|
||||
[_messageImageView stopLoading];
|
||||
_messageImageView.hidden = NO;
|
||||
_imageGestureRecognizer.enabled = YES;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -122,7 +118,7 @@
|
|||
}];
|
||||
}
|
||||
// we are uploading the image
|
||||
if (ftd.message != nil) {
|
||||
if (_ftd.message != nil) {
|
||||
_cancelButton.hidden = NO;
|
||||
_fileTransferProgress.hidden = NO;
|
||||
_downloadButton.hidden = YES;
|
||||
|
|
@ -133,7 +129,7 @@
|
|||
// we must download the image: either it has already started (show cancel button) or not yet (show download
|
||||
// button)
|
||||
} else {
|
||||
_messageImageView.hidden = _cancelButton.hidden = (ftd.message == nil);
|
||||
_messageImageView.hidden = _cancelButton.hidden = (_ftd.message == nil);
|
||||
_downloadButton.hidden = !_cancelButton.hidden;
|
||||
_fileTransferProgress.hidden = NO;
|
||||
|
||||
|
|
@ -156,20 +152,27 @@
|
|||
}
|
||||
|
||||
- (IBAction)onDownloadClick:(id)event {
|
||||
[ftd cancel];
|
||||
ftd = [[FileTransferDelegate alloc] init];
|
||||
[self connectToFileDelegate:ftd];
|
||||
[ftd download:self.message];
|
||||
[_ftd cancel];
|
||||
_ftd = [[FileTransferDelegate alloc] init];
|
||||
[self connectToFileDelegate:_ftd];
|
||||
[_ftd download:self.message];
|
||||
_cancelButton.hidden = NO;
|
||||
_downloadButton.hidden = YES;
|
||||
|
||||
// we must tell the tableview to refresh the cell to reflect its internal state
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
[view.tableController updateChatEntry:self.message];
|
||||
}
|
||||
|
||||
- (IBAction)onCancelClick:(id)sender {
|
||||
FileTransferDelegate *tmp = ftd;
|
||||
FileTransferDelegate *tmp = _ftd;
|
||||
[self disconnectFromFileDelegate];
|
||||
[tmp cancel];
|
||||
_fileTransferProgress.progress = 0;
|
||||
[self update];
|
||||
// we must tell the tableview to refresh the cell to reflect its internal state
|
||||
ChatConversationView *view = VIEW(ChatConversationView);
|
||||
[view.tableController updateChatEntry:self.message];
|
||||
}
|
||||
|
||||
- (void)onResendClick:(id)event {
|
||||
|
|
@ -194,22 +197,28 @@
|
|||
#pragma mark - LinphoneFileTransfer Notifications Handling
|
||||
|
||||
- (void)connectToFileDelegate:(FileTransferDelegate *)aftd {
|
||||
ftd = aftd;
|
||||
if (aftd.message && linphone_chat_message_get_state(aftd.message) == LinphoneChatMessageStateFileTransferError) {
|
||||
LOGW(@"This file transfer failed unexpectedly, cleaning it");
|
||||
[aftd stopAndDestroy];
|
||||
return;
|
||||
}
|
||||
|
||||
_ftd = aftd;
|
||||
_fileTransferProgress.progress = 0;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onFileTransferSendUpdate:)
|
||||
name:kLinphoneFileTransferSendUpdate
|
||||
object:ftd];
|
||||
object:_ftd];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onFileTransferRecvUpdate:)
|
||||
name:kLinphoneFileTransferRecvUpdate
|
||||
object:ftd];
|
||||
object:_ftd];
|
||||
}
|
||||
|
||||
- (void)disconnectFromFileDelegate {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
ftd = nil;
|
||||
_ftd = nil;
|
||||
}
|
||||
|
||||
- (void)onFileTransferSendUpdate:(NSNotification *)notif {
|
||||
|
|
@ -241,23 +250,4 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (CGSize)viewSizeWithWidth:(int)width {
|
||||
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.statusErrorImage.frame.size.width + 5) + MARGIN_WIDTH;
|
||||
bubbleSize.height = messageSize.height + MARGIN_HEIGHT;
|
||||
|
||||
return bubbleSize;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
<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="imageGestureRecognizer" destination="aDF-hC-ddO" id="2jh-Rr-eKk"/>
|
||||
<outlet property="imageSubView" destination="GmN-7v-uuO" id="k9r-Xc-csv"/>
|
||||
<outlet property="messageImageView" destination="yMW-cT-bpU" id="MNr-F2-abQ"/>
|
||||
<outlet property="resendRecognizer" destination="5ZI-Ip-lGl" id="G2r-On-6mV"/>
|
||||
|
|
@ -119,7 +120,7 @@
|
|||
<rect key="frame" x="302" y="0.0" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Message status"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" id="Eab-ND-ix3" userLabel="statusInprogressSpinner">
|
||||
<rect key="frame" x="302" y="0.0" width="20" height="20"/>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ 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 CHECK_BOX_WIDTH = 40;
|
||||
static const CGFloat IMAGE_HEIGHT = 100.0f;
|
||||
static const CGFloat IMAGE_WIDTH = 100.0f;
|
||||
|
||||
@interface UIChatBubbleTextCell : UITableViewCell
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ static const CGFloat CHECK_BOX_WIDTH = 40;
|
|||
@property(strong, nonatomic) IBOutlet UIView *bubbleView;
|
||||
@property(strong, nonatomic) IBOutlet UITapGestureRecognizer *resendRecognizer;
|
||||
|
||||
- (CGSize)viewSizeWithWidth:(int)width;
|
||||
+ (CGSize)ViewSizeForMessage:(LinphoneChatMessage *)chat withWidth:(int)width;
|
||||
|
||||
- (void)setChatMessage:(LinphoneChatMessage *)message;
|
||||
|
||||
|
|
@ -52,6 +54,6 @@ static const CGFloat CHECK_BOX_WIDTH = 40;
|
|||
- (void)update;
|
||||
|
||||
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message;
|
||||
- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
|
||||
+ (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -30,13 +30,15 @@
|
|||
|
||||
- (id)initWithIdentifier:(NSString *)identifier {
|
||||
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
|
||||
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 = ((UIView *)[arrayOfViews objectAtIndex:arrayOfViews.count - 1]);
|
||||
[self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)];
|
||||
[self addSubview:sub];
|
||||
if ([identifier isEqualToString:NSStringFromClass(self.class)]) {
|
||||
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 = ((UIView *)[arrayOfViews objectAtIndex:arrayOfViews.count - 1]);
|
||||
[self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)];
|
||||
[self addSubview:sub];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -63,16 +65,22 @@
|
|||
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 *)ContactDateForChat:(LinphoneChatMessage *)message {
|
||||
return [NSString
|
||||
stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(message)
|
||||
withFormat:LinphoneDateChatBubble],
|
||||
[FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(message)]];
|
||||
}
|
||||
|
||||
- (NSString *)textMessage {
|
||||
return [self.class TextMessageForChat:_message];
|
||||
}
|
||||
|
|
@ -83,6 +91,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
_statusInProgressSpinner.accessibilityLabel = @"Delivery in progress";
|
||||
|
||||
if (_messageText) {
|
||||
[_messageText setHidden:FALSE];
|
||||
/* We need to use an attributed string here so that data detector don't mess
|
||||
|
|
@ -108,10 +118,7 @@
|
|||
bordered:NO
|
||||
withRoundedRadius:YES];
|
||||
}
|
||||
_contactDateLabel.text = [NSString
|
||||
stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(_message)
|
||||
withFormat:LinphoneDateChatBubble],
|
||||
[FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(_message)]];
|
||||
_contactDateLabel.text = [self.class ContactDateForChat:_message];
|
||||
|
||||
_backgroundColorImage.image = _bottomBarColor.image =
|
||||
[UIImage imageNamed:(outgoing ? @"color_A.png" : @"color_D.png")];
|
||||
|
|
@ -165,7 +172,7 @@
|
|||
return;
|
||||
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(_message);
|
||||
if (state == LinphoneChatMessageStateNotDelivered) {
|
||||
if (state == LinphoneChatMessageStateNotDelivered || state == LinphoneChatMessageStateFileTransferError) {
|
||||
if (linphone_chat_message_get_file_transfer_information(_message) != NULL) {
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message];
|
||||
NSURL *imageUrl = [NSURL URLWithString:localImage];
|
||||
|
|
@ -204,7 +211,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
|
||||
#pragma mark - Bubble size computing
|
||||
|
||||
- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font {
|
||||
+ (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font {
|
||||
if (!text || text.length == 0)
|
||||
return CGSizeMake(0, 0);
|
||||
|
||||
|
|
@ -222,21 +229,36 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
{ return [text sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping]; }
|
||||
}
|
||||
|
||||
- (CGSize)viewSizeWithWidth:(int)width {
|
||||
+ (CGSize)ViewSizeForMessage:(LinphoneChatMessage *)chat withWidth:(int)width {
|
||||
static UIFont *messageFont = nil;
|
||||
static UIFont *dateFont = nil;
|
||||
static CGSize dateViewSize;
|
||||
|
||||
int messageAvailableWidth = width - MARGIN_WIDTH - CHECK_BOX_WIDTH;
|
||||
CGSize messageSize;
|
||||
|
||||
NSString *text = [UIChatBubbleTextCell TextMessageForChat:_message];
|
||||
if (!messageFont) {
|
||||
UIChatBubbleTextCell *cell =
|
||||
[[UIChatBubbleTextCell alloc] initWithIdentifier:NSStringFromClass(UIChatBubbleTextCell.class)];
|
||||
messageFont = cell.messageText.font;
|
||||
dateFont = cell.contactDateLabel.font;
|
||||
dateViewSize = cell.contactDateLabel.frame.size;
|
||||
}
|
||||
|
||||
CGSize 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));
|
||||
|
||||
CGSize dateSize =
|
||||
[self computeBoundingBox:_contactDateLabel.text size:_contactDateLabel.frame.size font:_contactDateLabel.font];
|
||||
if (linphone_chat_message_get_file_transfer_information(chat)) {
|
||||
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
messageSize = (localImage != nil) ? CGSizeMake(IMAGE_WIDTH, IMAGE_HEIGHT) : CGSizeMake(50, 50);
|
||||
} else {
|
||||
NSString *text = [UIChatBubbleTextCell TextMessageForChat:chat];
|
||||
messageSize =
|
||||
[self computeBoundingBox:text size:CGSizeMake(messageAvailableWidth, CGFLOAT_MAX) font:messageFont];
|
||||
messageSize.width = MAX(TEXT_MIN_WIDTH, ceil(messageSize.width));
|
||||
messageSize.height = MAX(TEXT_MIN_HEIGHT, ceil(messageSize.height));
|
||||
}
|
||||
CGSize dateSize = [self computeBoundingBox:[self ContactDateForChat:chat] size:dateViewSize font:dateFont];
|
||||
|
||||
CGSize bubbleSize;
|
||||
bubbleSize.width = MAX(messageSize.width, dateSize.width + _statusErrorImage.frame.size.width + 5) + MARGIN_WIDTH;
|
||||
bubbleSize.width = MAX(messageSize.width, dateSize.width + 20 /*error icon*/ + 5) + MARGIN_WIDTH;
|
||||
bubbleSize.height = messageSize.height + MARGIN_HEIGHT;
|
||||
|
||||
return bubbleSize;
|
||||
|
|
@ -248,7 +270,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st
|
|||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(_message);
|
||||
CGRect bubbleFrame = _bubbleView.frame;
|
||||
bubbleFrame.size = [self viewSizeWithWidth:self.frame.size.width];
|
||||
bubbleFrame.size = [self.class ViewSizeForMessage:_message withWidth:self.frame.size.width];
|
||||
bubbleFrame.origin.x =
|
||||
tableView.isEditing ? 0 : (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
|
||||
_bubbleView.frame = bubbleFrame;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
<rect key="frame" x="302" y="0.0" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<accessibility key="accessibilityConfiguration" label="Message status"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" id="4Z8-PE-uPe" userLabel="statusInprogressSpinner">
|
||||
<rect key="frame" x="302" y="0.0" width="20" height="20"/>
|
||||
|
|
|
|||
|
|
@ -685,7 +685,10 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
while (rooms) {
|
||||
const MSList *messages = linphone_chat_room_get_history(rooms->data, 0);
|
||||
while (messages) {
|
||||
[LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:messages->data];
|
||||
LinphoneChatMessage *msg = messages->data;
|
||||
if (!linphone_chat_message_is_outgoing(msg)) {
|
||||
[LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:messages->data];
|
||||
}
|
||||
messages = messages->next;
|
||||
}
|
||||
rooms = rooms->next;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@
|
|||
|
||||
- (void)beforeEach {
|
||||
[super beforeEach];
|
||||
if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) {
|
||||
[self goBackFromChat];
|
||||
}
|
||||
[self goBackFromChat];
|
||||
[tester tapViewWithAccessibilityLabel:@"Chat"];
|
||||
[self removeAllRooms];
|
||||
}
|
||||
|
|
@ -33,9 +31,7 @@
|
|||
[super afterAll];
|
||||
linphone_core_set_log_level(ORTP_MESSAGE);
|
||||
// at the end of tests, go back to chat rooms to display main bar
|
||||
if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) {
|
||||
[self goBackFromChat];
|
||||
}
|
||||
[self goBackFromChat];
|
||||
ASSERT_EQ([LinphoneManager instance].fileTransferDelegates.count, 0)
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +47,14 @@
|
|||
[tester tapViewWithAccessibilityLabel:@"DELETE" traits:UIAccessibilityTraitButton];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[tester tapScreenAtPoint:CGPointMake(0, 0)]; // dismiss keyboard, if any
|
||||
}
|
||||
- (void)goBackFromChat {
|
||||
[tester tapViewWithAccessibilityLabel:@"Back"];
|
||||
[self dismissKeyboard];
|
||||
if ([tester tryFindingTappableViewWithAccessibilityLabel:@"Back" error:nil]) {
|
||||
[tester tapViewWithAccessibilityLabel:@"Back"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)startChatWith:(NSString *)user {
|
||||
|
|
@ -135,9 +137,8 @@
|
|||
|
||||
[self startChatWith:user];
|
||||
[self sendMessage:user];
|
||||
[tester waitForViewWithAccessibilityLabel:@"Message status"
|
||||
value:@"not delivered"
|
||||
traits:UIAccessibilityTraitImage];
|
||||
[tester waitForViewWithAccessibilityLabel:@"Delivery failed" traits:UIAccessibilityTraitImage];
|
||||
[self dismissKeyboard];
|
||||
|
||||
[tester tapViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton];
|
||||
[tester waitForViewWithAccessibilityLabel:@"Checkbox" value:@"Deselected" traits:UIAccessibilityTraitButton];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue