diff --git a/Classes/Base.lproj/ChatConversationImdnView.xib b/Classes/Base.lproj/ChatConversationImdnView.xib
index c768ffd1d..99dc77538 100644
--- a/Classes/Base.lproj/ChatConversationImdnView.xib
+++ b/Classes/Base.lproj/ChatConversationImdnView.xib
@@ -1,17 +1,15 @@
-
+
+
-
+
+
+
-
-
-
-
-
@@ -19,19 +17,19 @@
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
@@ -112,10 +76,14 @@
-
-
+
+
+
+
+
+
diff --git a/Classes/Base.lproj/ChatConversationView.xib b/Classes/Base.lproj/ChatConversationView.xib
index e4db76e66..446b483da 100644
--- a/Classes/Base.lproj/ChatConversationView.xib
+++ b/Classes/Base.lproj/ChatConversationView.xib
@@ -31,6 +31,7 @@
+
@@ -387,6 +388,11 @@
+
+
+
+
+
diff --git a/Classes/Base.lproj/ChatsListView.xib b/Classes/Base.lproj/ChatsListView.xib
index 7ee88726d..a9ecaa1a0 100644
--- a/Classes/Base.lproj/ChatsListView.xib
+++ b/Classes/Base.lproj/ChatsListView.xib
@@ -1,7 +1,10 @@
-
+
+
-
+
+
+
@@ -10,6 +13,8 @@
+
+
@@ -18,19 +23,19 @@
-
+
-
+
-
+
+
-
+
-
+
-
+
@@ -146,31 +165,39 @@
+
-
+
-
+
-
+
-
+
@@ -190,6 +217,7 @@
+
@@ -198,5 +226,11 @@
+
+
+
+
+
+
diff --git a/Classes/ChatConversationImdnView.h b/Classes/ChatConversationImdnView.h
index 67d6d820b..78a9042b6 100644
--- a/Classes/ChatConversationImdnView.h
+++ b/Classes/ChatConversationImdnView.h
@@ -36,13 +36,11 @@
@property(nonatomic) bctbx_list_t *receivedList;
@property(nonatomic) bctbx_list_t *notReceivedList;
@property(nonatomic) bctbx_list_t *errorList;
+@property(nonatomic) UIChatBubbleTextCell *cell;
+@property(nonatomic) NSTimer *ephemeralDisplayTimer;
+
@property (weak, nonatomic) IBOutlet UIView *msgView;
-@property (weak, nonatomic) IBOutlet UIImageView *msgBackgroundColorImage;
-@property (weak, nonatomic) IBOutlet UIRoundedImageView *msgAvatarImage;
-@property (weak, nonatomic) IBOutlet UIImageView *msgBottomBar;
-@property (weak, nonatomic) IBOutlet UILabel *msgDateLabel;
-@property (weak, nonatomic) IBOutlet UITextViewNoDefine *msgText;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
- (IBAction)onBackClick:(id)sender;
diff --git a/Classes/ChatConversationImdnView.m b/Classes/ChatConversationImdnView.m
index 38ceeb337..c99f9859a 100644
--- a/Classes/ChatConversationImdnView.m
+++ b/Classes/ChatConversationImdnView.m
@@ -22,6 +22,7 @@
#import "ChatConversationImdnView.h"
#import "PhoneMainView.h"
#import "UIChatBubbleTextCell.h"
+#import "UIChatBubblePhotoCell.h"
#import "UIChatConversationImdnTableViewCell.h"
@implementation ChatConversationImdnView
@@ -52,21 +53,40 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
- const LinphoneAddress *addr = linphone_chat_message_get_from_address(_msg);
- BOOL outgoing = linphone_chat_message_is_outgoing(_msg);
-
- _msgDateLabel.text = [NSString stringWithFormat:@"%@ - %@",
- [LinphoneUtils timeToString:linphone_chat_message_get_time(_msg) withFormat:LinphoneDateChatBubble],
- [FastAddressBook displayNameForAddress:addr]];
- _msgAvatarImage.image = outgoing ? [LinphoneUtils selfAvatar] : [FastAddressBook imageForAddress:addr];
- _msgText.text = messageText;
- _msgBackgroundColorImage.image = _msgBottomBar.image = [UIImage imageNamed:(outgoing ? @"color_A.png" : @"color_D.png")];
- _msgDateLabel.textColor = [UIColor colorWithPatternImage:_msgBackgroundColorImage.image];
-
+
+ int index = [VIEW(ChatConversationView).tableController indexOfMesssage:_msg];
+ if (index < 0)
+ [PhoneMainView.instance popToView:ChatConversationView.compositeViewDescription];
+
+ _cell = (UIChatBubbleTextCell *)[VIEW(ChatConversationView).tableController tableView:VIEW(ChatConversationView).tableController.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]];
+ _cell.frame = CGRectMake(-10,0,_msgView.frame.size.width,_msgView.frame.size.height);
+ _cell.isFirst = true;
+ _cell.isLast = true;
+ [_cell update];
+ _cell.popupMenuAllowed = false;
+ for (UIView *v in [_msgView subviews]) {
+ [v removeFromSuperview];
+ }
+ [_msgView addSubview:_cell];
+
+
_tableView.delegate = self;
_tableView.dataSource = self;
[self updateImdnList];
+ [self fitContent];
+ [self startEphemeralDisplayTimer];
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(ephemeralDeleted:)
+ name:kLinphoneEphemeralMessageDeletedInRoom
+ object:nil];
+
+}
+
+-(void) viewWillDisappear:(BOOL)animated {
+ [self stopEphemeralDisplayTimer];
+ [NSNotificationCenter.defaultCenter removeObserver:self];
+ [super viewWillDisappear:animated];
}
- (void)updateImdnList {
@@ -81,15 +101,12 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (void)fitContent {
- [self setMessageText];
-
- BOOL outgoing = linphone_chat_message_is_outgoing(_msg);
- _msgBackgroundColorImage.image = _msgBottomBar.image = [UIImage imageNamed:(outgoing ? @"color_A.png" : @"color_D.png")];
- _msgDateLabel.textColor = [UIColor colorWithPatternImage:_msgBackgroundColorImage.image];
+
+ CGSize messageSize = [UIChatBubbleTextCell ViewHeightForMessage:_msg withWidth:self.view.frame.size.width];
[_msgView setFrame:CGRectMake(_msgView.frame.origin.x,
_msgView.frame.origin.y,
- _msgView.frame.size.width,
- [UIChatBubbleTextCell ViewHeightForMessageText:_msg withWidth:self.view.frame.size.width textForImdn:messageText].height)];
+ self.view.frame.size.width,
+ messageSize.height+5)];
[_tableView setFrame:CGRectMake(_tableView.frame.origin.x,
_msgView.frame.origin.y + _msgView.frame.size.height + 10,
@@ -101,18 +118,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[self fitContent];
}
-- (void)setMessageText {
- const char *utf8Text= linphone_chat_message_get_text_content(_msg);
- LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(_msg);
- messageText = nil;
- if (utf8Text) {
- messageText = [NSString stringWithUTF8String:utf8Text];
- if (fileContent)
- messageText = [NSString stringWithFormat:@"%@\n%@", messageText, [NSString stringWithUTF8String: linphone_content_get_name(fileContent)]];
- } else {
- messageText = [NSString stringWithUTF8String: linphone_content_get_name(fileContent)];
- }
-}
+
#pragma mark - TableView
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@@ -278,4 +284,38 @@ static UICompositeViewDescription *compositeDescription = nil;
[PhoneMainView.instance popCurrentView];
}
+#pragma mark ephemeral messages
+
+-(void) startEphemeralDisplayTimer {
+ _ephemeralDisplayTimer = [NSTimer scheduledTimerWithTimeInterval:1
+ target:self
+ selector:@selector(updateEphemeralTimes)
+ userInfo:nil
+ repeats:YES];
+}
+
+-(void) updateEphemeralTimes {
+ NSDateComponentsFormatter *f= [[NSDateComponentsFormatter alloc] init];
+ f.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
+ f.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
+
+ if (linphone_chat_message_is_ephemeral(_msg)) {
+ long duration = linphone_chat_message_get_ephemeral_expire_time(_msg) == 0 ?
+ linphone_chat_room_get_ephemeral_lifetime(linphone_chat_message_get_chat_room(_msg)) :
+ linphone_chat_message_get_ephemeral_expire_time(_msg)-[NSDate date].timeIntervalSince1970;
+ f.allowedUnits = (duration > 86400 ? kCFCalendarUnitDay : 0)|(duration > 3600 ? kCFCalendarUnitHour : 0)|kCFCalendarUnitMinute|kCFCalendarUnitSecond;
+ _cell.ephemeralTime.text = [f stringFromTimeInterval:duration];
+ _cell.ephemeralTime.hidden = NO;
+ _cell.ephemeralIcon.hidden = NO;
+ }
+}
+
+-(void) stopEphemeralDisplayTimer {
+ [_ephemeralDisplayTimer invalidate];
+}
+
+- (void)ephemeralDeleted:(NSNotification *)notif {
+ [PhoneMainView.instance popToView:ChatConversationView.compositeViewDescription];
+}
+
@end
diff --git a/Classes/ChatConversationTableView.h b/Classes/ChatConversationTableView.h
index 1a3f783d7..1fe9ff3e2 100644
--- a/Classes/ChatConversationTableView.h
+++ b/Classes/ChatConversationTableView.h
@@ -39,10 +39,10 @@
@protocol ChatConversationDelegate
-- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent;
-- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent;
-- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name;
-- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url voiceContent:(LinphoneContent *)voiceContent;
+- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message rootMessage:(LinphoneChatMessage *)rootMessage;
+- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message rootMessage:(LinphoneChatMessage *)rootMessage;
+- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name rootMessage:(LinphoneChatMessage *)rootMessage;
+- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url rootMessage:(LinphoneChatMessage *)rootMessage;
- (void)tableViewIsScrolling;
@end
@@ -64,5 +64,9 @@
- (void)scrollToLastUnread:(BOOL)animated;
- (void)updateEventEntry:(LinphoneEventLog *)event;
- (void)refreshData;
+- (void)reloadData;
+- (void) dismissMessagesPopups;
+- (void) scrollToMessage:(LinphoneChatMessage *)message;
+- (int) indexOfMesssage:(LinphoneChatMessage *)message;
@end
diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m
index 5673c0766..45b44367d 100644
--- a/Classes/ChatConversationTableView.m
+++ b/Classes/ChatConversationTableView.m
@@ -49,6 +49,7 @@
}
-(void) viewWillDisappear:(BOOL)animated {
+ [self dismissMessagesPopups];
[self stopEphemeralDisplayTimer];
[NSNotificationCenter.defaultCenter removeObserver:self];
[super viewWillDisappear:animated];
@@ -204,6 +205,39 @@
animated:animated];
}
+
+- (void) scrollToMessage:(LinphoneChatMessage *)message {
+ int index = [self indexOfMesssage:message];
+ if (index < 0)
+ return;
+
+ [self.tableView.layer removeAllAnimations];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]
+ atScrollPosition:UITableViewScrollPositionTop
+ animated:true];
+}
+
+-(int) indexOfMesssage:(LinphoneChatMessage *)message {
+ if (eventList.count == 0 || _chatRoom == nil)
+ return -1;
+
+ int index = -1;
+ size_t count = eventList.count;
+ for (int i = (int)count - 1; i > 0; --i) {
+ LinphoneEventLog *event = [[eventList objectAtIndex:i] pointerValue];
+ if (!(linphone_event_log_get_type(event) == LinphoneEventLogTypeConferenceChatMessage))
+ continue;;
+
+ LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event);
+ if (chat == message) {
+ index = i;
+ break;
+ }
+
+ }
+ return index;
+}
+
#pragma mark - Property Functions
- (void)setChatRoom:(LinphoneChatRoom *)room {
@@ -275,6 +309,15 @@ static const int BASIC_EVENT_LIST=15;
if (!_chatRoom && [[cell reuseIdentifier] isEqualToString:@"UIChatBubblePhotoCell"]) {
[(UIChatBubbleTextCell *)cell clearEncryptedFiles];
}
+ if ([cell isKindOfClass:[UIChatBubbleTextCell class]] ||[cell isKindOfClass:[UIChatBubblePhotoCell class]])
+ [(UIChatBubbleTextCell *)cell dismissPopup];
+}
+
+-(void) dismissMessagesPopups {
+ for (UITableViewCell *cell in self.tableView.visibleCells) {
+ if (![[cell reuseIdentifier] isEqualToString:NSStringFromClass(UIChatNotifiedEventCell.class)])
+ [(UIChatBubbleTextCell *)cell dismissPopup];
+ }
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@@ -301,6 +344,8 @@ static const int BASIC_EVENT_LIST=15;
[cell setChatRoomDelegate:_chatRoomDelegate];
[super accessoryForCell:cell atPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.tableController = self;
+ cell.popupMenuAllowed = true;
return cell;
} else {
kCellId = NSStringFromClass(UIChatNotifiedEventCell.class);
@@ -393,6 +438,8 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f;
LinphoneEventLog *event = [[eventList objectAtIndex:indexPath.row] pointerValue];
if (linphone_event_log_get_chat_message(event)) {
linphone_chat_room_delete_message(_chatRoom, linphone_event_log_get_chat_message(event));
+ } else {
+ linphone_event_log_delete_from_database(event);
}
NSInteger index = indexPath.row + _currentIndex + (totalEventList.count - eventList.count);
if (index < totalEventList.count)
diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h
index bc4b00e93..7c76cb286 100644
--- a/Classes/ChatConversationView.h
+++ b/Classes/ChatConversationView.h
@@ -32,7 +32,8 @@
#import "UIImageViewDeletable.h"
#import "UIConfirmationDialog.h"
#import "UIInterfaceStyleButton.h"
-
+#import "linphoneapp-Swift.h"
+#import "UIChatReplyBubbleView.h"
#include "linphone/linphonecore.h"
@@ -111,7 +112,15 @@
@property LinphoneRecorder *voiceRecorder;
@property LinphonePlayer *sharedVoicePlayer;
@property BOOL showVoiceRecorderView;
-@property BOOL preservePendingRecording;
+@property BOOL preservePendingActions;
+
+// Reply
+@property (weak, nonatomic) IBOutlet UIView *replyView;
+@property BOOL showReplyView;
+@property UIChatReplyBubbleView *replyBubble;
+
+// Forward
+@property LinphoneChatMessage *pendingForwardMessage;
+ (void)markAsRead:(LinphoneChatRoom *)chatRoom;
@@ -149,4 +158,6 @@
-(void) stopSharedPlayer;
-(BOOL) sharedPlayedIsPlaying:(const char *)path;
+-(void) initiateReplyViewForMessage:(LinphoneChatMessage *)message;
+
@end
diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m
index d7e4d4479..0a4517f9b 100644
--- a/Classes/ChatConversationView.m
+++ b/Classes/ChatConversationView.m
@@ -137,7 +137,7 @@ static UICompositeViewDescription *compositeDescription = nil;
if (compositeDescription == nil) {
compositeDescription = [[UICompositeViewDescription alloc] init:self.class
statusBar:StatusBarView.class
- tabBar:TabBarView.class
+ tabBar:nil
sideMenu:SideMenuView.class
fullscreen:false
isLeftFragment:NO
@@ -258,7 +258,7 @@ static UICompositeViewDescription *compositeDescription = nil;
CGRect tableViewFrame = [_tableController.tableView frame];
tableViewFrame.size.height -= 120;
[_tableController.tableView setFrame:tableViewFrame];
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
}
completion:nil];
}
@@ -269,17 +269,26 @@ static UICompositeViewDescription *compositeDescription = nil;
popupFrame.size.height = 44 * [_popupMenu numberOfRowsInSection:0];
_popupMenu.frame = popupFrame;
- // Voice recording
+ // Voice recording & Replies
_vrView.hidden = true;
- _preservePendingRecording = false;
_toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
+ _replyView.hidden = true;
+ _preservePendingActions = false;
+
+ _toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
}
- (void)viewWillDisappear:(BOOL)animated {
- if (!_preservePendingRecording)
+ if (!_preservePendingActions)
[self cancelVoiceRecording];
+
+ if (!_preservePendingActions)
+ [self closePendingReply];
+
+
+
else if (_isVoiceRecording)
[self stopVoiceRecording];
@@ -330,10 +339,14 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark -
- (void)applicationWillEnterBackground{
- if (!_preservePendingRecording)
+ if (!_preservePendingActions)
[self cancelVoiceRecording];
else if (_isVoiceRecording)
[self stopVoiceRecording];
+ if (!_preservePendingActions)
+ [self closePendingReply];
+ [self stopAllPlays];
+
}
@@ -393,6 +406,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[self setupPopupMenu];
_ephemeralndicator.hidden = !linphone_chat_room_ephemeral_enabled(_chatRoom);
}
+ [self handlePendingTransferIfAny];
}
@@ -420,7 +434,7 @@ static UICompositeViewDescription *compositeDescription = nil;
}
-(NSData *) nsDataRead {
- NSString* groupName = [NSString stringWithFormat:@"group.%@.linphoneExtension",[[NSBundle mainBundle] bundleIdentifier]];
+ NSString* groupName = @"group.com.clavys.frogtrust.store";
NSString *path =[[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:groupName] path];
NSString *fullCacheFilePathPath = [NSString stringWithFormat:@"%@/%@",path,@"nsData"];
return[NSData dataWithContentsOfFile:fullCacheFilePathPath];
@@ -428,7 +442,8 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)shareFile {
- NSString* groupName = [NSString stringWithFormat:@"group.%@.linphoneExtension",[[NSBundle mainBundle] bundleIdentifier]];
+ NSString* groupName = @"group.com.clavys.frogtrust.store";
+
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
NSDictionary *dict = [defaults valueForKey:@"photoData"];
@@ -505,13 +520,13 @@ static UICompositeViewDescription *compositeDescription = nil;
}
}
-- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl andVoiceContent:(LinphoneContent *)voiceContent {
+- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl rootMessage:(LinphoneChatMessage *)rootMessage {
if (_chatRoom == NULL) {
LOGW(@"Cannot send message: No chatroom");
return FALSE;
}
- LinphoneChatMessage *msg = linphone_chat_room_create_empty_message(_chatRoom);
+ LinphoneChatMessage *msg = rootMessage;
if (message && message.length > 0)
linphone_chat_message_add_utf8_text_content(msg, message.UTF8String);
@@ -519,11 +534,6 @@ static UICompositeViewDescription *compositeDescription = nil;
linphone_chat_message_set_external_body_url(msg, [[externalUrl absoluteString] UTF8String]);
}
- // Voice recording
-
- if (voiceContent)
- linphone_chat_message_add_content(msg, voiceContent);
-
// we must ref & unref message because in case of error, it will be destroy otherwise
linphone_chat_message_send(msg);
@@ -566,15 +576,15 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)confirmShare:(NSData *)data url:(NSString *)url fileName:(NSString *)fileName {
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:@""];
dispatch_async(dispatch_get_main_queue(), ^{
- [sheet addButtonWithTitle:NSLocalizedString(@"Send to this friend", nil)
+ [sheet addButtonWithTitle:NSLocalizedString(@"send to this conversation", nil)
block:^() {
if (![[self.messageField text] isEqualToString:@""]) {
- [self sendMessageInMessageFieldWithVoiceContent:nil];
+ [self sendMessageInMessageField:linphone_chat_room_create_empty_message(_chatRoom)];
}
if (url)
- [self sendMessage:url withExterlBodyUrl:nil andVoiceContent:nil];
+ [self sendMessage:url withExterlBodyUrl:nil rootMessage:linphone_chat_room_create_empty_message(_chatRoom)];
else
- [self startFileUpload:data withName:fileName];
+ [self startFileUpload:data withName:fileName rootMessage:linphone_chat_room_create_empty_message(_chatRoom)];
}];
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
@@ -657,8 +667,8 @@ static UICompositeViewDescription *compositeDescription = nil;
_addressLabel.frame = frame;
}
-- (void)sendMessageInMessageFieldWithVoiceContent:(LinphoneContent *)voiceContent {
- if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil andVoiceContent:voiceContent]) {
+- (void)sendMessageInMessageField:(LinphoneChatMessage *)rootMessage {
+ if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil rootMessage:rootMessage]) {
scrollOnGrowingEnabled = FALSE;
[_messageField setText:@""];
scrollOnGrowingEnabled = TRUE;
@@ -714,7 +724,7 @@ static UICompositeViewDescription *compositeDescription = nil;
CGRect tableRect = [_tableController.view frame];
tableRect.size.height -= diff;
[_tableController.view setFrame:tableRect];
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
// if we're showing the compose message, update it position
if (![_composeLabel isHidden]) {
@@ -739,40 +749,48 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onSendClick:(id)event {
- LinphoneContent *voiceContent = nil;
+
+ if (!linphone_core_is_network_reachable(LC)) {
+ //[PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
+ //return;
+ }
+
+ LinphoneChatMessage *rootMessage = _replyBubble ? linphone_chat_room_create_reply_message(_chatRoom, _replyBubble.message) : linphone_chat_room_create_empty_message(_chatRoom);
+
+ if (_replyBubble) {
+ [self closePendingReply];
+ }
+
if (_isPendingVoiceRecord && _voiceRecorder && linphone_recorder_get_file(_voiceRecorder)) {
- voiceContent = linphone_recorder_create_content(_voiceRecorder);
+ LinphoneContent * voiceContent = linphone_recorder_create_content(_voiceRecorder);
_isPendingVoiceRecord = false;
[self cancelVoiceRecording];
[self stopVoiceRecordPlayer];
+ linphone_chat_message_add_content(rootMessage, voiceContent);
}
- if (!linphone_core_is_network_reachable(LC)) {
- [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
- return;
- }
if ([_fileContext count] > 0) {
if (linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesConference) {
- [self startMultiFilesUploadWithVoiceContent:voiceContent];
+ [self startMultiFilesUpload:rootMessage];
} else {
int i = 0;
for (i = 0; i < [_fileContext count]-1; ++i) {
- [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL voiceContent:voiceContent];
+ [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL rootMessage:rootMessage];
}
if (isOneToOne) {
- [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL voiceContent:voiceContent];
+ [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:NULL rootMessage:rootMessage];
if (![[self.messageField text] isEqualToString:@""]) {
- [self sendMessage:[_messageField text] withExterlBodyUrl:nil andVoiceContent:voiceContent];
+ [self sendMessage:[_messageField text] withExterlBodyUrl:nil rootMessage:rootMessage];
}
} else {
- [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:[self.messageField text] voiceContent:voiceContent];
+ [self startUploadData:[_fileContext.datasArray objectAtIndex:i] withType:[_fileContext.typesArray objectAtIndex:i] withName:[_fileContext.namesArray objectAtIndex:i] andMessage:[self.messageField text] rootMessage:rootMessage];
}
}
[self clearMessageView];
return;
}
- [self sendMessageInMessageFieldWithVoiceContent:voiceContent];
+ [self sendMessageInMessageField:rootMessage];
}
- (IBAction)onListTap:(id)sender {
@@ -833,7 +851,7 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onPictureClick:(id)event {
- _preservePendingRecording = true;
+ _preservePendingActions = true;
[_messageField resignFirstResponder];
[ImagePickerView SelectImageFromDevice:self atPosition:_pictureButton inView:self.view withDocumentMenuDelegate:self];
@@ -867,15 +885,15 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark ChatRoomDelegate
-- (BOOL)startMultiFilesUploadWithVoiceContent:(LinphoneContent *)voiceContent {
+- (BOOL)startMultiFilesUpload:(LinphoneChatMessage *)rootMessage {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
[fileTransfer setText:[self.messageField text]];
- [fileTransfer uploadFileContent:_fileContext forChatRoom:_chatRoom andVoiceContent:voiceContent];
+ [fileTransfer uploadFileContent:_fileContext forChatRoom:_chatRoom rootMessage:rootMessage];
[_tableController scrollToBottom:true];
return TRUE;
}
-- (BOOL)startUploadData:(NSData *)data withType:(NSString*)type withName:(NSString *)name andMessage:(NSString *)message voiceContent:(LinphoneContent *)voiceContent {
+- (BOOL)startUploadData:(NSData *)data withType:(NSString*)type withName:(NSString *)name andMessage:(NSString *)message rootMessage:(LinphoneChatMessage *)rootMessage {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
if (message)
[fileTransfer setText:message];
@@ -885,38 +903,38 @@ static UICompositeViewDescription *compositeDescription = nil;
} else if ([type isEqualToString:@"image"]) {
key = @"localimage";
}
- [fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key voiceContent:voiceContent];
+ [fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key rootMessage:rootMessage];
[_tableController scrollToBottom:true];
return TRUE;
}
-- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name {
+- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name rootMessage:(LinphoneChatMessage *)rootMessage {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
- [fileTransfer uploadFile:data forChatRoom:_chatRoom withName:name];
+ [fileTransfer uploadFile:data forChatRoom:_chatRoom withName:name rootMessage:rootMessage];
[_tableController scrollToBottom:true];
return TRUE;
}
-- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent {
+- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message rootMessage:(LinphoneChatMessage *)rootMessage {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
if (message)
[fileTransfer setText:message];
- [fileTransfer uploadFileContent:newFileContext forChatRoom:_chatRoom andVoiceContent:voiceContent];
+ [fileTransfer uploadFileContent:newFileContext forChatRoom:_chatRoom rootMessage:rootMessage];
[_tableController scrollToBottom:true];
return TRUE;
}
-- (BOOL)resendFile: (NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message voiceContent:(LinphoneContent *)voiceContent{
+- (BOOL)resendFile: (NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message rootMessage:(LinphoneChatMessage *)rootMessage{
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
if (message)
[fileTransfer setText:message];
- [fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key voiceContent:voiceContent];
+ [fileTransfer uploadData:data forChatRoom:_chatRoom type:type subtype:type name:name key:key rootMessage:rootMessage];
[_tableController scrollToBottom:true];
return TRUE;
}
-- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url voiceContent:(LinphoneContent *)voiceContent {
- [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] andVoiceContent:voiceContent];
+- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url rootMessage:(LinphoneChatMessage *)rootMessage {
+ [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] rootMessage:rootMessage];
}
#pragma mark ImagePickerDelegate
@@ -1171,8 +1189,10 @@ static UICompositeViewDescription *compositeDescription = nil;
[_tableController.tableView setFrame:tableViewFrame];
}
if (_showVoiceRecorderView)
- _vrView.hidden = true;
- [self updateFramesInclRecordingView];
+ _vrView.hidden = true; // force recalculate
+ if (_showReplyView)
+ _replyView.hidden = true; // force recalculate
+ [self updateFramesInclRecordingAndReplyView];
}
completion:^(BOOL finished){
@@ -1257,8 +1277,10 @@ static UICompositeViewDescription *compositeDescription = nil;
}
}
if (_showVoiceRecorderView)
- _vrView.hidden = true;
- [self updateFramesInclRecordingView];
+ _vrView.hidden = true; // force recalculate
+ if (_showReplyView)
+ _replyView.hidden = true; // force recalculate
+ [self updateFramesInclRecordingAndReplyView];
}
@@ -1497,7 +1519,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
CGRect tableViewFrame = [_tableController.tableView frame];
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
[_tableController.tableView setFrame:tableViewFrame];
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
}
completion:nil];
[self setSendButtonState];
@@ -1511,7 +1533,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
CGRect tableViewFrame = [_tableController.tableView frame];
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
[_tableController.tableView setFrame:tableViewFrame];
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
[_imagesCollectionView reloadData];
}
}
@@ -1705,13 +1727,12 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
LinphoneRecorderParams *p = linphone_core_create_recorder_params(LC);
linphone_recorder_params_set_file_format(p, LinphoneRecorderFileFormatWav);
_voiceRecorder = linphone_core_create_recorder(LC, p);
- [CallManager.instance activateAudioSession];
}
-(void) cancelVoiceRecording {
_showVoiceRecorderView = false;
_toggleRecord.selected = false;
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
_isPendingVoiceRecord = false;
_isVoiceRecording = false;
if (_voiceRecorder && linphone_recorder_get_state(_voiceRecorder) != LinphoneRecorderClosed) {
@@ -1748,13 +1769,13 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
if (!_voiceRecorder)
[self createVoiceRecorder];
-
+ [CallManager.instance activateAudioSession];
_toggleRecord.selected = true;
[_vrPlayButton setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
_showVoiceRecorderView = true;
- [self updateFramesInclRecordingView];
+ [self updateFramesInclRecordingAndReplyView];
_isVoiceRecording = true;
_vrWaveMaskPlayer.frame = CGRectZero;
@@ -1850,9 +1871,6 @@ void on_shared_player_eof_reached(LinphonePlayer *p) {
NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:currentPlayedFile]};
[NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerEOF object:nil userInfo:userInfo];
}
-
-// ChatConversationView *view = (__bridge ChatConversationView *)linphone_player_cbs_get_user_data(linphone_player_get_current_callbacks(p));
-// [view stopVoiceRecordPlayer];
}
// Playback of new recordings
@@ -1907,20 +1925,35 @@ void on_shared_player_eof_reached(LinphonePlayer *p) {
return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60000, (valueMs % 60000) / 1000 ];
}
--(void) updateFramesInclRecordingView { // place below the messages table.
- BOOL showHide = _showVoiceRecorderView != !_vrView.hidden;
- if (showHide)
+-(void) updateFramesInclRecordingAndReplyView { // place below the messages table.
+ BOOL showHideVoice = _showVoiceRecorderView != !_vrView.hidden;
+ if (showHideVoice)
_vrView.hidden = !_showVoiceRecorderView;
CGRect vrFrame = _vrView.frame;
CGRect tableFrame = _tableController.tableView.frame;
- if (showHide) {
+ if (showHideVoice) {
tableFrame.size.height = _showVoiceRecorderView ? tableFrame.size.height - vrFrame.size.height : tableFrame.size.height + vrFrame.size.height;
_tableController.tableView.frame = tableFrame;
[_tableController.tableView reloadData];
}
vrFrame.origin.y = tableFrame.origin.y+tableFrame.size.height;
_vrView.frame = vrFrame;
+
+ BOOL showHideReply = _showReplyView != !_replyView.hidden;
+ if (showHideReply)
+ _replyView.hidden = !_showReplyView;
+
+ CGRect repFrame = _replyView.frame;
+ tableFrame = _tableController.tableView.frame;
+ if (showHideReply) {
+ tableFrame.size.height = _showReplyView ? tableFrame.size.height - repFrame.size.height : tableFrame.size.height + repFrame.size.height;
+ _tableController.tableView.frame = tableFrame;
+ [_tableController.tableView reloadData];
+ }
+ repFrame.origin.y = _showVoiceRecorderView ? vrFrame.origin.y + vrFrame.size.height : tableFrame.origin.y+tableFrame.size.height;
+ _replyView.frame = repFrame;
+
}
-(void) stopAllPlays {
@@ -1937,5 +1970,48 @@ void on_shared_player_eof_reached(LinphonePlayer *p) {
}
+// Reply
+
+-(void) closePendingReply {
+ if (_replyBubble != nil) {
+ _showReplyView = false;
+ [_replyBubble.view removeFromSuperview];
+ [self updateFramesInclRecordingAndReplyView];
+ _replyBubble = nil;
+ }
+}
+
+-(void) initiateReplyViewForMessage:(LinphoneChatMessage *)message {
+ if (_replyBubble != nil)
+ [self closePendingReply];
+ _replyBubble = [[UIChatReplyBubbleView alloc] initWithNibName:@"UIChatReplyBubbleView" bundle:nil];
+ [self addChildViewController:_replyBubble];
+ [_replyView addSubview:_replyBubble.view];
+ [_replyBubble didMoveToParentViewController:self];
+ [_replyBubble configureForMessage:message withDimissBlock:^{
+ [self closePendingReply];
+ } hideDismiss:false withClickBlock:^{}];
+ _showReplyView = true;
+ [self updateFramesInclRecordingAndReplyView];
+ [self.tableController scrollToMessage:message];
+}
+
+-(void) handlePendingTransferIfAny {
+ if (self.pendingForwardMessage) {
+ LinphoneChatMessage *message = self.pendingForwardMessage;
+ self.pendingForwardMessage = nil;
+ UIConfirmationDialog *d = [UIConfirmationDialog ShowWithMessage:NSLocalizedString(@"Transfer this message to this conversation ?",nil)
+ cancelMessage:nil
+ confirmMessage:NSLocalizedString(@"TRANSFER",nil)
+ onCancelClick:^() {}
+ onConfirmationClick:^() {
+ linphone_chat_message_send(linphone_chat_room_create_forward_message(_chatRoom, message));
+
+ }];
+ d.forwardImage.hidden = NO;
+ [d setSpecialColor];
+ }
+}
+
@end
diff --git a/Classes/ChatsListTableView.h b/Classes/ChatsListTableView.h
index 30a054770..3c0593ebc 100644
--- a/Classes/ChatsListTableView.h
+++ b/Classes/ChatsListTableView.h
@@ -28,6 +28,7 @@
@property (weak, nonatomic) IBOutlet UIView *waitView;
@property bctbx_list_t *data;
+
- (void)loadData;
- (void)markCellAsRead:(LinphoneChatRoom *)chatRoom;
@end
diff --git a/Classes/ChatsListTableView.m b/Classes/ChatsListTableView.m
index ae6ad0196..935fadcd7 100644
--- a/Classes/ChatsListTableView.m
+++ b/Classes/ChatsListTableView.m
@@ -160,6 +160,13 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
[cell setChatRoom:(LinphoneChatRoom *)bctbx_list_nth_data(_data, (int)[indexPath row])];
[super accessoryForCell:cell atPath:indexPath];
+ BOOL forwardMode = VIEW(ChatConversationView).pendingForwardMessage != nil;
+ cell.forwardIcon.hidden = !forwardMode;
+ if (forwardMode) {
+ cell.ephemeral.hidden = true;
+ cell.imdmIcon.hidden = true;
+ }
+
return cell;
}
diff --git a/Classes/ChatsListView.h b/Classes/ChatsListView.h
index 8525e4aac..c0046957d 100644
--- a/Classes/ChatsListView.h
+++ b/Classes/ChatsListView.h
@@ -34,6 +34,9 @@
@property(weak, nonatomic) IBOutlet UIBackToCallButton *backToCallButton;
@property (weak, nonatomic) IBOutlet UIView *waitView;
@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleSelectionButton;
+@property (weak, nonatomic) IBOutlet UILabel *forwardTitle;
+@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *cancelForwardButton;
+
- (IBAction)onAddGroupChatClick:(id)event;
- (IBAction)onAddClick:(id)event;
diff --git a/Classes/ChatsListView.m b/Classes/ChatsListView.m
index a3acc5b7c..e80421b5f 100644
--- a/Classes/ChatsListView.m
+++ b/Classes/ChatsListView.m
@@ -53,8 +53,28 @@
[button addTarget:self action:@selector(crashButtonTapped:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];*/
+
+ BOOL forwardMode = VIEW(ChatConversationView).pendingForwardMessage != nil;
+
+ _tableController.editButton.hidden = forwardMode;
+ _forwardTitle.text = NSLocalizedString(@"Select a discussion or create a new one",nil);
+ _forwardTitle.hidden = !forwardMode;
+ _cancelForwardButton.hidden = !forwardMode;
+
+ _tableController.tableView.frame = CGRectMake(0, 66 + (forwardMode ? _forwardTitle.frame.size.height : 0), _tableController.tableView.frame.size.width, self.view.frame.size.height - 66 - ( forwardMode ? _forwardTitle.frame.size.height : 0 ));
+ _addButton.frame = CGRectMake(forwardMode ? 82 : 0 , _addButton.frame.origin.y, _addButton.frame.size.width, _addButton.frame.size.height);
+ _addGroupChatButton.frame = CGRectMake(forwardMode ? 164 : 82 , _addGroupChatButton.frame.origin.y, _addGroupChatButton.frame.size.width, _addGroupChatButton.frame.size.height);
+
}
+
+
+- (void)ephemeralDeleted:(NSNotification *)notif {
+ //LinphoneChatRoom *r =[[notif.userInfo objectForKey:@"room"] intValue];
+ [self.tableController loadData];
+}
+
+
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
@@ -150,8 +170,9 @@ static UICompositeViewDescription *compositeDescription = nil;
assert(NO);
}
-- (void)ephemeralDeleted:(NSNotification *)notif {
- [self.tableController loadData];
+- (IBAction)onCancelForwardClicked:(id)sender {
+ VIEW(ChatConversationView).pendingForwardMessage = nil;
+ [PhoneMainView.instance popCurrentView];
}
@end
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
index b987f08b4..8cae658dc 100644
--- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
@@ -29,9 +29,10 @@
+
-
-
+
+
@@ -65,163 +66,179 @@
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
@@ -229,21 +246,11 @@
-
-
-
-
-
-
-
-
-
-
@@ -254,6 +261,7 @@
+
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib
index 481e4541a..d19e81d0c 100644
--- a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib
@@ -18,6 +18,8 @@
+
+
@@ -41,6 +43,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -80,5 +93,6 @@
+
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatCell.xib
index 67257c9d5..9ed041472 100644
--- a/Classes/LinphoneUI/Base.lproj/UIChatCell.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIChatCell.xib
@@ -14,6 +14,7 @@
+
@@ -64,10 +65,6 @@
-
-
-
-
@@ -90,6 +87,14 @@
+
+
+
+
+
+
+
+
@@ -101,6 +106,7 @@
+
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatReplyBubbleView.xib b/Classes/LinphoneUI/Base.lproj/UIChatReplyBubbleView.xib
new file mode 100644
index 000000000..4a657bdc5
--- /dev/null
+++ b/Classes/LinphoneUI/Base.lproj/UIChatReplyBubbleView.xib
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Classes/LinphoneUI/Base.lproj/UIConfirmationDialog.xib b/Classes/LinphoneUI/Base.lproj/UIConfirmationDialog.xib
index 3bc5b8c8e..eb265f061 100644
--- a/Classes/LinphoneUI/Base.lproj/UIConfirmationDialog.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIConfirmationDialog.xib
@@ -1,11 +1,9 @@
-
-
-
-
+
+
-
+
@@ -15,6 +13,7 @@
+
@@ -25,26 +24,26 @@
-
+
-
+
-
+
-
+
-
+
@@ -56,11 +55,11 @@
-
+
-
+
@@ -69,7 +68,7 @@
-
+
@@ -78,7 +77,7 @@
-
+
@@ -90,22 +89,27 @@
+
+
+
+
-
+
-
-
+
+
-
+
+
diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.h b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
index c1530c413..49555feaa 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.h
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
@@ -41,7 +41,6 @@
@property(strong, nonatomic) IBOutlet UITapGestureRecognizer *imageGestureRecognizer;
@property (weak, nonatomic) IBOutlet UIButton *fileButton;
@property (weak, nonatomic) IBOutlet UIView *fileView;
-@property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *plusLongGestureRecognizer;
@property(strong, nonatomic) NSMutableArray *contentViews;
// Video recordings
@@ -61,10 +60,8 @@
- (IBAction)onDownloadClick:(id)event;
- (IBAction)onImageClick:(id)event;
- (IBAction)onCancelClick:(id)sender;
-- (IBAction)onResendClick:(id)event;
- (IBAction)onPlayClick:(id)sender;
- (IBAction)onFileClick:(id)sender;
-- (IBAction)onPlusClick:(id)sender;
@end
diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m
index 43474ea1a..f94ea00d7 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m
@@ -61,8 +61,13 @@
assetIsLoaded = FALSE;
self.contentView.userInteractionEnabled = NO;
_contentViews = [[NSMutableArray alloc] init];
- self.vrWaveMaskPlayback.layer.cornerRadius = 10.0f;
- self.vrWaveMaskPlayback.layer.masksToBounds = YES;
+
+
+ self.vrView.layer.cornerRadius = 30.0f;
+ self.vrView.layer.masksToBounds = YES;
+ [self.innerView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onPopupMenuPressed)]];
+ self.messageText.userInteractionEnabled = false;
+
}
return self;
}
@@ -82,7 +87,6 @@
- (void)setChatMessage:(LinphoneChatMessage *)amessage {
_imageGestureRecognizer.enabled = NO;
- _plusLongGestureRecognizer.enabled = NO;
_messageImageView.image = nil;
_finalImage.image = nil;
_finalImage.hidden = TRUE;
@@ -115,7 +119,6 @@
_messageImageView.hidden = YES;
_finalImage.hidden = NO;
_fileView.hidden = YES;
- _plusLongGestureRecognizer.enabled = YES;
[self layoutSubviews];
});
}
@@ -151,7 +154,6 @@
[_messageImageView stopLoading];
_messageImageView.hidden = YES;
_imageGestureRecognizer.enabled = YES;
- _plusLongGestureRecognizer.enabled = YES;
_finalImage.hidden = NO;
[self layoutSubviews];
});
@@ -499,25 +501,6 @@
}];
}
-- (IBAction)onPlusClick:(id)sender {
- UILongPressGestureRecognizer *gesture = (UILongPressGestureRecognizer *)sender;
- if (gesture.state != UIGestureRecognizerStateBegan) {
- // allow only one click once time
- return;
- }
- DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:@""];
- dispatch_async(dispatch_get_main_queue(), ^{
- [sheet addButtonWithTitle:NSLocalizedString(@"Save to Gallery", nil)
- block:^() {
- LinphoneContent *content = linphone_chat_message_get_file_transfer_information(self.message);
- NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
- [ChatConversationView writeMediaToGallery:name fileType:[NSString stringWithUTF8String:linphone_content_get_type(content)?:""]];
- }];
-
- [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
- [sheet showInView:PhoneMainView.instance.view];
- });
-}
- (IBAction)onFileClick:(id)sender {
ChatConversationView *view = VIEW(ChatConversationView);
@@ -545,16 +528,6 @@
}
}
-- (void)onResendClick:(id)event {
- if (_downloadButton.hidden == NO) {
- // if download button is displayed, click on it
- [self onDownloadClick:event];
- } else if (_cancelButton.hidden == NO) {
- [self onCancelClick:event];
- } else {
- [super onResend];
- }
-}
- (IBAction)onImageClick:(id)event {
if (_finalImage.tag == FILE_ICON_TAG) {
@@ -563,7 +536,7 @@
}
LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
if (state == LinphoneChatMessageStateNotDelivered) {
- [self onResendClick:event];
+ return;
} else {
if (![_messageImageView isLoading]) {
ImageView *view = VIEW(ImageView);
@@ -768,6 +741,14 @@
} else {
_vrView.hidden = YES;
}
+
+ CGRect r = super.photoCellContentView.frame;
+ r.origin.y = linphone_chat_message_is_reply(super.message) ? super.replyView.view.frame.origin.y + super.replyView.view.frame.size.height + 10 : 7 ;
+ super.photoCellContentView.frame = r;
+
+ r = super.photoCellContentView.frame;
+ r.origin.y = linphone_chat_message_is_forward(super.message) ? super.contactDateLabel.frame.origin.y + super.contactDateLabel.frame.size.height + 3 : r.origin.y;
+ super.photoCellContentView.frame = r;
self.messageText.frame = textFrame;
}
@@ -841,6 +822,14 @@ static AVAudioPlayer* utilityPlayer;
}
}
+
+// menu
+
+-(void) onPopupMenuPressed {
+ [super onPopupMenuPressed];
+}
+
+
@end
diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h
index e90bf6b44..fe729b670 100644
--- a/Classes/LinphoneUI/UIChatBubbleTextCell.h
+++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h
@@ -22,6 +22,7 @@
#import "UITextViewNoDefine.h"
#import "ChatConversationTableView.h"
#import "UIRoundedImageView.h"
+#import "UIChatReplyBubbleView.h"
#define CELL_IMAGE_X_MARGIN 100
#define IMAGE_DEFAULT_WIDTH 120
@@ -30,7 +31,7 @@
#define VOICE_RECORDING_PLAYER_WIDTH 300
-@interface UIChatBubbleTextCell : UITableViewCell
+@interface UIChatBubbleTextCell : UITableViewCell
@property(readonly, nonatomic) LinphoneEventLog *event;
@property(readonly, nonatomic) LinphoneChatMessage *message;
@@ -50,6 +51,22 @@
@property (weak, nonatomic) IBOutlet UIView *innerView;
@property (weak, nonatomic) IBOutlet UILabel *ephemeralTime;
@property (weak, nonatomic) IBOutlet UIImageView *ephemeralIcon;
+@property ChatConversationTableView *tableController;
+@property BOOL popupMenuAllowed;
+
+// Message popup menu
+@property UITableView *popupMenu;
+@property NSMutableArray *messageActionsTitles;
+@property NSMutableArray *messageActionsIcons;
+@property NSMutableArray *messageActionsBlocks;
+
+// Message reply/transfer
+@property UIChatReplyBubbleView *replyView;
+@property UILabel *replyOrForward;
+@property (weak, nonatomic) IBOutlet UIImageView *replyTransferIcon;
+@property (weak, nonatomic) IBOutlet UILabel *replyTransferLabel;
+@property (weak, nonatomic) IBOutlet UIView *photoCellContentView;
+
@property(nonatomic) BOOL isFirst;
@property(nonatomic) BOOL isLast;
@@ -67,8 +84,6 @@
- (void)clearEncryptedFiles;
- (void)onDelete;
-- (void)onResend;
-- (void)onLime;
- (void)update;
- (void)displayImdmStatus:(LinphoneChatMessageState)state;
@@ -77,5 +92,6 @@
+ (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
+ (NSString *)ContactDateForChat:(LinphoneChatMessage *)message;
+(LinphoneContent *) voiceContent:(LinphoneChatMessage *)message;
-
+-(void) onPopupMenuPressed;
+-(void) dismissPopup;
@end
diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m
index 8f8fed31b..ef170ae1b 100644
--- a/Classes/LinphoneUI/UIChatBubbleTextCell.m
+++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m
@@ -20,6 +20,7 @@
#import "UIChatBubbleTextCell.h"
#import "LinphoneManager.h"
#import "PhoneMainView.h"
+#import "Utils.h"
#import
#import
@@ -28,6 +29,8 @@
#pragma mark - Lifecycle Functions
+
+
- (id)initWithIdentifier:(NSString *)identifier {
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
if ([identifier isEqualToString:NSStringFromClass(self.class)]) {
@@ -40,22 +43,11 @@
[self addSubview:sub];
}
}
+
+
+ [_innerView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(onPopupMenuPressed)]];
+ _messageText.userInteractionEnabled = false;
- UITapGestureRecognizer *limeRecognizer =
- [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onLime)];
- limeRecognizer.numberOfTapsRequired = 1;
- //[_LIMEKO addGestureRecognizer:limeRecognizer];
- //_LIMEKO.userInteractionEnabled = YES;
- UITapGestureRecognizer *resendRecognizer =
- [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)];
- resendRecognizer.numberOfTapsRequired = 1;
- [_bubbleView addGestureRecognizer:resendRecognizer];
- _imdmIcon.userInteractionEnabled = YES;
- UITapGestureRecognizer *resendRecognizer2 =
- [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResend)];
- resendRecognizer2.numberOfTapsRequired = 1;
- //[_imdmLabel addGestureRecognizer:resendRecognizer2];
- //_imdmLabel.userInteractionEnabled = YES;
self.contentView.userInteractionEnabled = NO;
return self;
@@ -205,11 +197,12 @@
_avatarImage.hidden = !_isFirst;
}
+
// Not use [UIImage imageNamed], it takes too much time
- NSString *imageName = outgoing ? @"color_A.png" : @"color_D.png";
- _backgroundColorImage.image =
- [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] bundlePath],imageName]];
-
+ _backgroundColorImage.image = nil;
+ _backgroundColorImage.backgroundColor = outgoing ? [UIColor color:@"A"] : [UIColor color:@"D"];
+
+
// set maskedCorners
if (@available(iOS 11.0, *)) {
_backgroundColorImage.layer.cornerRadius = 10;
@@ -255,6 +248,7 @@
frame.origin.y = _isFirst ? 20 : 0;
_innerView.frame = frame;
+
[_messageText setAccessibilityLabel:outgoing ? @"Outgoing message" : @"Incoming message"];
if (outgoing &&
(state == LinphoneChatMessageStateDeliveredToUser || state == LinphoneChatMessageStateDisplayed ||
@@ -262,6 +256,23 @@
[self displayImdmStatus:state];
} else
[self displayImdmStatus:LinphoneChatMessageStateInProgress];
+
+ if (linphone_chat_message_is_reply(_message)) {
+ if (_replyView == nil) {
+ _replyView = [[UIChatReplyBubbleView alloc] initWithNibName:@"UIChatReplyBubbleView" bundle:nil];
+ [self.innerView addSubview:_replyView.view];
+ }
+ _replyView.view.hidden = false;
+ CGRect replyFrame = CGRectMake(_contactDateLabel.frame.origin.x, _contactDateLabel.frame.origin.y+_contactDateLabel.frame.size.height,self.contactDateLabel.frame.size.width, REPLY_CHAT_BUBBLE_HEIGHT);
+ _replyView.view.frame = replyFrame;
+ [_replyView configureForMessage:linphone_chat_message_get_reply_message(_message) withDimissBlock:^{} hideDismiss:true withClickBlock:^{
+ [_tableController scrollToMessage:linphone_chat_message_get_reply_message(_message)];
+ }];
+ } else {
+ if (_replyView)
+ _replyView.view.hidden = true;
+ }
+
}
- (void)setEditing:(BOOL)editing {
@@ -269,7 +280,6 @@
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
- _messageText.userInteractionEnabled = !editing;
_resendRecognizer.enabled = !editing;
}
@@ -300,94 +310,6 @@
}
}
-- (void)onLime {
- /*if (!_LIMEKO.hidden)
- [self displayLIMEWarning];*/
-}
-
-- (void)onResend {
-
- if (!linphone_core_is_network_reachable(LC)) {
- [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
- //return;
- }
-
- if (_message == nil || !linphone_chat_message_is_outgoing(_message))
- return;
-
- LinphoneChatMessageState state = linphone_chat_message_get_state(_message);
- if (state != LinphoneChatMessageStateNotDelivered && state != LinphoneChatMessageStateFileTransferError)
- return;
-
- const bctbx_list_t *contents = linphone_chat_message_get_contents(_message);
- LinphoneContent *voiceContent = [UIChatBubbleTextCell voiceContent:_message];
- size_t contentCount = bctbx_list_size(contents);
- if (voiceContent)
- contentCount--;
-
- BOOL multiParts = ((linphone_chat_message_get_text_content(_message) != NULL) ? contentCount > 2 : contentCount > 1);
-
- if (multiParts) {
- FileContext *newfileContext = [[FileContext alloc] init];
- [newfileContext clear];
- NSMutableDictionary *encrptedFilePaths = encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:_message];
- int i;
- const bctbx_list_t *it;
- for (it = contents, i=0; it != NULL; it=bctbx_list_next(it)){
- LinphoneContent *content = (LinphoneContent *)it->data;
- if (linphone_content_is_voice_recording(content)) {
- continue;
- }
- if (linphone_content_is_file_transfer(content) || linphone_content_is_file(content)){
- NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
- NSString *filePath = [encrptedFilePaths valueForKey:name];
- if (filePath == NULL) {
- filePath = [LinphoneManager validFilePath:name];
- }
- [newfileContext addObject:[NSData dataWithContentsOfFile:filePath] name:name type:[NSString stringWithUTF8String:linphone_content_get_type(content)]];
- }
- }
- [self onDelete];
- dispatch_async(dispatch_get_main_queue(), ^ {
- const char *text = linphone_chat_message_get_text_content(_message);
- [_chatRoomDelegate resendMultiFiles:newfileContext message: text? [NSString stringWithUTF8String:text]: NULL voiceContent:voiceContent];
- });
- return;
- }
- if (!voiceContent && contentCount == 1 && linphone_chat_message_get_file_transfer_information(_message) != NULL) {
- NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message];
- NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message];
- NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message];
- NSString *filePath = [LinphoneManager getMessageAppDataForKey:@"encryptedfile" inMessage:self.message];
-
- [self onDelete];
- dispatch_async(dispatch_get_main_queue(), ^ {
- NSData *data = NULL;
- if (filePath) {
- data = [NSData dataWithContentsOfFile:filePath];
- }
- const char *text = linphone_chat_message_get_text_content(_message);
- NSString *str = text ? [NSString stringWithUTF8String:text] : NULL;
- if (localImage) {
- [_chatRoomDelegate resendFile: (data?:[ChatConversationView getFileData:localImage]) withName:localImage type:@"image" key:@"localimage" message:str voiceContent:voiceContent];
- } else if (localVideo) {
- [_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localVideo]) withName:localVideo type:@"video" key:@"localvideo" message:str voiceContent:voiceContent];
- } else {
- [_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localFile]) withName:localFile type:@"image" key:@"localfile" message:str voiceContent:voiceContent];
- }
- });
- } else {
- [self onDelete];
- 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) {
- NSString *text = self.textMessage;
- if (voiceContent && [text isEqualToString:@"🗻"])
- text = nil;
- [_chatRoomDelegate resendChat:text withExternalUrl:nil voiceContent:voiceContent];
- });
- }
-}
#pragma mark - State changed handling
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
LOGI(@"State for message [%p] changed to %s", msg, linphone_chat_message_state_to_string(state));
@@ -442,9 +364,15 @@ static const CGFloat CELL_MIN_HEIGHT = 65.0f;
static const CGFloat CELL_MIN_WIDTH = 190.0f;
static const CGFloat CELL_MESSAGE_X_MARGIN = 68 + 10.0f;
static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
+static const CGFloat REPLY_CHAT_BUBBLE_HEIGHT = 120;
+static const CGFloat REPLY_OR_FORWARD_TAG_HEIGHT = 18;
+
+ (CGSize)ViewHeightForMessage:(LinphoneChatMessage *)chat withWidth:(int)width {
- return [self ViewHeightForMessageText:chat withWidth:width textForImdn:nil];
+ CGSize size = [self ViewHeightForMessageText:chat withWidth:width textForImdn:nil];
+ size.height += linphone_chat_message_is_forward(chat) || linphone_chat_message_is_reply(chat) ? REPLY_OR_FORWARD_TAG_HEIGHT : 0;
+ size.height += linphone_chat_message_is_reply(chat) ? REPLY_CHAT_BUBBLE_HEIGHT+5 : 0;
+ return size;
}
+ (CGSize)ViewHeightForFile:(int)width {
@@ -456,20 +384,38 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
}
++(NSString *)formattedDuration:(long)valueMs {
+ return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60, (valueMs % 60) ];
+}
+
++(NSString *) recordingDuration:(NSString *) _voiceRecordingFile{
+ NSError *error = nil;
+ AVAudioPlayer* utilityPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL URLWithString:_voiceRecordingFile] error:&error]; // Workaround as opening multiple linphone_players at the same time can cause crash (here for example layout refreshed whilst a voice memo is playing
+ return [self formattedDuration:utilityPlayer.duration];
+ utilityPlayer = nil;
+}
+
+ (UIImage *)getImageFromFileName:(NSString *)fileName {
NSString *extension = [[fileName.lowercaseString componentsSeparatedByString:@"."] lastObject];
UIImage *image;
- if ([extension isEqualToString:@"pdf"])
- image = [UIImage imageNamed:@"file_pdf_default"];
- else if ([@[@"png", @"jpg", @"jpeg", @"bmp", @"heic"] containsObject:extension])
- image = [UIImage imageNamed:@"file_picture_default"];
- else if ([@[@"mkv", @"avi", @"mov", @"mp4"] containsObject:extension])
- image = [UIImage imageNamed:@"file_video_default"];
- else if ([@[@"wav", @"au", @"m4a"] containsObject:extension])
- image = [UIImage imageNamed:@"file_audio_default"];
- else
- image = [UIImage imageNamed:@"file_default"];
- return [SwiftUtil textToImageWithDrawText:fileName inImage:image];
+ NSString * text = fileName;
+ if ([fileName containsString:@"voice-recording"]) {
+ image = [UIImage imageNamed:@"file_voice_default"];
+ text = [self recordingDuration:[LinphoneManager validFilePath:fileName]];
+ } else {
+ if ([extension isEqualToString:@"pdf"])
+ image = [UIImage imageNamed:@"file_pdf_default"];
+ else if ([@[@"png", @"jpg", @"jpeg", @"bmp", @"heic"] containsObject:extension])
+ image = [UIImage imageNamed:@"file_picture_default"];
+ else if ([@[@"mkv", @"avi", @"mov", @"mp4"] containsObject:extension])
+ image = [UIImage imageNamed:@"file_video_default"];
+ else if ([@[@"wav", @"au", @"m4a"] containsObject:extension])
+ image = [UIImage imageNamed:@"file_audio_default"];
+ else
+ image = [UIImage imageNamed:@"file_default"];
+ }
+
+ return [SwiftUtil textToImageWithDrawText:text inImage:image];
}
+ (UIImage *)getImageFromContent:(LinphoneContent *)content filePath:(NSString *)filePath; {
@@ -630,7 +576,8 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
size = [self computeBoundingBox:messageText
size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX)
font:messageFont];
- } else {
+ size.width += 4;
+ } else { // Just file or file with text
LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(chat);
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:chat];
@@ -671,10 +618,11 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
} else if (voiceContent){
return [self addVoicePlayerToSize:[self ViewHeightForFile:width] withMargins:true];
} else {
- image = [UIChatBubbleTextCell getImageFromFileName:fileName];
+ image = nil;
+ originalImageSize = CGSizeMake(140, 140);
}
-
- originalImageSize = image.size;
+ if (image != nil)
+ originalImageSize = image.size;
} else {
if (!localImage && !localVideo) {
//We are loading the image
@@ -781,15 +729,45 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
int origin_x;
bubbleFrame.size = [self.class ViewSizeForMessage:_message withWidth:available_width];
+ if (linphone_chat_message_is_reply(_message)) {
+ bubbleFrame.size.width = MAX(bubbleFrame.size.width, 300);
+ }
if (tableView.isEditing) {
origin_x = 0;
} else {
origin_x = (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
}
+
+ CGRect r = _messageText.frame;
+ r.origin.y = linphone_chat_message_is_reply(_message) ? _replyView.view.frame.origin.y + _replyView.view.frame.size.height + 5 : 3;
+ _messageText.frame = r;
+
+ r = _messageText.frame;
+ r.origin.y = linphone_chat_message_is_forward(_message) ? _contactDateLabel.frame.origin.y + _contactDateLabel.frame.size.height + 5 : r.origin.y;
+ _messageText.frame = r;
+
+ _replyTransferIcon.hidden = ! linphone_chat_message_is_reply(_message) && !linphone_chat_message_is_forward(_message);
+ _replyTransferLabel.hidden = ! linphone_chat_message_is_reply(_message) && !linphone_chat_message_is_forward(_message);
+
+ if (linphone_chat_message_is_reply(_message)) {
+ CGRect replyFrame = CGRectMake(10, _replyTransferLabel.frame.origin.y+_replyTransferLabel.frame.size.height+5,MAX(self.contactDateLabel.frame.size.width-20,180), REPLY_CHAT_BUBBLE_HEIGHT);
+ _replyView.view.frame = replyFrame;
+ _replyTransferIcon.image = [UIImage imageNamed:@"menu_reply_default"];
+ _replyTransferLabel.text = NSLocalizedString(@"Answer",nil);
+ _replyTransferLabel.textColor = [UIColor lightGrayColor];
+ }
+
+ if (linphone_chat_message_is_forward(_message)) {
+ _replyTransferIcon.image = [UIImage imageNamed:@"menu_forward_default"];
+ _replyTransferLabel.text = NSLocalizedString(@"Transferred",nil);
+ _replyTransferLabel.textColor = [UIColor darkGrayColor];
+ }
bubbleFrame.origin.x = origin_x;
_bubbleView.frame = bubbleFrame;
+
+
}
}
@@ -817,4 +795,173 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
return mediaSize;
}
+
+// Message popup menu
+// Copy text -> if has text
+// Transfer -> always
+// Reply -> always
+// IMDM Status -> out
+// Delete -> always
+
+
+-(void) buildActions {
+ LinphoneChatMessage *message = self.message;
+ _messageActionsTitles = [[NSMutableArray alloc] init];
+ _messageActionsBlocks = [[NSMutableArray alloc] init];
+ _messageActionsIcons = [[NSMutableArray alloc] init];
+
+ UIChatBubbleTextCell *thiz = self;
+
+ LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
+ if (state == LinphoneChatMessageStateNotDelivered || state == LinphoneChatMessageStateFileTransferError) {
+ [_messageActionsTitles addObject:NSLocalizedString(@"Resend", nil)];
+ [_messageActionsIcons addObject:@"menu_resend_default"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ if (!linphone_core_is_network_reachable(LC)) {
+ [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
+ return;
+ }
+ linphone_chat_message_send(message);
+ }];
+ }
+
+
+ if (linphone_chat_message_get_utf8_text(message)) {
+ [_messageActionsTitles addObject:NSLocalizedString(@"Copy text", nil)];
+ [_messageActionsIcons addObject:@"menu_copy_text_default"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ [UIPasteboard.generalPasteboard setString:[NSString stringWithUTF8String:linphone_chat_message_get_text_content(message)]];
+ }];
+ }
+
+
+ [_messageActionsTitles addObject:NSLocalizedString(@"Forward", nil)];
+ [_messageActionsIcons addObject:@"menu_forward_default"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ VIEW(ChatConversationView).pendingForwardMessage = message;
+ [PhoneMainView.instance changeCurrentView:VIEW(ChatsListView).compositeViewDescription];
+ }];
+
+
+
+ [_messageActionsTitles addObject:NSLocalizedString(@"Reply", nil)];
+ [_messageActionsIcons addObject:@"menu_reply_default"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ [VIEW(ChatConversationView) initiateReplyViewForMessage:message];
+ }];
+
+ if (linphone_chat_message_is_outgoing(self.message) && linphone_chat_room_get_nb_participants(linphone_chat_message_get_chat_room(self.message)) > 1) {
+ [_messageActionsTitles addObject:NSLocalizedString(@"Infos", nil)];
+ [_messageActionsIcons addObject:@"menu_info"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ ChatConversationImdnView *view = VIEW(ChatConversationImdnView);
+ view.msg = message;
+ [PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
+ }];
+ }
+
+ [_messageActionsTitles addObject:NSLocalizedString(@"Delete", nil)];
+ [_messageActionsIcons addObject:@"menu_delete"];
+ [_messageActionsBlocks addObject:^{
+ [thiz dismissPopup];
+ linphone_chat_room_delete_message(linphone_chat_message_get_chat_room(message), message);
+ [VIEW(ChatConversationView).tableController reloadData];
+ }];
+}
+
+-(void) onPopupMenuPressed {
+ if (_popupMenu != nil)
+ [self dismissPopup];
+
+ if (!self.popupMenuAllowed)
+ return;
+
+
+ [VIEW(ChatConversationView).tableController dismissMessagesPopups];
+ self.innerView.layer.borderWidth = 3;
+ self.innerView.layer.borderColor = [UIColor color:@"A"].CGColor;
+ [self buildActions];
+ int width = 250;
+ int cellHeight = 44;
+ int numberOfItems = (int) _messageActionsTitles.count;
+ CGRect screenRect = UIScreen.mainScreen.bounds;
+ int menuHeight = numberOfItems * cellHeight;
+
+ CGRect frame = CGRectMake(
+ linphone_chat_message_is_outgoing(self.message) ? screenRect.size.width - width - 10 : 10,
+ (self.frame.origin.y + self.frame.size.height) - [VIEW(ChatConversationView).tableController .tableView contentOffset].y > screenRect.size.height /2 ? self.frame.origin.y - menuHeight - 10: self.frame.origin.y + self.frame.size.height,
+ width,
+ menuHeight);
+
+ _popupMenu = [[UITableView alloc]initWithFrame:frame];
+ _popupMenu.dataSource = self;
+ _popupMenu.delegate = self;
+ _popupMenu.layer.shadowColor = [UIColor lightGrayColor].CGColor;
+ _popupMenu.layer.shadowOpacity = 0.5;
+ _popupMenu.layer.shadowOffset = CGSizeZero;
+ _popupMenu.layer.shadowRadius = 5;
+ _popupMenu.layer.masksToBounds = false;
+ _popupMenu.tableFooterView = [UIView new];
+ _popupMenu.editing = NO;
+ _popupMenu.userInteractionEnabled = true;
+ [_popupMenu reloadData];
+ [VIEW(ChatConversationView).tableController.view addSubview:_popupMenu];
+ UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapOutsideMenu:)];
+ tapGestureRecognizer.cancelsTouchesInView = NO;
+ tapGestureRecognizer.numberOfTapsRequired = 1;
+ [VIEW(ChatConversationView).tableController.view addGestureRecognizer:tapGestureRecognizer];
+}
+
+-(void) dismissPopup {
+ if (!_popupMenu)
+ return;
+ [_popupMenu removeFromSuperview];
+ _popupMenu = nil;
+ self.innerView.layer.borderWidth = 0;
+ [self setNeedsLayout];
+}
+
+
+-(void) tapOutsideMenu:(UITapGestureRecognizer *) g {
+ CGPoint p = [g locationInView:VIEW(ChatConversationView).tableController.view];
+ if (!CGRectContainsPoint(_popupMenu.frame,p)) {
+ [self dismissPopup];
+ }
+}
+
+-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+ void (^ myblock)(void) = [_messageActionsBlocks objectAtIndex:indexPath.row];
+ [self dismissPopup];
+ myblock();
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return [_messageActionsTitles count];
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ UITableViewCell *cell = [[UITableViewCell alloc] init];
+ cell.imageView.image = [[UIImage imageNamed:[_messageActionsIcons objectAtIndex:indexPath.row]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+ cell.textLabel.text = [_messageActionsTitles objectAtIndex:indexPath.row];
+ cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
+ if ([[_messageActionsIcons objectAtIndex:indexPath.row] isEqualToString:@"menu_delete"]) {
+ cell.textLabel.textColor = UIColor.redColor;
+ cell.imageView.tintColor = UIColor.redColor;
+ } else {
+ cell.imageView.tintColor = PhoneMainView.instance.darkMode ? UIColor.whiteColor : UIColor.blackColor;
+ }
+ return cell;
+}
+
+
+
@end
diff --git a/Classes/LinphoneUI/UIChatCell.h b/Classes/LinphoneUI/UIChatCell.h
index d5d0327b9..29343ea40 100644
--- a/Classes/LinphoneUI/UIChatCell.h
+++ b/Classes/LinphoneUI/UIChatCell.h
@@ -38,6 +38,8 @@
@property(weak, nonatomic) IBOutlet UILabel *unreadCountLabel;
@property (weak, nonatomic) IBOutlet UIImageView *imdmIcon;
@property (weak, nonatomic) IBOutlet UIImageView *ephemeral;
+@property (weak, nonatomic) IBOutlet UIImageView *forwardIcon;
+
- (id)initWithIdentifier:(NSString*)identifier;
diff --git a/Classes/LinphoneUI/UIChatCell.m b/Classes/LinphoneUI/UIChatCell.m
index 299898dbf..3fc01de59 100644
--- a/Classes/LinphoneUI/UIChatCell.m
+++ b/Classes/LinphoneUI/UIChatCell.m
@@ -46,6 +46,7 @@
- (void)setChatRoom:(LinphoneChatRoom *)achat {
chatRoom = achat;
[self update];
+ [self.forwardIcon setImageNamed:@"forward_message_default" tintColor:PhoneMainView.instance.darkMode ? UIColor.whiteColor : UIColor.darkGrayColor];
}
#pragma mark -
diff --git a/Classes/LinphoneUI/UIChatReplyBubbleView.h b/Classes/LinphoneUI/UIChatReplyBubbleView.h
new file mode 100644
index 000000000..b9c175ae2
--- /dev/null
+++ b/Classes/LinphoneUI/UIChatReplyBubbleView.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010-2020 Belledonne Communications SARL.
+ *
+ * This file is part of linphone-iphone
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface UIChatReplyBubbleView : UIViewController
+@property (weak, nonatomic) IBOutlet UILabel *senderName;
+@property (weak, nonatomic) IBOutlet UIButton *dismissButton;
+@property (weak, nonatomic) IBOutlet UIView *leftBar;
+@property (weak, nonatomic) IBOutlet UIView *rightBar;
+@property LinphoneChatMessage *message;
+@property (weak, nonatomic) IBOutlet UILabel *textContent;
+@property void (^ dismissAction)(void);
+@property void (^ clickAction)(void);
+@property (weak, nonatomic) IBOutlet UICollectionView *contentCollection;
+@property NSArray *dataContent;
+@property (weak, nonatomic) IBOutlet UILabel *originalMessageGone;
+
+-(void) configureForMessage:(LinphoneChatMessage *)message withDimissBlock:(void (^)(void))dismissBlock hideDismiss:(BOOL)hideDismiss withClickBlock:(void (^)(void))clickBlock;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Classes/LinphoneUI/UIChatReplyBubbleView.m b/Classes/LinphoneUI/UIChatReplyBubbleView.m
new file mode 100644
index 000000000..e6e523561
--- /dev/null
+++ b/Classes/LinphoneUI/UIChatReplyBubbleView.m
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2010-2020 Belledonne Communications SARL.
+ *
+ * This file is part of linphone-iphone
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#import "UIChatReplyBubbleView.h"
+#import "linphoneapp-Swift.h"
+#import "Utils.h"
+
+@interface UIChatReplyBubbleView ()
+
+@end
+
+@implementation UIChatReplyBubbleView
+
+
+- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
+ return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+ return self;
+}
+
+-(void) viewDidLoad {
+ _contentCollection.dataSource = self;
+ [_contentCollection registerClass:UICollectionViewCell.class forCellWithReuseIdentifier:@"dataContent"];
+}
+
+
+-(void) configureForMessage:(LinphoneChatMessage *)message withDimissBlock:(void (^)(void))dismissBlock hideDismiss:(BOOL)hideDismiss withClickBlock:(void (^)(void))clickBlock{
+ if (!message) {
+ _textContent.hidden = true;
+ _dismissButton.hidden = true;
+ _contentCollection.hidden = true;
+ _senderName.hidden = true;
+ _originalMessageGone.hidden = false;
+ return;
+ }
+ if (hideDismiss) {
+ self.view.layer.cornerRadius = 10;
+ self.view.layer.masksToBounds = true;
+ }
+ _originalMessageGone.hidden = true;
+ self.message = message;
+ self.dataContent = [self loadDataContent];
+ NSString *sender = [FastAddressBook displayNameForAddress:linphone_chat_message_get_from_address(message)];
+ _senderName.text = sender;
+ const char * text = linphone_chat_message_get_text_content(message);
+ if (text && strlen(text) == 0)
+ text = nil;
+ _textContent.text = text ? [NSString stringWithUTF8String:text] : @"";
+ _dismissButton.hidden = hideDismiss;
+ _dismissAction = dismissBlock;
+ _clickAction = clickBlock;
+ if (hideDismiss) {
+ UITapGestureRecognizer *singleFingerTap =
+ [[UITapGestureRecognizer alloc] initWithTarget:self
+ action:@selector(onClick)];
+ [self.view addGestureRecognizer:singleFingerTap];
+ }
+ else
+ [_dismissButton addTarget:self action:@selector(dismissClick) forControlEvents:UIControlEventTouchUpInside];
+
+
+ self.view.backgroundColor = hideDismiss ? UIColor.whiteColor :(linphone_chat_message_is_outgoing(message) ? [[UIColor color:@"A"] colorWithAlphaComponent:0.2] : [[UIColor color:@"D"] colorWithAlphaComponent:0.2]);
+ _leftBar.backgroundColor = linphone_chat_message_is_outgoing(message) ? [UIColor color:@"A"] : [UIColor color:@"D"];
+ _leftBar.hidden = !hideDismiss;
+ _rightBar.backgroundColor = self.view.backgroundColor;
+
+
+ // Resize frame -> text or content only = 100, 145 otherwise
+ _contentCollection.hidden = self.dataContent.count == 0;
+
+ CGRect r = self.view.frame ;
+ r.size.width = self.view.superview.frame.size.width;
+ self.view.frame = r;
+
+ if (self.dataContent.count == 0) {
+ CGRect r = _textContent.frame;
+ r.origin.y = _contentCollection.frame.origin.y;
+ r.size.height = 87;
+ _textContent.frame = r;
+ }
+
+ if (text == nil) {
+ CGRect r = _contentCollection.frame;
+ r.origin.y = 30;
+ _contentCollection.frame = r;
+ }
+}
+
+
+-(NSArray *) loadDataContent {
+ NSMutableArray *result = [[NSMutableArray alloc] init];
+ const bctbx_list_t *contents = linphone_chat_message_get_contents(_message);
+ const char * text = linphone_chat_message_get_utf8_text(_message);
+ if (text && bctbx_list_size(contents) == 1)
+ return result;
+
+ for (const bctbx_list_t * it = contents; it != NULL; it=bctbx_list_next(it)){
+ LinphoneContent *content = (LinphoneContent *)it->data;
+ if (linphone_content_is_text(content))
+ continue;
+ NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
+ NSMutableDictionary *encrptedFilePaths = encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:_message];
+ NSString *filePath = encrptedFilePaths ? [encrptedFilePaths valueForKey:name] : nil;
+ if (filePath == NULL) {
+ filePath = [LinphoneManager validFilePath:name];
+ }
+ [result addObject:[UIChatBubbleTextCell getImageFromContent:content filePath:filePath]];
+ }
+ return result;
+}
+
+-(void) dismissClick {
+ _dismissAction();
+}
+
+-(void) onClick {
+ _clickAction();
+}
+
+-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
+ return 1;
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+ return self.dataContent.count;
+}
+
+- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+ UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"dataContent" forIndexPath:indexPath];
+ UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
+ img.image = [self.dataContent objectAtIndex:indexPath.row];
+ [cell.contentView addSubview:img];
+ return cell;
+}
+
+
+
+
+@end
diff --git a/Classes/LinphoneUI/UIConfirmationDialog.h b/Classes/LinphoneUI/UIConfirmationDialog.h
index ad0a0b5b0..c2d9feadc 100644
--- a/Classes/LinphoneUI/UIConfirmationDialog.h
+++ b/Classes/LinphoneUI/UIConfirmationDialog.h
@@ -45,6 +45,7 @@ typedef void (^UIConfirmationBlock)(void);
@property(weak, nonatomic) IBOutlet UIRoundBorderedButton *cancelButton;
@property (weak, nonatomic) IBOutlet UIImageView *securityImage;
+@property (weak, nonatomic) IBOutlet UIImageView *forwardImage;
@property(weak, nonatomic) IBOutlet UIRoundBorderedButton *confirmationButton;
@property (weak, nonatomic) IBOutlet UIView *authView;
@property(weak, nonatomic) IBOutlet UILabel *titleLabel;
diff --git a/Classes/LinphoneUI/en.lproj/UIChatReplyBubbleView.strings b/Classes/LinphoneUI/en.lproj/UIChatReplyBubbleView.strings
new file mode 100644
index 000000000..cfa28ba85
--- /dev/null
+++ b/Classes/LinphoneUI/en.lproj/UIChatReplyBubbleView.strings
@@ -0,0 +1,9 @@
+
+/* Class = "UILabel"; text = "Original message removed"; ObjectID = "B26-sw-o4w"; */
+"B26-sw-o4w.text" = "Original message does not exist anymore.";
+
+/* Class = "UILabel"; text = "Label"; ObjectID = "Czc-VH-qiH"; */
+"Czc-VH-qiH.text" = "Label";
+
+/* Class = "UILabel"; text = "Label"; ObjectID = "uuW-tW-1Sj"; */
+"uuW-tW-1Sj.text" = "Label";
diff --git a/Classes/LinphoneUI/fr.lproj/UIChatReplyBubbleView.strings b/Classes/LinphoneUI/fr.lproj/UIChatReplyBubbleView.strings
new file mode 100644
index 000000000..de5a5c443
--- /dev/null
+++ b/Classes/LinphoneUI/fr.lproj/UIChatReplyBubbleView.strings
@@ -0,0 +1,9 @@
+
+/* Class = "UILabel"; text = "Original message removed"; ObjectID = "B26-sw-o4w"; */
+"B26-sw-o4w.text" = "Le message original n'existe plus.";
+
+/* Class = "UILabel"; text = "Label"; ObjectID = "Czc-VH-qiH"; */
+"Czc-VH-qiH.text" = "Label";
+
+/* Class = "UILabel"; text = "Label"; ObjectID = "uuW-tW-1Sj"; */
+"uuW-tW-1Sj.text" = "Label";
diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h
index 60633724e..adfe87b5a 100644
--- a/Classes/PhoneMainView.h
+++ b/Classes/PhoneMainView.h
@@ -121,6 +121,7 @@
- (BOOL)isIphoneXDevice;
+ (int)iphoneStatusBarHeight;
+-(BOOL) darkMode;
@end
diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m
index 680712541..793243495 100644
--- a/Classes/PhoneMainView.m
+++ b/Classes/PhoneMainView.m
@@ -957,4 +957,15 @@ void main_view_chat_room_state_changed(LinphoneChatRoom *cr, LinphoneChatRoomSta
[controller dismissModalViewControllerAnimated:YES];
}
+#pragma mark - Light/Dark mode
+
+-(BOOL) darkMode {
+ if (@available(iOS 13.0, *)) {
+ UITraitCollection *collection = [UITraitCollection currentTraitCollection];
+ return collection.userInterfaceStyle == UIUserInterfaceStyleDark;
+ } else {
+ return false;
+ }
+}
+
@end
diff --git a/Classes/SwiftUtil.swift b/Classes/SwiftUtil.swift
index ff1701b87..ff9278263 100644
--- a/Classes/SwiftUtil.swift
+++ b/Classes/SwiftUtil.swift
@@ -1,46 +1,69 @@
-//
-// SwiftUtil.swift
-// linphone
-//
-// Created by Tof on 23/07/2021.
-//
+/*
+* Copyright (c) 2010-2020 Belledonne Communications SARL.
+*
+* This file is part of linphone-iphone
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see .
+*/
import UIKit
@objc class SwiftUtil: NSObject {
-
+
@objc static func textToImage(drawText text: String, inImage image: UIImage) -> UIImage {
let textColor = UIColor.black
- let textFont = UIFont(name: "Helvetica", size: 12)!
+ let fontMax = UIFont.systemFont(ofSize: 30)
let backgroundColor = UIColor.white
let size = CGSize(width: 120, height: 120)
-
+
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
backgroundColor.setFill()
context!.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
-
- let paragraph = NSMutableParagraphStyle()
- paragraph.alignment = .center
- let textFontAttributes = [
- NSAttributedString.Key.font: textFont,
- NSAttributedString.Key.foregroundColor: textColor,
- NSAttributedString.Key.paragraphStyle: paragraph,
- ] as [NSAttributedString.Key : Any]
+ image.draw(in: CGRect(origin: CGPoint(x: size.width/2 - (image.size.width)/2,y: 5), size: image.size))
+
+ let label = UILabel(frame: CGRect(x: 0,y: 0,width: size.width,height: 50))
+ label.numberOfLines = 0
+ label.font = fontMax
+ label.adjustsFontSizeToFitWidth = true
+ label.text = text
+ label.textColor = textColor
+ label.textAlignment = .center
+ label.allowsDefaultTighteningForTruncation = true
+ label.lineBreakMode = .byTruncatingTail
+ imageWithLabel(label: label).draw(in: CGRect(origin: CGPoint(x:0,y: 60), size: CGSize(width: size.width,height: 50)))
+ let view = UIView(frame: CGRect(x: 0,y: 0,width: size.width,height: 50))
+ view.addSubview(label)
+ label.sizeToFit()
+
- image.draw(in: CGRect(origin: CGPoint(x: size.width/2 - (image.size.width)/2,y: 15), size: image.size))
-
- let rect = CGRect(origin: CGPoint(x: 0,y: 70), size: CGSize(width: size.width, height: 30))
- text.draw(in: rect, withAttributes: textFontAttributes)
-
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
-
+
return newImage!
}
+ static func imageWithLabel(label: UILabel) -> UIImage {
+ UIGraphicsBeginImageContextWithOptions(label.frame.size, false, 0.0)
+ label.layer.render(in: UIGraphicsGetCurrentContext()!)
+ let img = UIGraphicsGetImageFromCurrentImageContext()!
+ UIGraphicsEndImageContext()
+ return img
+ }
+
}
diff --git a/Classes/Utils/FileTransferDelegate.h b/Classes/Utils/FileTransferDelegate.h
index 21ff1d605..3fa22bb55 100644
--- a/Classes/Utils/FileTransferDelegate.h
+++ b/Classes/Utils/FileTransferDelegate.h
@@ -24,11 +24,10 @@
@interface FileTransferDelegate : NSObject
-- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom andVoiceContent:(LinphoneContent *)voiceContent;
-- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key voiceContent:(LinphoneContent *)voiceContent;
+- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom rootMessage:(LinphoneChatMessage *)rootMessage;
+- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key rootMessage:(LinphoneChatMessage *)rootMessage;
- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
-- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name;
-- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom;
+- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name rootMessage:(LinphoneChatMessage *)rootMessage;
- (void)cancel;
- (BOOL)download:(LinphoneChatMessage *)message;
- (void)stopAndDestroy;
diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m
index 9ad65457e..0738c54b4 100644
--- a/Classes/Utils/FileTransferDelegate.m
+++ b/Classes/Utils/FileTransferDelegate.m
@@ -102,7 +102,7 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
}
}
-- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key voiceContent:(LinphoneContent *)voiceContent{
+- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key rootMessage:(LinphoneChatMessage *)rootMessage{
if ([[LinphoneManager.instance fileTransferDelegates] containsObject:self]) {
LOGW(@"fileTransferDelegates has already added %p", self);
return;
@@ -115,7 +115,8 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
linphone_content_set_subtype(content, [subtype UTF8String]);
linphone_content_set_name(content, [name UTF8String]);
linphone_content_set_file_path(content, [[LinphoneManager imagesDirectory] stringByAppendingPathComponent:name].UTF8String);
- _message = linphone_chat_room_create_file_transfer_message(chatRoom, content);
+ _message = rootMessage;
+ linphone_chat_message_add_file_content(_message, content);
BOOL isOneToOneChat = linphone_chat_room_get_capabilities(chatRoom) & LinphoneChatRoomCapabilitiesOneToOne;
if (!isOneToOneChat && (_text!=nil && ![_text isEqualToString:@""]))
linphone_chat_message_add_text_content(_message, [_text UTF8String]);
@@ -125,17 +126,16 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
[LinphoneManager setValueInMessageAppData:name forKey:key inMessage:_message];
- if (voiceContent)
- linphone_chat_message_add_content(_message, voiceContent);
+
LOGI(@"%p Uploading content from message %p", self, _message);
linphone_chat_message_send(_message);
}
-- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom andVoiceContent:(LinphoneContent *)voiceContent{
+- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom rootMessage:(LinphoneChatMessage *)rootMessage{
[LinphoneManager.instance.fileTransferDelegates addObject:self];
- _message = linphone_chat_room_create_empty_message(chatRoom);
+ _message = rootMessage;
NSMutableArray *names = [[NSMutableArray alloc] init];
NSMutableArray *types = [[NSMutableArray alloc] init];
@@ -165,8 +165,7 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
// todo indication progress
[LinphoneManager setValueInMessageAppData:names forKey:@"multiparts" inMessage:_message];
[LinphoneManager setValueInMessageAppData:types forKey:@"multipartstypes" inMessage:_message];
- if (voiceContent)
- linphone_chat_message_add_content(_message, voiceContent);
+
LOGI(@"%p Uploading content from message %p", self, _message);
linphone_chat_message_send(_message);
}
@@ -175,21 +174,17 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
- (void)uploadImage:(UIImage *)image forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality {
NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]];
NSData *data = UIImageJPEGRepresentation(image, quality);
- [self uploadData:data forChatRoom:chatRoom type:@"image" subtype:@"jpg" name:name key:@"localimage" voiceContent:nil];
+ [self uploadData:data forChatRoom:chatRoom type:@"image" subtype:@"jpg" name:name key:@"localimage" rootMessage:nil];
}
-- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom {
- NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]];
- [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:@"mov" name:name key:@"localvideo" voiceContent:nil];
-}
-- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name {
+- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name rootMessage:(LinphoneChatMessage *)rootMessage {
NSURL *url = [ChatConversationView getFileUrl:name];
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
NSString *fileType = [[asset tracksWithMediaType:AVMediaTypeVideo] count] > 0 ? @"video" : @"file";
NSString *key = [ChatConversationView getKeyFromFileType:fileType fileName:name];
- [self uploadData:data forChatRoom:chatRoom type:fileType subtype:name.lastPathComponent name:name key:key voiceContent:nil];
+ [self uploadData:data forChatRoom:chatRoom type:fileType subtype:name.lastPathComponent name:name key:key rootMessage:rootMessage];
}
- (BOOL)download:(LinphoneChatMessage *)message {
diff --git a/Classes/Utils/Utils.h b/Classes/Utils/Utils.h
index d515926af..207521dc9 100644
--- a/Classes/Utils/Utils.h
+++ b/Classes/Utils/Utils.h
@@ -74,6 +74,13 @@ typedef enum {
@end
+@interface UIImageView (ImageWithTint)
+
+- (void)setImageNamed:(NSString *)name tintColor:(UIColor *)color;
+- (void)setImageNamed:(NSString *)name tintColorLetter:(NSString *)letter;
+
+@end
+
@interface NSString (linphoneExt)
- (NSString *)md5;
@@ -111,6 +118,8 @@ typedef enum {
- (UIColor *)darkerColor;
++(UIColor *)color:(NSString *)letter;
+
@end
@interface UIImage (ForceDecode)
diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m
index 7ae1fedca..b9cbfaaa1 100644
--- a/Classes/Utils/Utils.m
+++ b/Classes/Utils/Utils.m
@@ -575,6 +575,23 @@
@end
+
+
+@implementation UIImageView (ImageWithTint)
+
+- (void)setImageNamed:(NSString *)name tintColor:(UIColor *)color {
+ self.image = [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+ self.tintColor = color;
+}
+
+- (void)setImageNamed:(NSString *)name tintColorLetter:(NSString *)letter {
+ UIColor *color = [UIColor color:letter];
+ self.image = [[UIImage imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+ self.tintColor = color;
+}
+
+@end
+
@implementation NSString (md5)
- (NSString *)md5 {
@@ -804,6 +821,19 @@
return [self lumColor:0.75];
}
+
+static NSMutableDictionary *letterColors = nil;
+
++(UIColor *)color:(NSString *)letter {
+ if (letterColors == nil)
+ letterColors = [[NSMutableDictionary alloc] init];
+ if (![letterColors objectForKey:letter]) {
+ UIImage *colorImage = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/color_%@.png",[[NSBundle mainBundle] bundlePath],letter]];
+ [letterColors setObject:[UIColor colorWithPatternImage:colorImage] forKey:letter];
+ }
+ return [letterColors objectForKey:letter];
+}
+
@end
@implementation UIImage (ForceDecode)
diff --git a/Podfile b/Podfile
index d5ec02b57..7c061bc30 100644
--- a/Podfile
+++ b/Podfile
@@ -5,7 +5,7 @@ source "https://github.com/CocoaPods/Specs.git"
def all_pods
if ENV['PODFILE_PATH'].nil?
- pod 'linphone-sdk', '~> 5.1.0-alpha.11+950fc62'
+ pod 'linphone-sdk', '5.1.0-alpha.50+724b895'
else
pod 'linphone-sdk', :path => ENV['PODFILE_PATH'] # local sdk
end
diff --git a/Resources/fr.lproj/Localizable.strings b/Resources/fr.lproj/Localizable.strings
index 318063fa6..42321344b 100644
Binary files a/Resources/fr.lproj/Localizable.strings and b/Resources/fr.lproj/Localizable.strings differ
diff --git a/Resources/images/cancel_forward.png b/Resources/images/cancel_forward.png
new file mode 100644
index 000000000..8043430fe
Binary files /dev/null and b/Resources/images/cancel_forward.png differ
diff --git a/Resources/images/file_voice_default.png b/Resources/images/file_voice_default.png
new file mode 100644
index 000000000..a492d31a5
Binary files /dev/null and b/Resources/images/file_voice_default.png differ
diff --git a/Resources/images/forward_message_default.png b/Resources/images/forward_message_default.png
new file mode 100644
index 000000000..b51542ec8
Binary files /dev/null and b/Resources/images/forward_message_default.png differ
diff --git a/Resources/images/menu_copy_text_default.png b/Resources/images/menu_copy_text_default.png
new file mode 100644
index 000000000..ccdef4e4b
Binary files /dev/null and b/Resources/images/menu_copy_text_default.png differ
diff --git a/Resources/images/menu_delete.png b/Resources/images/menu_delete.png
new file mode 100644
index 000000000..947c0abf4
Binary files /dev/null and b/Resources/images/menu_delete.png differ
diff --git a/Resources/images/menu_forward_default.png b/Resources/images/menu_forward_default.png
new file mode 100644
index 000000000..910450bf9
Binary files /dev/null and b/Resources/images/menu_forward_default.png differ
diff --git a/Resources/images/menu_info.png b/Resources/images/menu_info.png
new file mode 100644
index 000000000..d45da33d5
Binary files /dev/null and b/Resources/images/menu_info.png differ
diff --git a/Resources/images/menu_reply_default.png b/Resources/images/menu_reply_default.png
new file mode 100644
index 000000000..8aa5b5e1e
Binary files /dev/null and b/Resources/images/menu_reply_default.png differ
diff --git a/Resources/images/menu_resend_default.png b/Resources/images/menu_resend_default.png
new file mode 100644
index 000000000..5f5ab4ddd
Binary files /dev/null and b/Resources/images/menu_resend_default.png differ
diff --git a/Resources/images/reply_cancel.png b/Resources/images/reply_cancel.png
new file mode 100644
index 000000000..8156bd629
Binary files /dev/null and b/Resources/images/reply_cancel.png differ
diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj
index b02841227..e02e00fe5 100644
--- a/linphone.xcodeproj/project.pbxproj
+++ b/linphone.xcodeproj/project.pbxproj
@@ -686,6 +686,18 @@
C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C64A85512667B74100252AD2 /* ephemeral_messages_default.png */; };
C666756F264C925800A0273C /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; };
C6667571264C925B00A0273C /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; };
+ C66B03BB26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */; };
+ C66B040A26EFDA55009B5EDC /* reply_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040926EFDA54009B5EDC /* reply_cancel.png */; };
+ C66B040E26F095D1009B5EDC /* cancel_forward.png in Resources */ = {isa = PBXBuildFile; fileRef = C66B040D26F095CE009B5EDC /* cancel_forward.png */; };
+ C6A1BB3526E8815400540D50 /* menu_info.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3126E8815300540D50 /* menu_info.png */; };
+ C6A1BB3626E8815400540D50 /* menu_forward_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3226E8815400540D50 /* menu_forward_default.png */; };
+ C6A1BB3726E8815400540D50 /* menu_copy_text_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3326E8815400540D50 /* menu_copy_text_default.png */; };
+ C6A1BB3826E8815400540D50 /* menu_reply_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3426E8815400540D50 /* menu_reply_default.png */; };
+ C6A1BB3A26E881E100540D50 /* menu_delete.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB3926E881E100540D50 /* menu_delete.png */; };
+ C6A1BB3E26E882D000540D50 /* UIChatReplyBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = C6A1BB3C26E882D000540D50 /* UIChatReplyBubbleView.m */; };
+ C6A1BB4126E889AD00540D50 /* forward_message_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4026E889AD00540D50 /* forward_message_default.png */; };
+ C6A1BB4326E88F7C00540D50 /* menu_resend_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4226E88F7C00540D50 /* menu_resend_default.png */; };
+ C6A1BB4526E890BD00540D50 /* file_voice_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6A1BB4426E890BD00540D50 /* file_voice_default.png */; };
C6B4444226AAD0980076C517 /* file_video_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443D26AAD0970076C517 /* file_video_default.png */; };
C6B4444326AAD0980076C517 /* file_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443E26AAD0970076C517 /* file_default.png */; };
C6B4444426AAD0980076C517 /* file_picture_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4443F26AAD0970076C517 /* file_picture_default.png */; };
@@ -1736,6 +1748,21 @@
C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EphemeralSettingsView.m; sourceTree = ""; };
C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EphemeralSettingsView.xib; sourceTree = ""; };
C64A85512667B74100252AD2 /* ephemeral_messages_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_default.png; sourceTree = ""; };
+ C66B03BC26E8EB1A009B5EDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIChatReplyBubbleView.xib; sourceTree = ""; };
+ C66B03C126E8EB82009B5EDC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; };
+ C66B03C326E8EB87009B5EDC /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/UIChatReplyBubbleView.strings; sourceTree = ""; };
+ C66B040926EFDA54009B5EDC /* reply_cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = reply_cancel.png; sourceTree = ""; };
+ C66B040D26F095CE009B5EDC /* cancel_forward.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cancel_forward.png; sourceTree = ""; };
+ C6A1BB3126E8815300540D50 /* menu_info.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_info.png; sourceTree = ""; };
+ C6A1BB3226E8815400540D50 /* menu_forward_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_forward_default.png; sourceTree = ""; };
+ C6A1BB3326E8815400540D50 /* menu_copy_text_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_copy_text_default.png; sourceTree = ""; };
+ C6A1BB3426E8815400540D50 /* menu_reply_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_reply_default.png; sourceTree = ""; };
+ C6A1BB3926E881E100540D50 /* menu_delete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_delete.png; sourceTree = ""; };
+ C6A1BB3B26E882D000540D50 /* UIChatReplyBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIChatReplyBubbleView.h; sourceTree = ""; };
+ C6A1BB3C26E882D000540D50 /* UIChatReplyBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIChatReplyBubbleView.m; sourceTree = ""; };
+ C6A1BB4026E889AD00540D50 /* forward_message_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = forward_message_default.png; sourceTree = ""; };
+ C6A1BB4226E88F7C00540D50 /* menu_resend_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_resend_default.png; sourceTree = ""; };
+ C6A1BB4426E890BD00540D50 /* file_voice_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_voice_default.png; sourceTree = ""; };
C6B4443D26AAD0970076C517 /* file_video_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_video_default.png; sourceTree = ""; };
C6B4443E26AAD0970076C517 /* file_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_default.png; sourceTree = ""; };
C6B4443F26AAD0970076C517 /* file_picture_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_picture_default.png; sourceTree = ""; };
@@ -2190,6 +2217,9 @@
2214EB7012F84668002A5394 /* LinphoneUI */ = {
isa = PBXGroup;
children = (
+ C6A1BB3B26E882D000540D50 /* UIChatReplyBubbleView.h */,
+ C6A1BB3C26E882D000540D50 /* UIChatReplyBubbleView.m */,
+ C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */,
63F1DF421BCE618E00EDED90 /* UIAddressTextField.h */,
63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */,
63C441C11BBC23ED0053DC5E /* UIAssistantTextField.h */,
@@ -2471,6 +2501,16 @@
633FEBE11D3CD5570014B822 /* images */ = {
isa = PBXGroup;
children = (
+ C66B040D26F095CE009B5EDC /* cancel_forward.png */,
+ C66B040926EFDA54009B5EDC /* reply_cancel.png */,
+ C6A1BB4426E890BD00540D50 /* file_voice_default.png */,
+ C6A1BB4226E88F7C00540D50 /* menu_resend_default.png */,
+ C6A1BB4026E889AD00540D50 /* forward_message_default.png */,
+ C6A1BB3926E881E100540D50 /* menu_delete.png */,
+ C6A1BB3326E8815400540D50 /* menu_copy_text_default.png */,
+ C6A1BB3226E8815400540D50 /* menu_forward_default.png */,
+ C6A1BB3126E8815300540D50 /* menu_info.png */,
+ C6A1BB3426E8815400540D50 /* menu_reply_default.png */,
C6B4444026AAD0970076C517 /* file_audio_default.png */,
C6B4443E26AAD0970076C517 /* file_default.png */,
C6B4444126AAD0970076C517 /* file_pdf_default.png */,
@@ -3414,6 +3454,7 @@
633FEF3F1D3CD55A0014B822 /* security_pending@2x.png in Resources */,
24BFAAA4209B0630004F47A7 /* linphone_logo.png in Resources */,
633FEDC41D3CD5590014B822 /* call_hangup_disabled.png in Resources */,
+ C66B03BB26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib in Resources */,
633FEDA81D3CD5590014B822 /* backspace_default.png in Resources */,
636316D11A1DEBCB0009B839 /* AboutView.xib in Resources */,
8CBD7BA620B6B82400E5DCC0 /* UIChatConversationInfoTableViewCell.xib in Resources */,
@@ -3480,6 +3521,7 @@
633FEF331D3CD55A0014B822 /* route_speaker_selected@2x.png in Resources */,
633FEE6C1D3CD5590014B822 /* footer_dialer_disabled.png in Resources */,
633FEF231D3CD55A0014B822 /* route_bluetooth_default@2x.png in Resources */,
+ C6A1BB4526E890BD00540D50 /* file_voice_default.png in Resources */,
633FED9C1D3CD5590014B822 /* add_field_default.png in Resources */,
633FEE411D3CD5590014B822 /* contacts_all_selected@2x.png in Resources */,
D38187F815FE355D00C3EDCA /* TabBarView.xib in Resources */,
@@ -3554,6 +3596,7 @@
633FEEED1D3CD55A0014B822 /* numpad_hash_over.png in Resources */,
633FEE1F1D3CD5590014B822 /* chat_start_body_disabled@2x.png in Resources */,
633FEEF81D3CD55A0014B822 /* numpad_star_over~ipad.png in Resources */,
+ C6A1BB3826E8815400540D50 /* menu_reply_default.png in Resources */,
633FEF301D3CD55A0014B822 /* route_speaker_disabled.png in Resources */,
639CEAFD1A1DF4D9004DE38F /* StatusBarView.xib in Resources */,
633FEDE91D3CD5590014B822 /* call_status_missed~ipad@2x.png in Resources */,
@@ -3587,6 +3630,7 @@
633FEEC81D3CD55A0014B822 /* numpad_5_over~ipad@2x.png in Resources */,
61586B91217A175D0038AC45 /* menu_recordings.png in Resources */,
633FEF1B1D3CD55A0014B822 /* presence_away@2x.png in Resources */,
+ C6A1BB3A26E881E100540D50 /* menu_delete.png in Resources */,
633FEE281D3CD5590014B822 /* checkbox_unchecked.png in Resources */,
633FEE9D1D3CD55A0014B822 /* numpad_0_over.png in Resources */,
633FEEC21D3CD55A0014B822 /* numpad_4~ipad@2x.png in Resources */,
@@ -3603,6 +3647,7 @@
633FEEC01D3CD55A0014B822 /* numpad_4_over~ipad@2x.png in Resources */,
61586B8B217A17320038AC45 /* menu_link_account@2x.png in Resources */,
63CDC4661C3BDE370085F529 /* shortring.caf in Resources */,
+ C6A1BB4126E889AD00540D50 /* forward_message_default.png in Resources */,
633FEDD51D3CD5590014B822 /* call_quality_indicator_4@2x.png in Resources */,
633FEDE71D3CD5590014B822 /* call_status_missed@2x.png in Resources */,
615A2821217F6FBF0060F920 /* security_alert_indicator@2x.png in Resources */,
@@ -3733,6 +3778,7 @@
24BFAAA5209B0630004F47A7 /* contacts_sip_default.png in Resources */,
633FEF441D3CD55A0014B822 /* speaker_default.png in Resources */,
639CEB031A1DF4EB004DE38F /* UICompositeView.xib in Resources */,
+ C6A1BB4326E88F7C00540D50 /* menu_resend_default.png in Resources */,
633FEF3A1D3CD55A0014B822 /* security_ko.png in Resources */,
615A283A2180788E0060F920 /* security_toogle_button.png in Resources */,
633FEDA01D3CD5590014B822 /* avatar.png in Resources */,
@@ -3764,6 +3810,7 @@
63CDC45E1C3BDE370085F529 /* msg.caf in Resources */,
633FEE6D1D3CD5590014B822 /* footer_dialer_disabled@2x.png in Resources */,
633FEF171D3CD55A0014B822 /* pause_small_disabled@2x.png in Resources */,
+ C6A1BB3626E8815400540D50 /* menu_forward_default.png in Resources */,
D38187DD15FE348A00C3EDCA /* AssistantView.xib in Resources */,
633FEDA61D3CD5590014B822 /* back_disabled.png in Resources */,
633FEED61D3CD55A0014B822 /* numpad_7_over@2x.png in Resources */,
@@ -3879,6 +3926,7 @@
C6B4444226AAD0980076C517 /* file_video_default.png in Resources */,
633FEDBE1D3CD5590014B822 /* call_back_default.png in Resources */,
633FEF0F1D3CD55A0014B822 /* pause_big_default@2x.png in Resources */,
+ C66B040E26F095D1009B5EDC /* cancel_forward.png in Resources */,
CF7602F6210898CC00749F76 /* rec_on_default@2x.png in Resources */,
633FEF081D3CD55A0014B822 /* options_start_conference_disabled.png in Resources */,
63F1DF511BCE986A00EDED90 /* UICallConferenceCell.xib in Resources */,
@@ -3908,6 +3956,7 @@
633FEE221D3CD5590014B822 /* chat_start_body_over.png in Resources */,
633FEE601D3CD5590014B822 /* edit_list_disabled.png in Resources */,
D38187C115FE345B00C3EDCA /* DialerView.xib in Resources */,
+ C6A1BB3726E8815400540D50 /* menu_copy_text_default.png in Resources */,
D37EE10D16035793003608A6 /* ImageView.xib in Resources */,
633FEE9F1D3CD55A0014B822 /* numpad_0_over~ipad.png in Resources */,
633FEED51D3CD55A0014B822 /* numpad_7_over.png in Resources */,
@@ -3923,6 +3972,7 @@
633FEE4A1D3CD5590014B822 /* delete_disabled.png in Resources */,
614D09CE21E74D5400C43EDF /* GoogleService-Info.plist in Resources */,
C6B4444526AAD0980076C517 /* file_audio_default.png in Resources */,
+ C6A1BB3526E8815400540D50 /* menu_info.png in Resources */,
C61B1BF72667EC6B001A4E4A /* ephemeral_messages_color_A.png in Resources */,
633FEF151D3CD55A0014B822 /* pause_small_default@2x.png in Resources */,
633FEEF91D3CD55A0014B822 /* numpad_star_over~ipad@2x.png in Resources */,
@@ -3997,6 +4047,7 @@
633FEDDD1D3CD5590014B822 /* call_start_body_disabled~ipad@2x.png in Resources */,
633FEEBD1D3CD55A0014B822 /* numpad_4_over.png in Resources */,
8CA70AD41F9E285C00A3D2EB /* chat_group_add@2x.png in Resources */,
+ C66B040A26EFDA55009B5EDC /* reply_cancel.png in Resources */,
633FEEF11D3CD55A0014B822 /* numpad_hash~ipad.png in Resources */,
633FEE781D3CD5590014B822 /* history_chat_indicator.png in Resources */,
633FEF431D3CD55A0014B822 /* select_all_disabled@2x.png in Resources */,
@@ -4275,6 +4326,7 @@
CF7602D7210867E800749F76 /* RecordingsListView.m in Sources */,
63F1DF4B1BCE983200EDED90 /* CallConferenceTableView.m in Sources */,
D3F83F8E15822ABE00336684 /* PhoneMainView.m in Sources */,
+ C6A1BB3E26E882D000540D50 /* UIChatReplyBubbleView.m in Sources */,
6377AC801BDE4069007F7625 /* UIBackToCallButton.m in Sources */,
6308F9C51BF0DD6600D1234B /* XMLRPCHelper.m in Sources */,
D3ED3E871586291E006C0DE4 /* TabBarView.m in Sources */,
@@ -4764,6 +4816,16 @@
name = UIChatCreateCollectionViewCell.xib;
sourceTree = "";
};
+ C66B03BD26E8EB1A009B5EDC /* UIChatReplyBubbleView.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ C66B03BC26E8EB1A009B5EDC /* Base */,
+ C66B03C126E8EB82009B5EDC /* en */,
+ C66B03C326E8EB87009B5EDC /* fr */,
+ );
+ name = UIChatReplyBubbleView.xib;
+ sourceTree = "";
+ };
D37EE11016035793003608A6 /* ImageView.xib */ = {
isa = PBXVariantGroup;
children = (
@@ -4997,7 +5059,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.11+950fc62\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.50+724b895\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5120,7 +5182,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.11+950fc62\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.50+724b895\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5242,7 +5304,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.11+950fc62\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.50+724b895\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5363,7 +5425,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.11+950fc62\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.50+724b895\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;