diff --git a/Classes/AppManager.swift b/Classes/AppManager.swift
index d1987e746..9a86a02e9 100644
--- a/Classes/AppManager.swift
+++ b/Classes/AppManager.swift
@@ -64,4 +64,16 @@ enum NetworkType: Int {
//The recording prefix is used to identify recordings in the cache directory.
//We will use name_dayName-day-monthName-year to separate recordings by days, then hour-minutes-seconds to order them in each day.
}
+
+ @objc static func removeFile(file: String) {
+ let fileManager = FileManager.default
+ do {
+ try fileManager.removeItem(atPath: file)
+ Log.directLog(BCTBX_LOG_MESSAGE, text: "File :\(file) removed")
+
+ } catch {
+ print("Could not remove file : \(file) \(error)")
+ }
+ }
+
}
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 e321384a1..446b483da 100644
--- a/Classes/Base.lproj/ChatConversationView.xib
+++ b/Classes/Base.lproj/ChatConversationView.xib
@@ -31,12 +31,22 @@
+
+
+
+
+
+
+
+
+
+
@@ -209,7 +219,7 @@
-
+
@@ -221,7 +231,7 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -313,6 +388,11 @@
+
+
+
+
+
@@ -551,8 +631,21 @@
+
-
+
@@ -637,10 +730,14 @@
-
+
+
+
+
+
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/CallManager.swift b/Classes/CallManager.swift
index f6458e9cc..93e998212 100644
--- a/Classes/CallManager.swift
+++ b/Classes/CallManager.swift
@@ -651,9 +651,31 @@ import AVFoundation
}
}
+ // Audio messages
+
+ @objc func activateAudioSession() {
+ lc?.activateAudioSession(actived: true)
+ }
+
+ @objc func getSpeakerSoundCard() -> String? {
+ var speakerCard: String? = nil
+ var earpieceCard: String? = nil
+ lc?.audioDevices.forEach { device in
+ if (device.hasCapability(capability: .CapabilityPlay)) {
+ if (device.type == .Speaker) {
+ speakerCard = device.id
+ } else if (device.type == .Earpiece) {
+ earpieceCard = device.id
+ }
+ }
+ }
+ return speakerCard != nil ? speakerCard : earpieceCard
+ }
+
+
// Conference
-
+
@objc func hostConference() -> Bool {
return conference != nil
}
@@ -748,7 +770,9 @@ import AVFoundation
guard let core = lc else {
return false
}
- return isInConference() && (getConference()?.currentParams?.isVideoEnabled == true || core.currentCall?.currentParams?.videoEnabled == true)
+ let result = isInConference() && (getConference()?.currentParams?.isVideoEnabled == true || core.currentCall?.currentParams?.videoEnabled == true)
+ NSLog("cdes \(result) \(core.currentCall?.currentParams?.videoEnabled)")
+ return result
}
diff --git a/Classes/CallView.m b/Classes/CallView.m
index 712ebffc6..2ae10de87 100644
--- a/Classes/CallView.m
+++ b/Classes/CallView.m
@@ -683,9 +683,8 @@ static void hideSpinner(LinphoneCall *call, void *user_data) {
#pragma mark - ActionSheet Functions
- (void)displayAskToEnableVideoCall:(LinphoneCall *)call {
- if (linphone_call_params_get_local_conference_mode(linphone_call_get_current_params(call))) {
- return;
- } else if (CallManager.instance.inVideoConf) {
+
+ if (CallManager.instance.inVideoConf) { // we are hosting a video conf, so just accept people wanting to activate video.
LinphoneCallParams *params = linphone_core_create_call_params(LC, call);
linphone_call_params_enable_video(params, TRUE);
linphone_call_accept_update(call, params);
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 3fb5e83be..1fe9ff3e2 100644
--- a/Classes/ChatConversationTableView.h
+++ b/Classes/ChatConversationTableView.h
@@ -39,10 +39,10 @@
@protocol ChatConversationDelegate
-- (BOOL)resendMultiFiles:(FileContext *)newFileContext message:(NSString *)message;
-- (BOOL)resendFile:(NSData *)data withName:(NSString *)name type:(NSString *)type key:(NSString *)key message:(NSString *)message;
-- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name;
-- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url;
+- (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 026115094..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);
diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h
index 06bb89c17..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"
@@ -49,7 +50,7 @@
@interface ChatConversationView
: TPMultiLayoutViewController {
+ UIDocumentInteractionControllerDelegate, UISearchBarDelegate, UIImageViewDeletableDelegate,QLPreviewControllerDelegate, UICollectionViewDataSource,UICollectionViewDelegate,UIDocumentMenuDelegate,UIDocumentPickerDelegate,UITableViewDataSource, UITableViewDelegate> {
OrderedDictionary *imageQualities;
BOOL scrollOnGrowingEnabled;
BOOL composingVisible;
@@ -92,6 +93,36 @@
@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleMenuButton;
@property (weak, nonatomic) IBOutlet UIImageView *ephemeralndicator;
+
+// Voice recording
+@property (strong, nonatomic) IBOutlet UIView *vrView;
+@property (weak, nonatomic) IBOutlet UIView *vrInnerView;
+@property (weak, nonatomic) IBOutlet UIButton *vrDeleteButton;
+@property (weak, nonatomic) IBOutlet UIButton *vrPlayButton;
+@property (weak, nonatomic) IBOutlet UIImageView *vrWave;
+@property (weak, nonatomic) IBOutlet UIView *vrWaveMask;
+@property (weak, nonatomic) IBOutlet UIView *vrWaveMaskPlayer;
+@property (weak, nonatomic) IBOutlet UILabel *vrDurationLabel;
+@property NSTimer *vrRecordTimer;
+@property NSTimer *vrPlayerTimer;
+@property (weak, nonatomic) IBOutlet UIButton *toggleRecord;
+@property BOOL isVoiceRecording;
+@property BOOL isPendingVoiceRecord;
+@property BOOL isPlayingVoiceRecording;
+@property LinphoneRecorder *voiceRecorder;
+@property LinphonePlayer *sharedVoicePlayer;
+@property BOOL showVoiceRecorderView;
+@property BOOL preservePendingActions;
+
+// Reply
+@property (weak, nonatomic) IBOutlet UIView *replyView;
+@property BOOL showReplyView;
+@property UIChatReplyBubbleView *replyBubble;
+
+// Forward
+@property LinphoneChatMessage *pendingForwardMessage;
+
+
+ (void)markAsRead:(LinphoneChatRoom *)chatRoom;
+ (void)autoDownload:(LinphoneChatMessage *)message;
+(NSString *)getKeyFromFileType:(NSString *)fileType fileName:(NSString *)name;
@@ -123,4 +154,10 @@
- (NSURL *)getICloudFileUrl:(NSString *)name;
- (void)removeCallBacks;
+-(void) startSharedPlayer:(const char *)path;
+-(void) stopSharedPlayer;
+-(BOOL) sharedPlayedIsPlaying:(const char *)path;
+
+-(void) initiateReplyViewForMessage:(LinphoneChatMessage *)message;
+
@end
diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m
index bfdca00f3..0a4517f9b 100644
--- a/Classes/ChatConversationView.m
+++ b/Classes/ChatConversationView.m
@@ -120,6 +120,7 @@
[NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil),
[NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil];
composingVisible = false;
+ [self initSharedPlayer];
}
return self;
}
@@ -136,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
@@ -186,7 +187,14 @@ static UICompositeViewDescription *compositeDescription = nil;
[_tableController setChatRoomDelegate:self];
[_imagesCollectionView registerClass:[UIImageViewDeletable class] forCellWithReuseIdentifier:NSStringFromClass([UIImageViewDeletable class])];
[_imagesCollectionView setDataSource:self];
+ [_imagesCollectionView setDelegate:self];
[_toggleSelectionButton setImage:[UIImage imageNamed:@"select_all_default.png"] forState:UIControlStateSelected];
+
+ _vrInnerView.layer.cornerRadius = 5.0f;
+ _vrInnerView.layer.masksToBounds = YES;
+ _vrWaveMaskPlayer.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"color_L"]]; // rgba(1,88,7,0.2);
+ _showVoiceRecorderView = false;
+
}
- (void)refreshData {
@@ -202,6 +210,10 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(applicationWillEnterBackground)
+ name:UIApplicationDidEnterBackgroundNotification
+ object:nil];
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
@@ -222,6 +234,16 @@ static UICompositeViewDescription *compositeDescription = nil;
selector:@selector(onLinphoneCoreReady:)
name:kLinphoneGlobalStateUpdate
object:nil];
+
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(endVoicePlayingIfDoingSO:)
+ name:kLinphoneVoiceMessagePlayerLostFocus
+ object:nil];
+
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(endVoicePlayingIfDoingSO:)
+ name:kLinphoneVoiceMessagePlayerEOF
+ object:nil];
if ([_fileContext count] > 0) {
[UIView animateWithDuration:0
delay:0
@@ -229,13 +251,14 @@ static UICompositeViewDescription *compositeDescription = nil;
animations:^{
// resizing imagesView
CGRect imagesFrame = [_imagesView frame];
- imagesFrame.origin.y = [_messageView frame].origin.y - 100;
- imagesFrame.size.height = 100;
+ imagesFrame.origin.y = [_messageView frame].origin.y - 120;
+ imagesFrame.size.height = 120;
[_imagesView setFrame:imagesFrame];
// resizing chatTable
CGRect tableViewFrame = [_tableController.tableView frame];
- tableViewFrame.size.height -= 100;
+ tableViewFrame.size.height -= 120;
[_tableController.tableView setFrame:tableViewFrame];
+ [self updateFramesInclRecordingAndReplyView];
}
completion:nil];
}
@@ -245,10 +268,30 @@ static UICompositeViewDescription *compositeDescription = nil;
CGRect popupFrame = _popupMenu.frame;
popupFrame.size.height = 44 * [_popupMenu numberOfRowsInSection:0];
_popupMenu.frame = popupFrame;
+
+ // Voice recording & Replies
+ _vrView.hidden = true;
+ _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 (!_preservePendingActions)
+ [self cancelVoiceRecording];
+
+ if (!_preservePendingActions)
+ [self closePendingReply];
+
+
+
+ else if (_isVoiceRecording)
+ [self stopVoiceRecording];
+
[super viewWillDisappear:animated];
[self removeCallBacks];
@@ -256,7 +299,9 @@ static UICompositeViewDescription *compositeDescription = nil;
[_messageField resignFirstResponder];
[self setComposingVisible:false withDelay:0]; // will hide the "user is composing.." message
-
+
+ [self stopAllPlays];
+
[NSNotificationCenter.defaultCenter removeObserver:self];
PhoneMainView.instance.currentRoom = NULL;
}
@@ -287,10 +332,24 @@ static UICompositeViewDescription *compositeDescription = nil;
_backButton.hidden = _tableController.isEditing;
[_tableController scrollToBottom:true];
[self refreshImageDrawer];
+ [self stopAllPlays];
+
}
#pragma mark -
+- (void)applicationWillEnterBackground{
+ if (!_preservePendingActions)
+ [self cancelVoiceRecording];
+ else if (_isVoiceRecording)
+ [self stopVoiceRecording];
+ if (!_preservePendingActions)
+ [self closePendingReply];
+ [self stopAllPlays];
+
+}
+
+
- (void)configureForRoom:(BOOL)editing {
if (!_chatRoom) {
_chatView.hidden = YES;
@@ -347,6 +406,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[self setupPopupMenu];
_ephemeralndicator.hidden = !linphone_chat_room_ephemeral_enabled(_chatRoom);
}
+ [self handlePendingTransferIfAny];
}
@@ -374,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];
@@ -382,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"];
@@ -429,6 +490,9 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)callUpdateEvent:(NSNotification *)notif {
[self updateSuperposedButtons];
+ _toggleRecord.enabled = linphone_core_get_calls_nb(LC) == 0;
+ [_tableController.tableView reloadData];
+
}
- (void)update {
@@ -456,17 +520,20 @@ static UICompositeViewDescription *compositeDescription = nil;
}
}
-- (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL *)externalUrl {
+- (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_message(_chatRoom, [message UTF8String]);
+ LinphoneChatMessage *msg = rootMessage;
+ if (message && message.length > 0)
+ linphone_chat_message_add_utf8_text_content(msg, message.UTF8String);
+
if (externalUrl) {
linphone_chat_message_set_external_body_url(msg, [[externalUrl absoluteString] UTF8String]);
}
-
+
// we must ref & unref message because in case of error, it will be destroy otherwise
linphone_chat_message_send(msg);
@@ -509,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 sendMessageInMessageField];
+ [self sendMessageInMessageField:linphone_chat_room_create_empty_message(_chatRoom)];
}
if (url)
- [self sendMessage:url withExterlBodyUrl: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];
@@ -600,8 +667,8 @@ static UICompositeViewDescription *compositeDescription = nil;
_addressLabel.frame = frame;
}
-- (void)sendMessageInMessageField {
- if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil]) {
+- (void)sendMessageInMessageField:(LinphoneChatMessage *)rootMessage {
+ if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil rootMessage:rootMessage]) {
scrollOnGrowingEnabled = FALSE;
[_messageField setText:@""];
scrollOnGrowingEnabled = TRUE;
@@ -657,6 +724,7 @@ static UICompositeViewDescription *compositeDescription = nil;
CGRect tableRect = [_tableController.view frame];
tableRect.size.height -= diff;
[_tableController.view setFrame:tableRect];
+ [self updateFramesInclRecordingAndReplyView];
// if we're showing the compose message, update it position
if (![_composeLabel isHidden]) {
@@ -681,28 +749,48 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onSendClick:(id)event {
+
+ 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)) {
+ LinphoneContent * voiceContent = linphone_recorder_create_content(_voiceRecorder);
+ _isPendingVoiceRecord = false;
+ [self cancelVoiceRecording];
+ [self stopVoiceRecordPlayer];
+ linphone_chat_message_add_content(rootMessage, voiceContent);
+ }
+
if ([_fileContext count] > 0) {
if (linphone_chat_room_get_capabilities(_chatRoom) & LinphoneChatRoomCapabilitiesConference) {
- [self startMultiFilesUpload];
+ [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];
+ [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];
+ [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];
+ [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]];
+ [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 sendMessageInMessageField];
+ [self sendMessageInMessageField:rootMessage];
}
- (IBAction)onListTap:(id)sender {
@@ -759,14 +847,11 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onMessageChange:(id)sender {
- if ([[_messageField text] length] > 0) {
- [_sendButton setEnabled:TRUE];
- } else {
- [_sendButton setEnabled:FALSE];
- }
+ [self setSendButtonState];
}
- (IBAction)onPictureClick:(id)event {
+ _preservePendingActions = true;
[_messageField resignFirstResponder];
[ImagePickerView SelectImageFromDevice:self atPosition:_pictureButton inView:self.view withDocumentMenuDelegate:self];
@@ -800,15 +885,15 @@ static UICompositeViewDescription *compositeDescription = nil;
#pragma mark ChatRoomDelegate
-- (BOOL)startMultiFilesUpload {
+- (BOOL)startMultiFilesUpload:(LinphoneChatMessage *)rootMessage {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
[fileTransfer setText:[self.messageField text]];
- [fileTransfer uploadFileContent:_fileContext forChatRoom:_chatRoom];
+ [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 {
+- (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];
@@ -818,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];
+ [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 {
+- (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];
+ [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 {
+- (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];
+ [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 {
- [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url]];
+- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url rootMessage:(LinphoneChatMessage *)rootMessage {
+ [self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] rootMessage:rootMessage];
}
#pragma mark ImagePickerDelegate
@@ -1077,6 +1162,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[_messageView frame].origin.y - tableFrame.origin.y - composeIndicatorCompensation;
[_tableController.view setFrame:tableFrame];
+
// Scroll to bottom
NSInteger lastSection = [_tableController.tableView numberOfSections] - 1;
if (lastSection >= 0) {
@@ -1102,9 +1188,14 @@ static UICompositeViewDescription *compositeDescription = nil;
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
[_tableController.tableView setFrame:tableViewFrame];
}
+ if (_showVoiceRecorderView)
+ _vrView.hidden = true; // force recalculate
+ if (_showReplyView)
+ _replyView.hidden = true; // force recalculate
+ [self updateFramesInclRecordingAndReplyView];
+
}
completion:^(BOOL finished){
-
}];
}
@@ -1158,6 +1249,7 @@ static UICompositeViewDescription *compositeDescription = nil;
tableFrame.size.height =
[_messageView frame].origin.y - tableFrame.origin.y - composeIndicatorCompensation;
[_tableController.view setFrame:tableFrame];
+
}
if ([_fileContext count] > 0){
@@ -1170,6 +1262,7 @@ static UICompositeViewDescription *compositeDescription = nil;
CGRect tableViewFrame = [_tableController.tableView frame];
tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
[_tableController.tableView setFrame:tableViewFrame];
+
}
// Scroll
@@ -1183,10 +1276,15 @@ static UICompositeViewDescription *compositeDescription = nil;
animated:FALSE];
}
}
+ if (_showVoiceRecorderView)
+ _vrView.hidden = true; // force recalculate
+ if (_showReplyView)
+ _replyView.hidden = true; // force recalculate
+ [self updateFramesInclRecordingAndReplyView];
+
}
completion:^(BOOL finished){
-
}];
}
@@ -1381,26 +1479,31 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
return [_fileContext count];
}
+
+- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
+ return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? CGSizeMake(60, 60) : CGSizeMake(120, 120);
+}
+
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UIImageViewDeletable *imgView = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UIImageViewDeletable class]) forIndexPath:indexPath];
CGRect imgFrame = imgView.frame;
imgFrame.origin.y = 5;
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
- imgFrame.size.height = 50;
+ imgFrame.size.height = 60;
} else {
- imgFrame.size.height = 100;
+ imgFrame.size.height = 120;
}
[imgView.image setImage:[UIImage resizeImage:[_fileContext.previewsArray objectAtIndex:[indexPath item]] withMaxWidth:imgFrame.size.width andMaxHeight:imgFrame.size.height]];
[imgView setUuid:[_fileContext.uuidsArray objectAtIndex:[indexPath item]]];
[imgView setDeleteDelegate:self];
[imgView setFrame:imgFrame];
- [_sendButton setEnabled:TRUE];
+ [self setSendButtonState];
return imgView;
}
- (void)refreshImageDrawer {
- int heightDiff = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 55 : 105;
+ int heightDiff = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 65 : 125;
if ([_fileContext count] == 0) {
[UIView animateWithDuration:0
@@ -1416,10 +1519,10 @@ 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 updateFramesInclRecordingAndReplyView];
}
completion:nil];
- if ([_messageField.text isEqualToString:@""])
- [_sendButton setEnabled:FALSE];
+ [self setSendButtonState];
} else {
// resizing imagesView
CGRect imagesFrame = [_imagesView frame];
@@ -1430,6 +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 updateFramesInclRecordingAndReplyView];
[_imagesCollectionView reloadData];
}
}
@@ -1488,7 +1592,7 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
NSFileCoordinator *co =[[NSFileCoordinator alloc] init];
NSError *error = nil;
[co coordinateReadingItemAtURL:url options:0 error:&error byAccessor:^(NSURL * _Nonnull newURL) {
- UIImage *image = [ChatConversationView drawText:[newURL lastPathComponent] image:[ChatConversationView getBasicImage] textSize:10];
+ UIImage *image = [UIChatBubbleTextCell getImageFromFileName:[newURL lastPathComponent]];
[_fileContext addObject:[NSData dataWithContentsOfURL:newURL] name:[newURL lastPathComponent] type:@"file" image:image];
[self refreshImageDrawer];
}];
@@ -1592,4 +1696,322 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog
}
+// Voice redcording
+
+
+- (IBAction)onVrDelete:(id)sender {
+ [self cancelVoiceRecording];
+ [self stopVoiceRecordPlayer];
+}
+
+- (IBAction)onvrPlayPauseStop:(id)sender {
+ if (_isVoiceRecording) {
+ [self stopVoiceRecording];
+ } else {
+ if (_isPlayingVoiceRecording)
+ [self stopVoiceRecordPlayer];
+ else
+ [self playRecordedMessage];
+ }
+}
+
+- (IBAction)onVrStart:(id)sender {
+ if (_isVoiceRecording) {
+ [self stopVoiceRecording];
+ } else {
+ [self startVoiceRecording];
+ }
+}
+
+-(void) createVoiceRecorder {
+ LinphoneRecorderParams *p = linphone_core_create_recorder_params(LC);
+ linphone_recorder_params_set_file_format(p, LinphoneRecorderFileFormatWav);
+ _voiceRecorder = linphone_core_create_recorder(LC, p);
+}
+
+-(void) cancelVoiceRecording {
+ _showVoiceRecorderView = false;
+ _toggleRecord.selected = false;
+ [self updateFramesInclRecordingAndReplyView];
+ _isPendingVoiceRecord = false;
+ _isVoiceRecording = false;
+ if (_voiceRecorder && linphone_recorder_get_state(_voiceRecorder) != LinphoneRecorderClosed) {
+ linphone_recorder_close(_voiceRecorder);
+ const char *recordingFile = linphone_recorder_get_file(_voiceRecorder);
+ if (recordingFile) {
+ [AppManager removeFileWithFile:[NSString stringWithUTF8String:recordingFile]];
+ }
+ }
+ [self setSendButtonState];
+}
+
+-(void) stopVoiceRecording {
+ if (_voiceRecorder && linphone_recorder_get_state(_voiceRecorder) == LinphoneRecorderRunning) {
+ LOGI(@"[Chat Message Sending] Pausing / closing voice recorder");
+ linphone_recorder_pause(_voiceRecorder);
+ linphone_recorder_close(_voiceRecorder);
+ _vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
+ }
+ _isVoiceRecording = false;
+ if ([LinphoneManager.instance lpConfigBoolForKey:@"voice_recording_send_right_away" withDefault:false]) {
+ [self onSendClick:nil];
+ }
+ [_vrPlayButton setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
+ _toggleRecord.selected = false;
+ _vrWaveMask.frame = CGRectZero;
+ [_vrRecordTimer invalidate];
+ _isPendingVoiceRecord = linphone_recorder_get_duration(_voiceRecorder) > 0;
+ [self setSendButtonState];
+
+}
+
+-(void) startVoiceRecording {
+
+ if (!_voiceRecorder)
+ [self createVoiceRecorder];
+ [CallManager.instance activateAudioSession];
+ _toggleRecord.selected = true;
+ [_vrPlayButton setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
+
+
+ _showVoiceRecorderView = true;
+ [self updateFramesInclRecordingAndReplyView];
+ _isVoiceRecording = true;
+ _vrWaveMaskPlayer.frame = CGRectZero;
+
+ switch (linphone_recorder_get_state(_voiceRecorder)) {
+ case LinphoneRecorderClosed: {
+ NSString *filename = [NSString stringWithFormat:@"%@/voice-recording-%@.wav",[LinphoneManager imagesDirectory], [NSUUID UUID].UUIDString];
+ linphone_recorder_open(_voiceRecorder, filename.UTF8String);
+ linphone_recorder_start(_voiceRecorder);
+ LOGW(@"[Chat Message Sending] Recorder is closed opening it with %@",filename);
+ break;
+ };
+ case LinphoneRecorderRunning: {
+ LOGW(@"[Chat Message Sending] Recorder is already recording");
+ break;
+ }
+ case LinphoneRecorderPaused: {
+ LOGW(@"[Chat Message Sending] Recorder isn't closed, resuming recording");
+ linphone_recorder_start(_voiceRecorder);
+ }
+ }
+ _vrWaveMask.frame = _vrWave.frame;
+ _vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
+ _vrRecordTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
+ target:self
+ selector:@selector(voiceRecordTimerUpdate)
+ userInfo:nil
+ repeats:YES];
+
+
+}
+
+-(void) voiceRecordTimerUpdate {
+ int recorderDuration = linphone_recorder_get_duration(_voiceRecorder);
+ if (recorderDuration > [LinphoneManager.instance lpConfigIntForKey:@"voice_recording_max_duration" withDefault:60000]) {
+ LOGW(@"[Chat Message Sending] Max duration for voice recording exceeded, stopping. (max = %d)",[LinphoneManager.instance lpConfigIntForKey:@"voice_recording_max_duration" withDefault:60000]);
+ [self stopVoiceRecording];
+ } else {
+ _vrDurationLabel.text = [self formattedDuration:linphone_recorder_get_duration(_voiceRecorder)];
+ CGRect r = _vrWaveMask.frame;
+ r.origin.x += 30;
+ r.size.width -= 30;
+ if (r.origin.x > _vrWave.frame.size.width) {
+ r = _vrWave.frame;
+ _vrWaveMask.frame = r;
+ } else {
+ [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ _vrWaveMask.frame = r;
+ }completion:^(BOOL finished) {}];
+ }
+ }
+}
+
+// Playback Shared Player (new recording & chat bubble)
+
+- (void) initSharedPlayer {
+ LOGI(@"[Voice Message] Creating shared player");
+ _sharedVoicePlayer = linphone_core_create_local_player(LC, [CallManager.instance getSpeakerSoundCard].UTF8String, nil, nil);
+ LinphonePlayerCbs *cbs = linphone_factory_create_player_cbs(linphone_factory_get());
+ linphone_player_cbs_set_eof_reached(cbs, on_shared_player_eof_reached);
+ linphone_player_cbs_set_user_data(cbs, (__bridge void*)self);
+ linphone_player_add_callbacks(_sharedVoicePlayer, cbs);
+}
+
+-(void) startSharedPlayer:(const char *)path {
+ LOGI(@"[Voice Message] Starting shared player path = %s",path);
+ if (linphone_player_get_user_data(_sharedVoicePlayer)) {
+ LOGI(@"[Voice Message] a play was requested (%s), but there is already one going (%s)",path,(const char *)linphone_player_get_user_data(_sharedVoicePlayer) );
+ NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:linphone_player_get_user_data(_sharedVoicePlayer)]};
+ [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerLostFocus object:nil userInfo:userInfo];
+ }
+ [CallManager.instance changeRouteToSpeaker];
+ linphone_player_set_user_data(_sharedVoicePlayer, (void *)path);
+ linphone_player_open(_sharedVoicePlayer, path);
+ linphone_player_start(_sharedVoicePlayer);
+}
+
+-(void) stopSharedPlayer {
+ LOGI(@"[Voice Message] Stopping shared player path = %s",linphone_player_get_user_data(_sharedVoicePlayer) ? (const char *)linphone_player_get_user_data(_sharedVoicePlayer) : "nil");
+ linphone_player_pause(_sharedVoicePlayer);
+ linphone_player_seek(_sharedVoicePlayer,0);
+ linphone_player_close(_sharedVoicePlayer);
+ linphone_player_set_user_data(_sharedVoicePlayer, nil);
+}
+
+-(BOOL) sharedPlayedIsPlaying:(const char *)path {
+ return path && linphone_player_get_user_data(_sharedVoicePlayer) && !strcmp(path,linphone_player_get_user_data(_sharedVoicePlayer));
+}
+
+void on_shared_player_eof_reached(LinphonePlayer *p) {
+ LOGI(@"[Voice Message] End of file reached for player");
+ const char * currentPlayedFile = (const char *) linphone_player_get_user_data(p);
+ if (currentPlayedFile) {
+ NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:currentPlayedFile]};
+ [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerEOF object:nil userInfo:userInfo];
+ }
+}
+
+// Playback of new recordings
+
+-(void) playRecordedMessage {
+ [_vrPlayButton setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
+ _vrDurationLabel.text = [self formattedDuration:linphone_player_get_duration(_sharedVoicePlayer)];
+ _vrWaveMask.frame = CGRectZero;
+ CGRect r = CGRectZero;
+ r.size.height = _vrInnerView.frame.size.height;
+ _vrWaveMaskPlayer.frame = r;
+ _vrPlayerTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
+ target:self
+ selector:@selector(voicePlayTimerUpdate)
+ userInfo:nil
+ repeats:YES];
+ [self startSharedPlayer:linphone_recorder_get_file(_voiceRecorder)];
+ [self animPlayerOnce];
+ _isPlayingVoiceRecording = true;
+}
+
+-(void) voicePlayTimerUpdate {
+ _vrDurationLabel.text = [self formattedDuration:linphone_player_get_duration(_sharedVoicePlayer)];
+ [self animPlayerOnce];
+}
+
+-(void) animPlayerOnce {
+ CGRect r = _vrWaveMaskPlayer.frame;
+ r.size.width += _vrInnerView.frame.size.width / ((linphone_player_get_duration(_sharedVoicePlayer) / 1000)+1) ;
+ if (r.size.width > _vrInnerView.frame.size.width) {
+ r.size.width = _vrInnerView.frame.size.width;
+ }
+ [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ _vrWaveMaskPlayer.frame = r;
+ }completion:^(BOOL finished) {}];
+}
+
+-(void) endVoicePlayingIfDoingSO:(NSNotification *)notif {
+ if (_isPlayingVoiceRecording)
+ [self stopVoiceRecordPlayer];
+}
+
+-(void) stopVoiceRecordPlayer {
+ [self stopSharedPlayer];
+ [_vrPlayButton setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
+ _isPlayingVoiceRecording = false;
+ [_vrPlayerTimer invalidate];
+ _vrWaveMaskPlayer.frame = CGRectZero;
+}
+
+-(NSString *)formattedDuration:(long)valueMs {
+ return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60000, (valueMs % 60000) / 1000 ];
+}
+
+-(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 (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 {
+ if (linphone_player_get_user_data(_sharedVoicePlayer)) {
+ NSDictionary* userInfo = @{@"path": [NSString stringWithUTF8String:linphone_player_get_user_data(_sharedVoicePlayer)]};
+ [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneVoiceMessagePlayerLostFocus object:nil userInfo:userInfo];
+ }
+}
+
+// send button state
+
+-(void) setSendButtonState {
+ _sendButton.enabled = !_isVoiceRecording && ((_isPendingVoiceRecord && linphone_recorder_get_duration(_voiceRecorder) > 0) || [[_messageField text] length] > 0 || _fileContext.count > 0);
+}
+
+
+// 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/FirstLoginView.m b/Classes/FirstLoginView.m
index f00b1182d..a0d10d0a6 100644
--- a/Classes/FirstLoginView.m
+++ b/Classes/FirstLoginView.m
@@ -200,7 +200,7 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)onLoginClick:(id)sender {
if (!linphone_core_is_network_reachable(LC)) {
- [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
+ [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"configure an account"] animated:YES completion:nil];
return;
}
diff --git a/Classes/KIF b/Classes/KIF
deleted file mode 160000
index 99ae001ae..000000000
--- a/Classes/KIF
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 99ae001ae51f4883d189e3f77544828ec035395d
diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h
index 1054595b7..235caee7c 100644
--- a/Classes/LinphoneManager.h
+++ b/Classes/LinphoneManager.h
@@ -60,6 +60,8 @@ extern NSString *const kLinphoneFileTransferRecvUpdate;
extern NSString *const kLinphoneQRCodeFound;
extern NSString *const kLinphoneChatCreateViewChange;
extern NSString *const kLinphoneEphemeralMessageDeletedInRoom;
+extern NSString *const kLinphoneVoiceMessagePlayerEOF;
+extern NSString *const kLinphoneVoiceMessagePlayerLostFocus;
extern NSString *const kLinphoneConfStateParticipantListChanged;
extern NSString *const kLinphoneConfStateChanged;
diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m
index eaa693fca..3de5afe82 100644
--- a/Classes/LinphoneManager.m
+++ b/Classes/LinphoneManager.m
@@ -75,6 +75,8 @@ NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpda
NSString *const kLinphoneQRCodeFound = @"LinphoneQRCodeFound";
NSString *const kLinphoneChatCreateViewChange = @"LinphoneChatCreateViewChange";
NSString *const kLinphoneEphemeralMessageDeletedInRoom = @"LinphoneEphemeralMessageDeletedInRoom";
+NSString *const kLinphoneVoiceMessagePlayerEOF = @"LinphoneVoiceMessagePlayerEOF";
+NSString *const kLinphoneVoiceMessagePlayerLostFocus = @"LinphoneVoiceMessagePlayerLostFocus";
NSString *const kLinphoneConfStateChanged = @"kLinphoneConfStateChanged";
NSString *const kLinphoneConfStateParticipantListChanged = @"kLinphoneConfStateParticipantListChanged";
@@ -1801,6 +1803,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
return;
if (linphone_core_local_permission_enabled(LC)) return;
+
if (![defaults boolForKey: alertSuppressionKey]) {
UIAlertController *noticeView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Local network usage", nil)
@@ -1825,7 +1828,7 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
- (void)call:(const LinphoneAddress *)iaddr {
// First verify that network is available, abort otherwise.
if (!linphone_core_is_network_reachable(theLinphoneCore)) {
- [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
+ [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"place a call"] animated:YES completion:nil];
return;
}
@@ -2270,10 +2273,7 @@ void conference_device_changed(LinphoneConference *conference, const LinphonePar
void linphone_iphone_conference_state_changed(LinphoneCore *lc, LinphoneConference *conf,LinphoneConferenceState state) {
if (state == LinphoneConferenceStateCreated) {
- LinphoneConferenceCbs * cbs = linphone_conference_get_current_callbacks(conf);
- if (!cbs) {
- cbs = linphone_factory_create_conference_cbs(linphone_factory_get());
- }
+ LinphoneConferenceCbs * cbs = linphone_factory_create_conference_cbs(linphone_factory_get());
linphone_conference_cbs_set_participant_added(cbs, conference_participant_changed);
linphone_conference_cbs_set_participant_device_added(cbs, conference_device_changed);
linphone_conference_cbs_set_participant_device_removed(cbs, conference_device_changed);
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
index d320d6580..8cae658dc 100644
--- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
@@ -29,15 +29,21 @@
+
-
-
+
+
+
+
+
+
+
-
+
@@ -57,134 +63,182 @@
-
+
+
+
+
+
+
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -192,21 +246,11 @@
-
-
-
-
-
-
-
-
-
-
@@ -217,5 +261,8 @@
+
+
+
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 @@
-
+
-
+
-
+
-
-
+
-
-
+
+
-
+
+
diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.h b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
index 43b6b6eed..49555feaa 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.h
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
@@ -41,9 +41,18 @@
@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
+@property (weak, nonatomic) IBOutlet UIView *vrView;
+@property (weak, nonatomic) IBOutlet UIButton *vrPlayPause;
+@property (weak, nonatomic) IBOutlet UILabel *vrTimerLabel;
+@property (weak, nonatomic) IBOutlet UIImageView *vrWave;
+@property (weak, nonatomic) IBOutlet UIView *vrWaveMaskPlayback;
+@property NSTimer *vrPlayerTimer;
+@property NSString *voiceRecordingFile;
+
+
- (void)setEvent:(LinphoneEventLog *)event;
- (void)setChatMessage:(LinphoneChatMessage *)message;
@@ -51,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 d96ae3cb2..f94ea00d7 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m
@@ -26,6 +26,13 @@
#import
#import
+#define voicePlayer VIEW(ChatConversationView).sharedVoicePlayer
+#define chatView VIEW(ChatConversationView)
+#define FILE_ICON_TAG 0
+#define REALIMAGE_TAG 1
+
+
+
@implementation UIChatBubblePhotoCell {
FileTransferDelegate *_ftd;
CGSize imageSize, bubbleSize, videoDefaultSize;
@@ -54,6 +61,13 @@
assetIsLoaded = FALSE;
self.contentView.userInteractionEnabled = NO;
_contentViews = [[NSMutableArray alloc] init];
+
+
+ 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;
}
@@ -73,7 +87,6 @@
- (void)setChatMessage:(LinphoneChatMessage *)amessage {
_imageGestureRecognizer.enabled = NO;
- _plusLongGestureRecognizer.enabled = NO;
_messageImageView.image = nil;
_finalImage.image = nil;
_finalImage.hidden = TRUE;
@@ -98,6 +111,7 @@
}
- (void) loadImageAsset:(PHAsset*) asset image:(UIImage *)image {
+ _finalImage.tag = REALIMAGE_TAG;
dispatch_async(dispatch_get_main_queue(), ^{
[_finalImage setImage:image];
[_messageImageView setAsset:asset];
@@ -105,7 +119,6 @@
_messageImageView.hidden = YES;
_finalImage.hidden = NO;
_fileView.hidden = YES;
- _plusLongGestureRecognizer.enabled = YES;
[self layoutSubviews];
});
}
@@ -127,14 +140,10 @@
}
- (void) loadFileAsset:(NSString *)name {
- NSString *text = [NSString stringWithFormat:@"📎 %@",name];
- _fileName.text = text;
- dispatch_async(dispatch_get_main_queue(), ^{
- _fileName.hidden = _fileView.hidden = _fileButton.hidden = NO;
- _imageGestureRecognizer.enabled = NO;
- _plusLongGestureRecognizer.enabled = NO;
- _playButton.hidden = YES;
- });
+ UIImage *image = [UIChatBubbleTextCell getImageFromFileName:name];
+ [self loadImageAsset:nil image:image];
+ _imageGestureRecognizer.enabled = YES;
+ _finalImage.tag = FILE_ICON_TAG;
}
- (void) loadPlaceholder {
@@ -145,38 +154,63 @@
[_messageImageView stopLoading];
_messageImageView.hidden = YES;
_imageGestureRecognizer.enabled = YES;
- _plusLongGestureRecognizer.enabled = YES;
_finalImage.hidden = NO;
[self layoutSubviews];
});
}
+
- (void)update {
if (self.message == nil) {
LOGW(@"Cannot update message room cell: NULL message");
return;
}
[super update];
+
+ _vrPlayPause.enabled = linphone_core_get_calls_nb(LC) == 0;
+
+ NSMutableDictionary *encrptedFilePaths = NULL;
+ if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) {
+ encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:self.message];
+ if (!encrptedFilePaths) {
+ encrptedFilePaths = [NSMutableDictionary dictionary];
+ }
+ }
+
+ _voiceRecordingFile = nil;
+ LinphoneContent *voiceContent = [UIChatBubbleTextCell voiceContent:self.message];
+ if (voiceContent) {
+ _voiceRecordingFile = [NSString stringWithUTF8String:[VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] ? linphone_content_get_plain_file_path(voiceContent) : linphone_content_get_file_path(voiceContent)];
+ if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId])
+ [encrptedFilePaths setValue:_voiceRecordingFile forKey:[NSString stringWithUTF8String:linphone_content_get_name(voiceContent)]];
+ [self setVoiceMessageDuration];
+ _vrWaveMaskPlayback.frame = CGRectZero;
+ _vrWaveMaskPlayback.backgroundColor = linphone_chat_message_is_outgoing(self.message) ? UIColor.orangeColor : UIColor.grayColor;
+ }
+
const bctbx_list_t *contents = linphone_chat_message_get_contents(self.message);
+
+ size_t contentCount = bctbx_list_size(contents);
+ if (voiceContent)
+ contentCount--;
BOOL multiParts = ((linphone_chat_message_get_text_content(self.message) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 1);
+ if (voiceContent && !multiParts) {
+ _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES;
+ return;
+ }
+
if (multiParts) {
if (!assetIsLoaded) {
- NSMutableDictionary *encrptedFilePaths = NULL;
- if ([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId]) {
- encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:self.message];
- if (!encrptedFilePaths) {
- encrptedFilePaths = [NSMutableDictionary dictionary];
- }
- }
-
_imageGestureRecognizer.enabled = NO;
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = _fileView.hidden = _fileButton.hidden = YES;
-
const bctbx_list_t *it = contents;
int i;
for (it = contents, i=0; it != NULL; it=bctbx_list_next(it)){
LinphoneContent *content = (LinphoneContent *)it->data;
+ if (linphone_content_is_voice_recording(content)) { // Handled elsewhere
+ continue;
+ }
if (linphone_content_is_file_transfer(content) || linphone_content_is_file(content)){
UIChatContentView *contentView = [[UIChatContentView alloc] initWithFrame: CGRectMake(0,0,0,0)];
if([VFSUtil vfsEnabledWithGroupName:kLinphoneMsgNotificationAppGroupId] && (linphone_chat_message_is_outgoing(self.message) || linphone_content_is_file(content))) {
@@ -214,8 +248,6 @@
return;
}
-
-
const char *url = linphone_chat_message_get_external_body_url(self.message);
BOOL is_external =
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(self.message);
@@ -241,10 +273,15 @@
_playButton.hidden = YES;
_fileName.hidden = _fileView.hidden = _fileButton.hidden =YES;
} else {
- _downloadButton.hidden = NO;
+ _downloadButton.hidden = YES;
+ UIChatContentView * contentView = [[UIChatContentView alloc] init];
+ [contentView setContent:fileContent message:self.message];
+ contentView.position = 0;
+ [_contentViews addObject:contentView];
_cancelButton.hidden = _fileTransferProgress.hidden = YES;
_playButton.hidden = YES;
_fileName.hidden = _fileView.hidden = _fileButton.hidden = YES;
+ [self layoutSubviews];
}
return;
}
@@ -464,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);
@@ -510,21 +528,15 @@
}
}
-- (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) {
+ [self onFileClick:nil];
+ return;
+ }
LinphoneChatMessageState state = linphone_chat_message_get_state(self.message);
if (state == LinphoneChatMessageStateNotDelivered) {
- [self onResendClick:event];
+ return;
} else {
if (![_messageImageView isLoading]) {
ImageView *view = VIEW(ImageView);
@@ -662,7 +674,7 @@
CGFloat max_imagesh=0;
CGFloat max_imagesw=0;
CGFloat originy=0;
- CGFloat originx=0;
+ CGFloat originx=-IMAGE_DEFAULT_MARGIN;
CGFloat availableWidth = chatTableView.tableView.frame.size.width-CELL_IMAGE_X_MARGIN;
NSMutableArray *fileUrls = [[NSMutableArray alloc] init];
@@ -713,16 +725,111 @@
textFrame.origin = CGPointMake(textFrame.origin.x, self.finalAssetView.frame.origin.y + self.finalAssetView.frame.size.height);
else
// When image hasn't be download
- textFrame.origin = CGPointMake(textFrame.origin.x, _imageSubView.frame.size.height + _imageSubView.frame.origin.y - 10);
+ textFrame.origin = CGPointMake(textFrame.origin.x, _voiceRecordingFile ? _fileView.frame.origin.y : _imageSubView.frame.size.height + _imageSubView.frame.origin.y - 10);
if (!utf8Text) {
textFrame.size.height = 0;
} else {
textFrame.size.height = bubbleFrame.size.height - 90;//textFrame.origin.x;
}
+
+ if (_voiceRecordingFile) {
+ CGRect vrFrame = _vrView.frame;
+ vrFrame.origin.y = _contentViews.count == 0 && !utf8Text ? _fileView.frame.origin.y : textFrame.origin.y;
+ _vrView.frame = vrFrame;
+ textFrame.origin.y += VOICE_RECORDING_PLAYER_HEIGHT;
+ _vrView.hidden = NO;
+ } 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;
}
+// Voice messages
+
+static AVAudioPlayer* utilityPlayer;
+
+-(void) setVoiceMessageDuration {
+ 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
+ _vrTimerLabel.text = [self formattedDuration:utilityPlayer.duration];
+ utilityPlayer = nil;
+}
+
+-(void) voicePlayTimerUpdate {
+ CGRect r = _vrWaveMaskPlayback.frame;
+ r.size.width += _vrView.frame.size.width / ((linphone_player_get_duration(voicePlayer) / 500)) ;
+ if (r.size.width > _vrView.frame.size.width) {
+ r.size.width = _vrView.frame.size.width;
+ }
+ [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
+ _vrWaveMaskPlayback.frame = r;
+ }completion:^(BOOL finished) {}];
+}
+
+
+-(void) stopPlayer {
+ [NSNotificationCenter.defaultCenter removeObserver:self];
+ [chatView stopSharedPlayer];
+ [_vrPlayPause setImage:[UIImage imageNamed:@"vr_play"] forState:UIControlStateNormal];
+ [_vrPlayerTimer invalidate];
+ _vrWaveMaskPlayback.frame = CGRectZero;
+}
+
+-(NSString *)formattedDuration:(long)valueMs {
+ return [NSString stringWithFormat:@"%02ld:%02ld", valueMs/ 60, (valueMs % 60) ];
+}
+
+-(void) startPlayer {
+ [chatView startSharedPlayer:_voiceRecordingFile.UTF8String];
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(stopPlayer)
+ name:kLinphoneVoiceMessagePlayerLostFocus
+ object:nil];
+
+ [NSNotificationCenter.defaultCenter addObserver:self
+ selector:@selector(stopPlayer)
+ name:kLinphoneVoiceMessagePlayerEOF
+ object:nil];
+
+ [_vrPlayPause setImage:[UIImage imageNamed:@"vr_stop"] forState:UIControlStateNormal];
+ CGRect r = CGRectZero;
+ r.size.height = _vrView.frame.size.height - 14;
+ r.origin.y = 7;
+ _vrWaveMaskPlayback.frame = r;
+ _vrPlayerTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
+ target:self
+ selector:@selector(voicePlayTimerUpdate)
+ userInfo:nil
+ repeats:YES];
+ [self voicePlayTimerUpdate];
+
+}
+
+- (IBAction)onVRPlayPauseClick:(id)sender {
+ if ([chatView sharedPlayedIsPlaying:_voiceRecordingFile.UTF8String])
+ [self stopPlayer];
+ else {
+ [self startPlayer];
+ }
+}
+
+
+// menu
+
+-(void) onPopupMenuPressed {
+ [super onPopupMenuPressed];
+}
+
+
@end
diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h
index 6778a8143..fe729b670 100644
--- a/Classes/LinphoneUI/UIChatBubbleTextCell.h
+++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h
@@ -22,12 +22,16 @@
#import "UITextViewNoDefine.h"
#import "ChatConversationTableView.h"
#import "UIRoundedImageView.h"
+#import "UIChatReplyBubbleView.h"
#define CELL_IMAGE_X_MARGIN 100
#define IMAGE_DEFAULT_WIDTH 120
#define IMAGE_DEFAULT_MARGIN 5
+#define VOICE_RECORDING_PLAYER_HEIGHT 60
+#define VOICE_RECORDING_PLAYER_WIDTH 300
-@interface UIChatBubbleTextCell : UITableViewCell
+
+@interface UIChatBubbleTextCell : UITableViewCell
@property(readonly, nonatomic) LinphoneEventLog *event;
@property(readonly, nonatomic) LinphoneChatMessage *message;
@@ -47,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;
@@ -57,14 +77,13 @@
+ (CGSize)getMediaMessageSizefromOriginalSize:(CGSize)originalSize withWidth:(int)width;
+ (UIImage *)getImageFromVideoUrl:(NSURL *)url;
+ (UIImage *)getImageFromContent:(LinphoneContent *)content filePath:(NSString *)filePath;
++ (UIImage *)getImageFromFileName:(NSString *)fileName;
- (void)setEvent:(LinphoneEventLog *)event;
- (void)setChatMessageForCbs:(LinphoneChatMessage *)message;
- (void)clearEncryptedFiles;
- (void)onDelete;
-- (void)onResend;
-- (void)onLime;
- (void)update;
- (void)displayImdmStatus:(LinphoneChatMessageState)state;
@@ -72,5 +91,7 @@
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message;
+ (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 808cb20b1..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,76 +310,6 @@
}
}
-- (void)onLime {
- /*if (!_LIMEKO.hidden)
- [self displayLIMEWarning];*/
-}
-
-- (void)onResend {
- 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);
- BOOL multiParts = ((linphone_chat_message_get_text_content(self.message) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 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_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];
- });
- return;
- }
- if (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];
- } else if (localVideo) {
- [_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localVideo]) withName:localVideo type:@"video" key:@"localvideo" message:str];
- } else {
- [_chatRoomDelegate resendFile:(data?:[ChatConversationView getFileData:localFile]) withName:localFile type:@"image" key:@"localfile" message:str];
- }
- });
- } 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) {
- [_chatRoomDelegate resendChat:self.textMessage withExternalUrl:nil];
- });
- }
-}
#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));
@@ -424,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 {
@@ -437,6 +383,41 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
return size;
}
+
++(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;
+ 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; {
NSString *type = [NSString stringWithUTF8String:linphone_content_get_type(content)];
NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)];
@@ -452,11 +433,23 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
image = [[UIImage alloc] initWithData:data];
}
if (image) return image;
- UIImage *basicImage = [ChatConversationView getBasicImage];
- image = [ChatConversationView drawText:[NSString stringWithFormat:@"📎 %@",name] image:basicImage textSize:25];
- return image;
+ else return [self getImageFromFileName:name];
}
++(LinphoneContent *) voiceContent:(LinphoneChatMessage *)message {
+ for (const bctbx_list_t *it = linphone_chat_message_get_contents(message); it != NULL; it=bctbx_list_next(it)){
+ LinphoneContent *content = (LinphoneContent *)it->data;
+ if (linphone_content_is_voice_recording(content))
+ return content;
+ }
+ return nil;
+}
+
+
++(CGSize) addVoicePlayerToSize:(CGSize)size withMargins:(BOOL)margins {
+ return CGSizeMake(MAX(size.width,VOICE_RECORDING_PLAYER_WIDTH + (margins ? CELL_MESSAGE_X_MARGIN: 0)), size.height + VOICE_RECORDING_PLAYER_HEIGHT+(margins ? CELL_MESSAGE_Y_MARGIN: 0));
+
+}
+ (CGSize)ViewHeightForMessageText:(LinphoneChatMessage *)chat withWidth:(int)width textForImdn:(NSString *)imdnText {
NSString *messageText = [UIChatBubbleTextCell TextMessageForChat:chat];
@@ -484,14 +477,51 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
CGFloat imagesh=0;
CGFloat max_imagesw=0;
CGFloat max_imagesh=0;
+ LinphoneContent *voiceContent = [self voiceContent:chat];
const bctbx_list_t *contents = linphone_chat_message_get_contents(chat);
- BOOL multiParts = ((linphone_chat_message_get_text_content(chat) != NULL) ? bctbx_list_size(contents) > 2 : bctbx_list_size(contents) > 1);
+ size_t contentCount = bctbx_list_size(contents);
+ if (voiceContent)
+ contentCount--;
+
+ BOOL multiParts = ((linphone_chat_message_get_text_content(chat) != NULL) ? contentCount > 2 : contentCount > 1);
+
+ if (voiceContent && contentCount == 0) {
+ size = CGSizeMake(VOICE_RECORDING_PLAYER_WIDTH, VOICE_RECORDING_PLAYER_HEIGHT);
+ CGSize textSize = CGSizeMake(0, 0);
+ if (![messageText isEqualToString:@"🗻"]) {
+ textSize = [self computeBoundingBox:messageText
+ size:CGSizeMake(max_imagesw , CGFLOAT_MAX)
+ font:messageFont];
+ }
+
+ // add size for message text
+ size.height += textSize.height;
+ size.width = MAX(textSize.width, size.width);
+ size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
+ size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT) ;
+ return size;
+ }
+
if (multiParts) {
const bctbx_list_t *it = contents;
NSMutableDictionary *encrptedFilePaths = [LinphoneManager getMessageAppDataForKey:@"encryptedfiles" inMessage:chat];
for (it = contents; it != NULL; it=bctbx_list_next(it)){
LinphoneContent *content = (LinphoneContent *)it->data;
+ if (linphone_content_is_voice_recording(content)) {
+ CGSize sSize = CGSizeMake(VOICE_RECORDING_PLAYER_WIDTH, VOICE_RECORDING_PLAYER_HEIGHT);
+ imagesw += sSize.width;
+ if (imagesw > width) {
+ imagesw = sSize.width;
+ max_imagesw = MAX(max_imagesw, imagesw);
+ max_imagesh += imagesh;
+ imagesh = sSize.height;
+ } else {
+ max_imagesw = MAX(max_imagesw, imagesw);
+ imagesh = MAX(imagesh, sSize.height);
+ }
+ continue;
+ }
UIImage *image;
if(!linphone_chat_message_is_outgoing(chat) && linphone_content_is_file_transfer(content)) {
// not yet downloaded
@@ -538,22 +568,25 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT) ;
return size;
}
+
-
- LinphoneContent *fileContent = linphone_chat_message_get_file_transfer_information(chat);
- if (url == nil && fileContent == NULL) {
+ // if here, either 1 file + text or just one file or just text.
+ BOOL justText = linphone_chat_message_get_text_content(chat) != NULL && contentCount == 1;
+ if (justText) { // Just text
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];
NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:chat];
NSString *filePath = [LinphoneManager getMessageAppDataForKey:@"encryptedfile" inMessage:chat];
- NSString *fileName = [NSString stringWithUTF8String:linphone_content_get_name(fileContent)];
-
+ NSString *fileName = fileContent ? [NSString stringWithUTF8String:linphone_content_get_name(fileContent)] : nil;
+
CGSize textSize = CGSizeMake(0, 0);
- if (![messageText isEqualToString:@"🗻"]) {
+ if (![messageText isEqualToString:@"🗻"] && messageText.length > 0) {
textSize = [self computeBoundingBox:messageText
size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX)
font:messageFont];
@@ -582,28 +615,45 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
NSData *data = [NSData dataWithContentsOfURL:[VIEW(ChatConversationView) getICloudFileUrl:localFile]];
image = [[UIImage alloc] initWithData:data];
}
+ } else if (voiceContent){
+ return [self addVoicePlayerToSize:[self ViewHeightForFile:width] withMargins:true];
} else {
- return [self ViewHeightForFile:width];
+ image = nil;
+ originalImageSize = CGSizeMake(140, 140);
}
-
- originalImageSize = image.size;
+ if (image != nil)
+ originalImageSize = image.size;
} else {
if (!localImage && !localVideo) {
//We are loading the image
- return CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN + textSize.height + 20);
+ CGSize baseSize = CGSizeMake(120 + CELL_MESSAGE_X_MARGIN, 120 + CELL_MESSAGE_Y_MARGIN + textSize.height + (textSize.height != 0 ? 20 : 0));
+ if (voiceContent) {
+ baseSize = [self addVoicePlayerToSize:baseSize withMargins:true];
+ baseSize.height -= VOICE_RECORDING_PLAYER_HEIGHT;
+ baseSize.height += 10;
+ }
+ return baseSize;
}
if (localImage && [[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSData* data = [NSData dataWithContentsOfFile:filePath];
UIImage *image = [[UIImage alloc] initWithData:data];
if (!image) {
- return [self ViewHeightForFile:width];
+ CGSize fileSize = [self ViewHeightForFile:width];
+ if (voiceContent) {
+ fileSize = [self addVoicePlayerToSize:fileSize withMargins:true];
+ }
+ return fileSize;
}
originalImageSize = image.size;
} else if (localVideo && [[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
UIImage *image = [UIChatBubbleTextCell getImageFromVideoUrl:[NSURL fileURLWithPath:filePath]];
if (!image) {
- return [self ViewHeightForFile:width];
+ CGSize fileSize = [self ViewHeightForFile:width];
+ if (voiceContent) {
+ fileSize = [self addVoicePlayerToSize:fileSize withMargins:true];
+ }
+ return fileSize;
}
originalImageSize = image.size;
} else {
@@ -615,7 +665,11 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] options:nil];
if (![assets firstObject]) {
- return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height);
+ CGSize baseSize = CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_WIDTH + CELL_MESSAGE_Y_MARGIN + textSize.height);
+ if (voiceContent) {
+ baseSize = [self addVoicePlayerToSize:baseSize withMargins:true];
+ }
+ return baseSize;
} else {
PHAsset *asset = [assets firstObject];
originalImageSize = CGSizeMake([asset pixelWidth], [asset pixelHeight]);
@@ -627,6 +681,11 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 44;
size.height += textSize.height;
size.width = MAX(textSize.width, size.width);
}
+
+ if (voiceContent) {
+ size.width = MAX(size.width,VOICE_RECORDING_PLAYER_WIDTH);
+ size.height += VOICE_RECORDING_PLAYER_HEIGHT;
+ }
size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT);
@@ -670,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;
+
+
}
}
@@ -706,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/UIChatContentView.m b/Classes/LinphoneUI/UIChatContentView.m
index 45882677f..3b5713e94 100644
--- a/Classes/LinphoneUI/UIChatContentView.m
+++ b/Classes/LinphoneUI/UIChatContentView.m
@@ -31,19 +31,20 @@
if(!linphone_chat_message_is_outgoing(_message) && linphone_content_is_file_transfer(_content)) {
// has not yet downloaded
- UIImage *basicImage = [ChatConversationView getBasicImage];
NSString *name = [NSString stringWithUTF8String:linphone_content_get_name(content)] ;
- UIImage *image = [ChatConversationView drawText:name image:basicImage textSize:25];
+ UIImage *image = [UIChatBubbleTextCell getImageFromFileName:name];
[self setImage:image];
_downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_downloadButton addTarget:self
action:@selector(onDownloadClick:)
forControlEvents:UIControlEventTouchUpInside];
- _downloadButton.backgroundColor = [UIColor orangeColor];
- UIFont *boldFont = [UIFont systemFontOfSize:10];
- NSMutableAttributedString *boldText = [[NSMutableAttributedString alloc] initWithString:@"Download" attributes:@{ NSFontAttributeName : boldFont }];
+ UIFont *boldFont = [UIFont systemFontOfSize:12];
+ NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
+ paragraphStyle.alignment = NSTextAlignmentCenter;
+
+ NSMutableAttributedString *boldText = [[NSMutableAttributedString alloc] initWithString:@"Download" attributes:@{ NSFontAttributeName : boldFont, NSParagraphStyleAttributeName:paragraphStyle,NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle) }];
[_downloadButton setAttributedTitle:boldText forState:UIControlStateNormal];
- _downloadButton.frame = CGRectMake(3, 3, 60, 30);
+ _downloadButton.frame = CGRectMake(0, 90, 120, 30);
[self addSubview:_downloadButton];
} else {
if (_filePath == NULL) {
@@ -56,6 +57,7 @@
tapGestureRecognizer.numberOfTapsRequired = 1;
tapGestureRecognizer.enabled = YES;
[self addGestureRecognizer:tapGestureRecognizer];
+ self.userInteractionEnabled = true;
}
}
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/UIImageViewDeletable.xib b/Classes/LinphoneUI/UIImageViewDeletable.xib
index 2fa5d17e1..4d0dea67a 100644
--- a/Classes/LinphoneUI/UIImageViewDeletable.xib
+++ b/Classes/LinphoneUI/UIImageViewDeletable.xib
@@ -1,11 +1,9 @@
-
-
-
-
+
+
-
+
@@ -17,15 +15,15 @@
-
+
-
+
-
+
@@ -36,15 +34,15 @@
+
-
-
+
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 c8d78cd4f..793243495 100644
--- a/Classes/PhoneMainView.m
+++ b/Classes/PhoneMainView.m
@@ -830,7 +830,7 @@ static RootViewManager *rootViewManagerInstance = nil;
}
if (!linphone_core_is_network_reachable(LC)) {
- [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView] animated:YES completion:nil];
+ [PhoneMainView.instance presentViewController:[LinphoneUtils networkErrorView:@"send a message"] animated:YES completion:nil];
return;
}
@@ -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
new file mode 100644
index 000000000..ff9278263
--- /dev/null
+++ b/Classes/SwiftUtil.swift
@@ -0,0 +1,69 @@
+/*
+* 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 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))
+
+ 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()
+
+
+ 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 3aa3d22db..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;
-- (void)uploadData:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom type:(NSString *)type subtype:(NSString *)subtype name:(NSString *)name key:(NSString *)key;
+- (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 d8d20670b..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{
+- (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]);
@@ -124,15 +125,17 @@ static void file_transfer_progress_indication_send(LinphoneChatMessage *message,
linphone_chat_message_cbs_set_file_transfer_progress_indication(linphone_chat_message_get_callbacks(_message), file_transfer_progress_indication_send);
[LinphoneManager setValueInMessageAppData:name forKey:key inMessage:_message];
+
+
LOGI(@"%p Uploading content from message %p", self, _message);
linphone_chat_message_send(_message);
}
-- (void)uploadFileContent: (FileContext *)context forChatRoom:(LinphoneChatRoom *)chatRoom {
+- (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];
@@ -162,6 +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];
+
LOGI(@"%p Uploading content from message %p", self, _message);
linphone_chat_message_send(_message);
}
@@ -170,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"];
+ [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"];
-}
-- (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];
+ [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 7289bbe83..207521dc9 100644
--- a/Classes/Utils/Utils.h
+++ b/Classes/Utils/Utils.h
@@ -39,7 +39,7 @@
+ (UIImage *)resizeImage:(UIImage *)imageToResize newSize:(CGSize)newSize;
+ (LinphoneAddress *)normalizeSipOrPhoneAddress:(NSString *)addr;
-+ (UIAlertController *)networkErrorView;
++ (UIAlertController *)networkErrorView:(NSString *)action;
typedef enum {
LinphoneDateHistoryList,
@@ -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 4f6d1249d..b9cbfaaa1 100644
--- a/Classes/Utils/Utils.m
+++ b/Classes/Utils/Utils.m
@@ -516,12 +516,10 @@
return res;
}
-+ (UIAlertController *)networkErrorView {
++ (UIAlertController *)networkErrorView:(NSString *)action {
UIAlertController *errView =
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"Network Error", nil)
- message:NSLocalizedString(@"There is no network connection available, "
- @"enable WIFI or WWAN prior to place a call",
- nil)
+ message:NSLocalizedString([@"There is no network connection available, enable WIFI or WWAN prior to " stringByAppendingString:action],nil)
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
@@ -577,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 {
@@ -806,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 18c1cc72e..d6a747f18 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.0.16'
+ pod 'linphone-sdk', '~> 5.1.0-alpha.75+d4a0bd2'
else
pod 'linphone-sdk', :path => ENV['PODFILE_PATH'] # local sdk
end
diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings
index a69217772..76f33d13e 100644
Binary files a/Resources/en.lproj/Localizable.strings and b/Resources/en.lproj/Localizable.strings differ
diff --git a/Resources/fr.lproj/Localizable.strings b/Resources/fr.lproj/Localizable.strings
index b119be4b7..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_audio_default.png b/Resources/images/file_audio_default.png
new file mode 100644
index 000000000..ce5af4fd5
Binary files /dev/null and b/Resources/images/file_audio_default.png differ
diff --git a/Resources/images/file_default.png b/Resources/images/file_default.png
new file mode 100644
index 000000000..f660964fb
Binary files /dev/null and b/Resources/images/file_default.png differ
diff --git a/Resources/images/file_pdf_default.png b/Resources/images/file_pdf_default.png
new file mode 100644
index 000000000..3a6a30c94
Binary files /dev/null and b/Resources/images/file_pdf_default.png differ
diff --git a/Resources/images/file_picture_default.png b/Resources/images/file_picture_default.png
new file mode 100644
index 000000000..26f2c8d0c
Binary files /dev/null and b/Resources/images/file_picture_default.png differ
diff --git a/Resources/images/file_video_default.png b/Resources/images/file_video_default.png
new file mode 100644
index 000000000..9a3d1a301
Binary files /dev/null and b/Resources/images/file_video_default.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/Resources/images/vr_off.png b/Resources/images/vr_off.png
new file mode 100644
index 000000000..5f319e5c8
Binary files /dev/null and b/Resources/images/vr_off.png differ
diff --git a/Resources/images/vr_on.png b/Resources/images/vr_on.png
new file mode 100644
index 000000000..9fd24b67c
Binary files /dev/null and b/Resources/images/vr_on.png differ
diff --git a/Resources/images/vr_pause.png b/Resources/images/vr_pause.png
new file mode 100644
index 000000000..af2d89acc
Binary files /dev/null and b/Resources/images/vr_pause.png differ
diff --git a/Resources/images/vr_play.png b/Resources/images/vr_play.png
new file mode 100644
index 000000000..6de2686f0
Binary files /dev/null and b/Resources/images/vr_play.png differ
diff --git a/Resources/images/vr_stop.png b/Resources/images/vr_stop.png
new file mode 100644
index 000000000..6574a7d56
Binary files /dev/null and b/Resources/images/vr_stop.png differ
diff --git a/Resources/images/vr_wave.png b/Resources/images/vr_wave.png
new file mode 100644
index 000000000..26d7f1be7
Binary files /dev/null and b/Resources/images/vr_wave.png differ
diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj
index 9d049a72a..3fbac849c 100644
--- a/linphone.xcodeproj/project.pbxproj
+++ b/linphone.xcodeproj/project.pbxproj
@@ -109,7 +109,7 @@
61AE364F20C00B370089D9D3 /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AE364E20C00B370089D9D3 /* ShareViewController.m */; };
61AE365220C00B370089D9D3 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61AE365020C00B370089D9D3 /* MainInterface.storyboard */; };
61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 61AE364B20C00B370089D9D3 /* linphoneExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
- 61AEBEA321906AFC00F35E7F /* (null) in Frameworks */ = {isa = PBXBuildFile; };
+ 61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
61AEBEBD2191990A00F35E7F /* DevicesListView.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AEBEBC2191990A00F35E7F /* DevicesListView.m */; };
61AEBEBF2191991F00F35E7F /* DevicesListView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEBE2191991F00F35E7F /* DevicesListView.xib */; };
61AEBEC62191E47500F35E7F /* chevron_list_close.png in Resources */ = {isa = PBXBuildFile; fileRef = 61AEBEC52191E47500F35E7F /* chevron_list_close.png */; };
@@ -622,7 +622,7 @@
63E27A321C4FECD000D332AE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A311C4FECD000D332AE /* LaunchScreen.xib */; };
63E27A521C50EDB000D332AE /* hold.mkv in Resources */ = {isa = PBXBuildFile; fileRef = 63E27A511C50EB2700D332AE /* hold.mkv */; };
63E59A3F1ADE70D900646FB3 /* InAppProductsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E59A3E1ADE70D900646FB3 /* InAppProductsManager.m */; };
- 63E802DB1C625AEF000D5509 /* (null) in Resources */ = {isa = PBXBuildFile; };
+ 63E802DB1C625AEF000D5509 /* BuildFile in Resources */ = {isa = PBXBuildFile; };
63EC8D391D7438660066547B /* AssistantLinkView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 63EC8D3B1D7438660066547B /* AssistantLinkView.xib */; };
63F1DF441BCE618E00EDED90 /* UIAddressTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */; };
63F1DF4B1BCE983200EDED90 /* CallConferenceTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 63F1DF4A1BCE983200EDED90 /* CallConferenceTableView.m */; };
@@ -675,11 +675,35 @@
C61B1BF22667D075001A4E4A /* menu_security_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF12667D075001A4E4A /* menu_security_default.png */; };
C61B1BF42667D202001A4E4A /* more_menu_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF32667D202001A4E4A /* more_menu_default.png */; };
C61B1BF72667EC6B001A4E4A /* ephemeral_messages_color_A.png in Resources */ = {isa = PBXBuildFile; fileRef = C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */; };
+ C622E3EF26A81290004F5434 /* vr_stop.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3E926A8128F004F5434 /* vr_stop.png */; };
+ C622E3F026A81290004F5434 /* vr_wave.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EA26A8128F004F5434 /* vr_wave.png */; };
+ C622E3F126A81290004F5434 /* vr_on.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EB26A8128F004F5434 /* vr_on.png */; };
+ C622E3F226A81290004F5434 /* vr_off.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EC26A8128F004F5434 /* vr_off.png */; };
+ C622E3F326A81290004F5434 /* vr_pause.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3ED26A8128F004F5434 /* vr_pause.png */; };
+ C622E3F426A81290004F5434 /* vr_play.png in Resources */ = {isa = PBXBuildFile; fileRef = C622E3EE26A81290004F5434 /* vr_play.png */; };
C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */; };
C64A85502667B67A00252AD2 /* EphemeralSettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */; };
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 */; };
+ C6B4444526AAD0980076C517 /* file_audio_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4444026AAD0970076C517 /* file_audio_default.png */; };
+ C6B4444626AAD0980076C517 /* file_pdf_default.png in Resources */ = {isa = PBXBuildFile; fileRef = C6B4444126AAD0970076C517 /* file_pdf_default.png */; };
+ C6B4444826AADA530076C517 /* SwiftUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6B4444726AADA530076C517 /* SwiftUtil.swift */; };
C6DA657C261C950C0020CB43 /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; };
C90FAA7915AF54E6002091CB /* HistoryDetailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */; };
CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */ = {isa = PBXBuildFile; fileRef = CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */; };
@@ -1714,10 +1738,37 @@
C61B1BF12667D075001A4E4A /* menu_security_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_security_default.png; sourceTree = ""; };
C61B1BF32667D202001A4E4A /* more_menu_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = more_menu_default.png; sourceTree = ""; };
C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ephemeral_messages_color_A.png; sourceTree = ""; };
+ C622E3E926A8128F004F5434 /* vr_stop.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_stop.png; sourceTree = ""; };
+ C622E3EA26A8128F004F5434 /* vr_wave.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_wave.png; sourceTree = ""; };
+ C622E3EB26A8128F004F5434 /* vr_on.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_on.png; sourceTree = ""; };
+ C622E3EC26A8128F004F5434 /* vr_off.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_off.png; sourceTree = ""; };
+ C622E3ED26A8128F004F5434 /* vr_pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_pause.png; sourceTree = ""; };
+ C622E3EE26A81290004F5434 /* vr_play.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vr_play.png; sourceTree = ""; };
C64A854C2667B66900252AD2 /* EphemeralSettingsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EphemeralSettingsView.h; sourceTree = ""; };
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 = ""; };
+ C6B4444026AAD0970076C517 /* file_audio_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_audio_default.png; sourceTree = ""; };
+ C6B4444126AAD0970076C517 /* file_pdf_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = file_pdf_default.png; sourceTree = ""; };
+ C6B4444726AADA530076C517 /* SwiftUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUtil.swift; sourceTree = ""; };
C6DA657B261C950C0020CB43 /* VFSUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VFSUtil.swift; sourceTree = ""; };
C90FAA7615AF54E6002091CB /* HistoryDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryDetailsView.h; sourceTree = ""; };
C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryDetailsView.m; sourceTree = ""; };
@@ -1951,7 +2002,7 @@
files = (
61DD7E1F2372E88F001BDD01 /* CoreLocation.framework in Frameworks */,
6180D6FE21EE41A800AD9CB6 /* QuickLook.framework in Frameworks */,
- 61AEBEA321906AFC00F35E7F /* (null) in Frameworks */,
+ 61AEBEA321906AFC00F35E7F /* BuildFile in Frameworks */,
D37DC7181594AF3400B2A5EB /* MessageUI.framework in Frameworks */,
61F1997520C6B1D5006B069A /* AVKit.framework in Frameworks */,
249660951FD6A35F001D55AA /* Photos.framework in Frameworks */,
@@ -2166,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 */,
@@ -2285,7 +2339,7 @@
path = LinphoneUI;
sourceTree = "";
};
- 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
+ 29B97314FDCFA39411CA2CEA = {
isa = PBXGroup;
children = (
8C23BCB71D82AAC3005F19BB /* linphone.entitlements */,
@@ -2447,6 +2501,27 @@
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 */,
+ C6B4443F26AAD0970076C517 /* file_picture_default.png */,
+ C6B4443D26AAD0970076C517 /* file_video_default.png */,
+ C622E3EC26A8128F004F5434 /* vr_off.png */,
+ C622E3EB26A8128F004F5434 /* vr_on.png */,
+ C622E3ED26A8128F004F5434 /* vr_pause.png */,
+ C622E3EE26A81290004F5434 /* vr_play.png */,
+ C622E3E926A8128F004F5434 /* vr_stop.png */,
+ C622E3EA26A8128F004F5434 /* vr_wave.png */,
C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */,
C61B1BF32667D202001A4E4A /* more_menu_default.png */,
C61B1BF12667D075001A4E4A /* menu_security_default.png */,
@@ -3043,6 +3118,7 @@
63423C091C4501D000D9A050 /* Contact.m */,
8C1B67081E6718BC001EA2FE /* AudioHelper.h */,
8C1B67051E671826001EA2FE /* AudioHelper.m */,
+ C6B4444726AADA530076C517 /* SwiftUtil.swift */,
);
name = Utils;
sourceTree = "";
@@ -3357,7 +3433,7 @@
fr,
hu,
);
- mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
+ mainGroup = 29B97314FDCFA39411CA2CEA;
productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -3378,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 */,
@@ -3408,6 +3485,7 @@
615A2817217F280C0060F920 /* chat_list_indicator.png in Resources */,
633FEEFF1D3CD55A0014B822 /* options_add_call_disabled@2x.png in Resources */,
633FEF091D3CD55A0014B822 /* options_start_conference_disabled@2x.png in Resources */,
+ C622E3F326A81290004F5434 /* vr_pause.png in Resources */,
633FEE051D3CD5590014B822 /* cancel_edit_disabled@2x.png in Resources */,
633FEE5F1D3CD5590014B822 /* edit_list_default@2x.png in Resources */,
633FEEB61D3CD55A0014B822 /* numpad_3_over@2x.png in Resources */,
@@ -3418,7 +3496,7 @@
633FEED41D3CD55A0014B822 /* numpad_7_default@2x.png in Resources */,
633FEEE01D3CD55A0014B822 /* numpad_8_over~ipad@2x.png in Resources */,
633FEDDC1D3CD5590014B822 /* call_start_body_disabled~ipad.png in Resources */,
- 63E802DB1C625AEF000D5509 /* (null) in Resources */,
+ 63E802DB1C625AEF000D5509 /* BuildFile in Resources */,
633FEE2E1D3CD5590014B822 /* color_F.png in Resources */,
633FEDC51D3CD5590014B822 /* call_hangup_disabled@2x.png in Resources */,
633FEEDF1D3CD55A0014B822 /* numpad_8_over~ipad.png in Resources */,
@@ -3443,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 */,
@@ -3453,6 +3532,7 @@
633FEDD91D3CD5590014B822 /* call_start_body_default~ipad@2x.png in Resources */,
633FEE401D3CD5590014B822 /* contacts_all_selected.png in Resources */,
633FEE0C1D3CD5590014B822 /* chat_attachment_disabled.png in Resources */,
+ C622E3EF26A81290004F5434 /* vr_stop.png in Resources */,
633FEF001D3CD55A0014B822 /* options_default.png in Resources */,
CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */,
633FEE951D3CD55A0014B822 /* micro_default@2x.png in Resources */,
@@ -3478,6 +3558,7 @@
633FEE7A1D3CD5590014B822 /* history_missed_default.png in Resources */,
633FEF121D3CD55A0014B822 /* pause_big_over_selected.png in Resources */,
633FED9D1D3CD5590014B822 /* add_field_default@2x.png in Resources */,
+ C622E3F426A81290004F5434 /* vr_play.png in Resources */,
639E9CB01C0DB83000019A75 /* SideMenuView.xib in Resources */,
633FEDBB1D3CD5590014B822 /* call_audio_start_default@2x.png in Resources */,
633FEF1A1D3CD55A0014B822 /* presence_away.png in Resources */,
@@ -3505,6 +3586,7 @@
615A283E2180A2560060F920 /* invite_linphone.png in Resources */,
633FEF281D3CD55A0014B822 /* route_earpiece_default.png in Resources */,
633FEE4F1D3CD5590014B822 /* delete_field_over@2x.png in Resources */,
+ C622E3F226A81290004F5434 /* vr_off.png in Resources */,
633FEE531D3CD5590014B822 /* dialer_alt_back@2x.png in Resources */,
633FEE3E1D3CD5590014B822 /* contacts_all_disabled.png in Resources */,
633FEEF31D3CD55A0014B822 /* numpad_over_background.png in Resources */,
@@ -3514,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 */,
@@ -3547,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 */,
@@ -3563,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 */,
@@ -3602,6 +3687,7 @@
633FEDFD1D3CD5590014B822 /* camera_switch_default@2x.png in Resources */,
633FEEC51D3CD55A0014B822 /* numpad_5_over.png in Resources */,
633FEE721D3CD5590014B822 /* history_all_default.png in Resources */,
+ C6B4444326AAD0980076C517 /* file_default.png in Resources */,
615A283C2180789C0060F920 /* security_toogle_button@2x.png in Resources */,
633FEF0A1D3CD55A0014B822 /* options_transfer_call_default.png in Resources */,
633FEDA51D3CD5590014B822 /* back_default@2x.png in Resources */,
@@ -3627,6 +3713,7 @@
63E27A321C4FECD000D332AE /* LaunchScreen.xib in Resources */,
633FEED11D3CD55A0014B822 /* numpad_6~ipad.png in Resources */,
CF7602E82108759A00749F76 /* UIRecordingCell.xib in Resources */,
+ C6B4444626AAD0980076C517 /* file_pdf_default.png in Resources */,
633FEED21D3CD55A0014B822 /* numpad_6~ipad@2x.png in Resources */,
633FEDCD1D3CD5590014B822 /* call_quality_indicator_0@2x.png in Resources */,
636316D41A1DEC650009B839 /* SettingsView.xib in Resources */,
@@ -3691,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 */,
@@ -3722,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 */,
@@ -3740,7 +3829,9 @@
633FEE191D3CD5590014B822 /* chat_send_over@2x.png in Resources */,
633FEF181D3CD55A0014B822 /* pause_small_over_selected.png in Resources */,
633FEE001D3CD5590014B822 /* camera_switch_over.png in Resources */,
+ C622E3F126A81290004F5434 /* vr_on.png in Resources */,
633FEF401D3CD55A0014B822 /* select_all_default.png in Resources */,
+ C6B4444426AAD0980076C517 /* file_picture_default.png in Resources */,
633FEDF01D3CD5590014B822 /* call_transfer_disabled.png in Resources */,
633FEE351D3CD5590014B822 /* conference_exit_default@2x.png in Resources */,
633FEECF1D3CD55A0014B822 /* numpad_6_over~ipad.png in Resources */,
@@ -3772,6 +3863,7 @@
633FEEFA1D3CD55A0014B822 /* numpad_star~ipad.png in Resources */,
D38187B915FE342200C3EDCA /* ContactDetailsView.xib in Resources */,
633FEE921D3CD55A0014B822 /* menu.png in Resources */,
+ C622E3F026A81290004F5434 /* vr_wave.png in Resources */,
633FEDE41D3CD5590014B822 /* call_status_incoming~ipad.png in Resources */,
633FEE4C1D3CD5590014B822 /* delete_field_default.png in Resources */,
633FEE391D3CD5590014B822 /* contact_add_default@2x.png in Resources */,
@@ -3831,8 +3923,10 @@
633FEEF71D3CD55A0014B822 /* numpad_star_over@2x.png in Resources */,
633FEEAB1D3CD55A0014B822 /* numpad_2_default.png in Resources */,
633FEE851D3CD5590014B822 /* led_error@2x.png in Resources */,
+ 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 */,
@@ -3862,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 */,
@@ -3876,6 +3971,8 @@
633FEF3B1D3CD55A0014B822 /* security_ko@2x.png in Resources */,
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 */,
@@ -3950,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 */,
@@ -4195,6 +4293,7 @@
6135761C240E81BB005304D4 /* UIInterfaceStyleButton.m in Sources */,
8CD99A3C2090B9FA008A7CDA /* ChatConversationImdnView.m in Sources */,
1D3623260D0F684500981E51 /* LinphoneAppDelegate.m in Sources */,
+ C6B4444826AADA530076C517 /* SwiftUtil.swift in Sources */,
614C087A23D1A37400217F80 /* CallManager.swift in Sources */,
CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */,
22F2508E107141E100AC9B3F /* DialerView.m in Sources */,
@@ -4227,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 */,
@@ -4716,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 = (
@@ -4949,7 +5059,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5072,7 +5182,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5194,7 +5304,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;
@@ -5315,7 +5425,7 @@
"-DENABLE_QRCODE=TRUE",
"-DENABLE_SMS_INVITE=TRUE",
"$(inherited)",
- "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"",
+ "-DLINPHONE_SDK_VERSION=\\\"5.1.0-alpha.75+d4a0bd2\\\"",
);
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;