diff --git a/Classes/Base.lproj/ChatConversationInfoView.xib b/Classes/Base.lproj/ChatConversationInfoView.xib index 791c647eb..75d87f5cf 100644 --- a/Classes/Base.lproj/ChatConversationInfoView.xib +++ b/Classes/Base.lproj/ChatConversationInfoView.xib @@ -1,7 +1,10 @@ - + + - + + + @@ -19,17 +22,17 @@ - + - + - + - + @@ -77,7 +80,7 @@ - + @@ -109,10 +112,10 @@ - + + + - + @@ -319,7 +345,7 @@ + - + @@ -532,17 +571,26 @@ + + - + @@ -588,8 +636,16 @@ + + + + + + + + diff --git a/Classes/ChatConversationTableView.h b/Classes/ChatConversationTableView.h index 39fd08ba6..3fb5e83be 100644 --- a/Classes/ChatConversationTableView.h +++ b/Classes/ChatConversationTableView.h @@ -57,6 +57,7 @@ @property(nonatomic) NSInteger currentIndex; @property(nonatomic, strong) id chatRoomDelegate; @property NSMutableDictionary *imagesInChatroom; +@property(nonatomic) NSTimer *ephemeralDisplayTimer; - (void)addEventEntry:(LinphoneEventLog *)event; - (void)scrollToBottom:(BOOL)animated; diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m index 6b3d7eebc..ed18f9144 100644 --- a/Classes/ChatConversationTableView.m +++ b/Classes/ChatConversationTableView.m @@ -41,6 +41,17 @@ self.tableView.accessibilityIdentifier = @"ChatRoom list"; _imagesInChatroom = [NSMutableDictionary dictionary]; _currentIndex = 0; + [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]; } #pragma mark - @@ -54,35 +65,48 @@ [totalEventList removeAllObjects]; } +-(bool) eventTypeIsOfInterestForOneToOneRoom:(LinphoneEventLogType)type { + return + type == LinphoneEventLogTypeConferenceChatMessage || + type == LinphoneEventLogTypeConferenceEphemeralMessageEnabled || + type == LinphoneEventLogTypeConferenceEphemeralMessageDisabled || + type == LinphoneEventLogTypeConferenceEphemeralMessageLifetimeChanged; +} + - (void)updateData { - [self clearEventList]; + [self clearEventList]; if (!_chatRoom) return; - + LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(_chatRoom); - bctbx_list_t *chatRoomEvents = (capabilities & LinphoneChatRoomCapabilitiesOneToOne) - ? linphone_chat_room_get_history_message_events(_chatRoom, 0) - : linphone_chat_room_get_history_events(_chatRoom, 0); - bctbx_list_t *head = chatRoomEvents; - size_t listSize = bctbx_list_size(chatRoomEvents); + bool oneToOne = capabilities & LinphoneChatRoomCapabilitiesOneToOne; + bctbx_list_t *chatRoomEvents = linphone_chat_room_get_history_events(_chatRoom, 0); + + + bctbx_list_t *head = chatRoomEvents; + size_t listSize = bctbx_list_size(chatRoomEvents); totalEventList = [[NSMutableArray alloc] initWithCapacity:listSize]; - eventList = [[NSMutableArray alloc] initWithCapacity:MIN(listSize, BASIC_EVENT_LIST)]; + eventList = [[NSMutableArray alloc] initWithCapacity:MIN(listSize, BASIC_EVENT_LIST)]; BOOL autoDownload = (linphone_core_get_max_size_for_auto_download_incoming_files(LC) > -1); while (chatRoomEvents) { - LinphoneEventLog *event = (LinphoneEventLog *)chatRoomEvents->data; - LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event); - // if auto_download is available and file transfer in progress, not add event now - if (!(autoDownload && chat && linphone_chat_message_is_file_transfer_in_progress(chat))) { - [totalEventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]]; - if (listSize <= BASIC_EVENT_LIST) { - [eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]]; + LinphoneEventLog *event = (LinphoneEventLog *)chatRoomEvents->data; + if (oneToOne && ![self eventTypeIsOfInterestForOneToOneRoom:linphone_event_log_get_type(event)]) { + chatRoomEvents = chatRoomEvents->next; + } else { + LinphoneChatMessage *chat = linphone_event_log_get_chat_message(event); + // if auto_download is available and file transfer in progress, not add event now + if (!(autoDownload && chat && linphone_chat_message_is_file_transfer_in_progress(chat))) { + [totalEventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]]; + if (listSize <= BASIC_EVENT_LIST) { + [eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]]; + } } + + chatRoomEvents = chatRoomEvents->next; + listSize -= 1; } - - chatRoomEvents = chatRoomEvents->next; - listSize -= 1; } - bctbx_list_free_with_data(head, (bctbx_list_free_func)linphone_event_log_unref); + bctbx_list_free_with_data(head, (bctbx_list_free_func)linphone_event_log_unref); } - (void)refreshData { @@ -185,6 +209,7 @@ - (void)setChatRoom:(LinphoneChatRoom *)room { _chatRoom = room; [self reloadData]; + [self updateEphemeralTimes]; } static const int MAX_AGGLOMERATED_TIME=300; @@ -378,4 +403,47 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 1.f; }]; } +#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; + + for (NSValue *v in eventList) { + LinphoneEventLog *event = [v pointerValue]; + if (linphone_event_log_get_type(event) == LinphoneEventLogTypeConferenceChatMessage) { + LinphoneChatMessage *msg = linphone_event_log_get_chat_message(event); + if (linphone_chat_message_is_outgoing(msg) && linphone_chat_message_is_ephemeral(msg)) { + UIChatBubbleTextCell *cell = (UIChatBubbleTextCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:[eventList indexOfObject:v] inSection:0]]; + 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 { + LinphoneChatRoom *r =[[notif.userInfo objectForKey:@"room"] pointerValue]; + if (r ==_chatRoom) + [self reloadData]; +} + @end diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h index 777f9f6bd..32595c83c 100644 --- a/Classes/ChatConversationView.h +++ b/Classes/ChatConversationView.h @@ -49,7 +49,7 @@ @interface ChatConversationView : TPMultiLayoutViewController { + UIDocumentInteractionControllerDelegate, UISearchBarDelegate, UIImageViewDeletableDelegate,QLPreviewControllerDelegate, UICollectionViewDataSource,UIDocumentMenuDelegate,UIDocumentPickerDelegate,UITableViewDataSource, UITableViewDelegate> { OrderedDictionary *imageQualities; BOOL scrollOnGrowingEnabled; BOOL composingVisible; @@ -88,6 +88,9 @@ @property (weak, nonatomic) IBOutlet UIButton *encryptedButton; @property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleSelectionButton; @property FileContext *fileContext; +@property (weak, nonatomic) IBOutlet UITableView *popupMenu; +@property (weak, nonatomic) IBOutlet UIInterfaceStyleButton *toggleMenuButton; +@property (weak, nonatomic) IBOutlet UIImageView *ephemeralndicator; + (void)markAsRead:(LinphoneChatRoom *)chatRoom; + (void)autoDownload:(LinphoneChatMessage *)message; diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index 031132c73..fc5b8b989 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -26,6 +26,8 @@ #import "UIChatBubbleTextCell.h" #import "DevicesListView.h" #import "SVProgressHUD.h" +#import "EphemeralSettingsView.h" +#import "Utils.h" @implementation FileContext @@ -335,8 +337,22 @@ static UICompositeViewDescription *compositeDescription = nil; _encryptedButton.hidden = image ? FALSE : TRUE; [self update]; [self shareFile]; + + if (![self isBasicChatRoom]) { + [self setupPopupMenu]; + _ephemeralndicator.hidden = !linphone_chat_room_ephemeral_enabled(_chatRoom); + } + } +-(BOOL) isBasicChatRoom { + if (!_chatRoom) + return true; + LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(_chatRoom); + return capabilities & LinphoneChatRoomCapabilitiesBasic; +} + + - (void)configureMessageField { if (isOneToOne) { _messageField.editable = TRUE; @@ -563,6 +579,8 @@ static UICompositeViewDescription *compositeDescription = nil; [_backToCallButton update]; _infoButton.hidden = (isOneToOne|| !_backToCallButton.hidden || _tableController.tableView.isEditing); _callButton.hidden = !_backToCallButton.hidden || !_infoButton.hidden || _tableController.tableView.isEditing; + _toggleMenuButton.hidden = [self isBasicChatRoom] || _tableController.tableView.isEditing; + _tableController.editButton.hidden = _tableController.editButton.hidden || ![self isBasicChatRoom]; } - (void)updateParticipantLabel { @@ -1541,5 +1559,69 @@ void on_chat_room_conference_alert(LinphoneChatRoom *cr, const LinphoneEventLog return newImage; } +// Popup menu + + + +- (void) setupPopupMenu { + _popupMenu.dataSource = self; + _popupMenu.delegate = self; + _tableController.editButton.hidden = true; + _popupMenu.layer.shadowColor = [UIColor lightGrayColor].CGColor; + _popupMenu.layer.shadowOpacity = 0.5; + _popupMenu.layer.shadowOffset = CGSizeZero; + _popupMenu.layer.shadowRadius = 10; + _popupMenu.layer.masksToBounds = false; + _toggleMenuButton.hidden = false; +} + +-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [self onToggleMenu:nil]; + if (indexPath.row == 0) { + [self goToDeviceListView]; + } + if (indexPath.row == 1) { + EphemeralSettingsView *view = VIEW(EphemeralSettingsView); + view.room = _chatRoom; + [PhoneMainView.instance popToView:view.compositeViewDescription]; + } + if (indexPath.row == 2) { + [_tableController onEditClick:nil]; + [self onEditionChangeClick:nil]; + } +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 3; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [[UITableViewCell alloc] init]; + + if (indexPath.row == 0) { + cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"menu_security_default.png"] newSize:CGSizeMake(20, 25)]; + cell.textLabel.text = NSLocalizedString(@"Conversation's devices",nil); + } + if (indexPath.row == 1) { + cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"ephemeral_messages_default.png"] newSize:CGSizeMake(20, 25)]; + cell.textLabel.text = NSLocalizedString(@"Ephemeral messages",nil); + } + if (indexPath.row == 2) { + cell.imageView.image = [LinphoneUtils resizeImage:[UIImage imageNamed:@"delete_default.png"] newSize:CGSizeMake(20, 25)]; + cell.textLabel.text = NSLocalizedString(@"Delete messages",nil); + } + cell.imageView.contentMode = UIViewContentModeScaleAspectFit; + return cell; +} +- (IBAction)onToggleMenu:(id)sender { + _popupMenu.hidden = !_popupMenu.hidden; + if (!_popupMenu.hidden) + [_popupMenu selectRowAtIndexPath:nil animated:false scrollPosition:UITableViewScrollPositionNone]; +} + @end diff --git a/Classes/ChatsListView.m b/Classes/ChatsListView.m index 75d816954..a3acc5b7c 100644 --- a/Classes/ChatsListView.m +++ b/Classes/ChatsListView.m @@ -35,6 +35,10 @@ selector:@selector(callUpdateEvent:) name:kLinphoneCallUpdate object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self + selector:@selector(ephemeralDeleted:) + name:kLinphoneEphemeralMessageDeletedInRoom + object:nil]; [_backToCallButton update]; self.tableController.waitView = _waitView; [self setEditing:NO]; @@ -146,4 +150,8 @@ static UICompositeViewDescription *compositeDescription = nil; assert(NO); } +- (void)ephemeralDeleted:(NSNotification *)notif { + [self.tableController loadData]; +} + @end diff --git a/Classes/DevicesListView.xib b/Classes/DevicesListView.xib index 385b73d84..c0e97cabe 100644 --- a/Classes/DevicesListView.xib +++ b/Classes/DevicesListView.xib @@ -1,8 +1,11 @@ - + + - + + + @@ -15,19 +18,19 @@ - + - + - + - + - + - + - + @@ -81,5 +84,14 @@ + + + + + + + + + diff --git a/Classes/EphemeralSettingsView.h b/Classes/EphemeralSettingsView.h new file mode 100644 index 000000000..0bab2880c --- /dev/null +++ b/Classes/EphemeralSettingsView.h @@ -0,0 +1,36 @@ +/* + * 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 +#import "UICompositeView.h" + + + +@interface EphemeralSettingsView : TPMultiLayoutViewController + +@property (weak, nonatomic) IBOutlet UITableView *tableView; +@property (weak, nonatomic) IBOutlet UIImageView *icon; +@property (weak, nonatomic) IBOutlet UILabel *explanations; +@property (weak, nonatomic) IBOutlet UILabel *titleText; +@property(nonatomic) LinphoneChatRoom *room; +@property(nonatomic) long selectedIndex; + +- (IBAction)onBackClick:(id)sender; + +@end diff --git a/Classes/EphemeralSettingsView.m b/Classes/EphemeralSettingsView.m new file mode 100644 index 000000000..ab34989a4 --- /dev/null +++ b/Classes/EphemeralSettingsView.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 "EphemeralSettingsView.h" +#import "PhoneMainView.h" +#import "UIDevicesDetails.h" +#import "UIDeviceCell.h" + + + +@implementation EphemeralSettingsView +#pragma mark - UICompositeViewDelegate Functions + +static UICompositeViewDescription *compositeDescription = nil; + ++ (UICompositeViewDescription *)compositeViewDescription { + if (compositeDescription == nil) { + compositeDescription = [[UICompositeViewDescription alloc] init:self.class + statusBar:StatusBarView.class + tabBar:TabBarView.class + sideMenu:SideMenuView.class + fullscreen:false + isLeftFragment:NO + fragmentWith:ChatsListView.class]; + } + return compositeDescription; +} + +- (UICompositeViewDescription *)compositeViewDescription { + return self.class.compositeViewDescription; +} + +#pragma mark - ViewController Functions + + + +-(void) viewDidLoad { + [super viewDidLoad]; + self.tableView.tableHeaderView = ({ + UIView *line = [[UIView alloc] + initWithFrame:CGRectMake(0, 0, + self.tableView.frame.size.width, 1 / UIScreen.mainScreen.scale)]; + line.backgroundColor = self.tableView.separatorColor; + line; + }); + self.tableView.tintColor = UIColorFromRGB(0x96c11f); + self.explanations.text = NSLocalizedString(@"Messages will be deleted on both ends once they have been read and after the selected timeout.", nil); + self.titleText.text = NSLocalizedString(@"Ephemeral messages", nil); + +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + _tableView.dataSource = self; + _tableView.delegate = self; + [self setIndexBasedOnRoomSetting]; + [_tableView reloadData]; +} + +#pragma mark - Action Functions +- (IBAction)onBackClick:(id)sender { + ChatConversationView *view = VIEW(ChatConversationView); + [PhoneMainView.instance popToView:view.compositeViewDescription]; +} + + +- (IBAction)onSaveClick:(id)sender { + [self setRoomSettingsBasedOnIndex]; + ChatConversationView *view = VIEW(ChatConversationView); + [PhoneMainView.instance popToView:view.compositeViewDescription]; +} + +#pragma mark - TableView + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 6; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell = [[UITableViewCell alloc] init]; + + switch(indexPath.row) { + case 0:cell.textLabel.text = NSLocalizedString(@"Disabled",nil);break; + case 1:cell.textLabel.text = NSLocalizedString(@"1 minute",nil);break; + case 2:cell.textLabel.text = NSLocalizedString(@"1 hour",nil);break; + case 3:cell.textLabel.text = NSLocalizedString(@"1 day",nil);break; + case 4:cell.textLabel.text = NSLocalizedString(@"3 days",nil);break; + case 5:cell.textLabel.text = NSLocalizedString(@"1 week",nil);break; + } + if (indexPath.row == _selectedIndex) { + cell.accessoryType = UITableViewCellAccessoryCheckmark; + cell.textLabel.font = [UIFont fontWithDescriptor:[cell.textLabel.font.fontDescriptor fontDescriptorWithSymbolicTraits:UIFontDescriptorTraitBold] + size:cell.textLabel.font.pointSize]; + } + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + _selectedIndex = indexPath.row; + [_tableView reloadData]; +} + +#pragma mark - BL Functions + +-(void) setIndexBasedOnRoomSetting { + if (!linphone_chat_room_ephemeral_enabled(_room)) { + _selectedIndex = 0; + }else if (linphone_chat_room_get_ephemeral_lifetime(_room) == 60) { + _selectedIndex = 1; + }else if (linphone_chat_room_get_ephemeral_lifetime(_room) == 3600) { + _selectedIndex = 2; + }else if (linphone_chat_room_get_ephemeral_lifetime(_room) == 86400) { + _selectedIndex = 3; + }else if (linphone_chat_room_get_ephemeral_lifetime(_room) == 3*86400) { + _selectedIndex = 4; + }else if (linphone_chat_room_get_ephemeral_lifetime(_room) == 7*86400) { + _selectedIndex = 5; + } +} + +-(void) setRoomSettingsBasedOnIndex { + if (_selectedIndex == 0) { + linphone_chat_room_enable_ephemeral(_room, false); + return; + } + + linphone_chat_room_enable_ephemeral(_room, true); + switch (_selectedIndex) { + case 1: linphone_chat_room_set_ephemeral_lifetime(_room, 60);break; + case 2: linphone_chat_room_set_ephemeral_lifetime(_room, 3600);break; + case 3: linphone_chat_room_set_ephemeral_lifetime(_room, 86400);break; + case 4: linphone_chat_room_set_ephemeral_lifetime(_room, 3*86400);break; + case 5: linphone_chat_room_set_ephemeral_lifetime(_room, 7*86400);break; + } + +} + +@end diff --git a/Classes/EphemeralSettingsView.xib b/Classes/EphemeralSettingsView.xib new file mode 100644 index 000000000..d5bdf2a17 --- /dev/null +++ b/Classes/EphemeralSettingsView.xib @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 710338ea6..319302535 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -59,6 +59,7 @@ extern NSString *const kLinphoneFileTransferSendUpdate; extern NSString *const kLinphoneFileTransferRecvUpdate; extern NSString *const kLinphoneQRCodeFound; extern NSString *const kLinphoneChatCreateViewChange; +extern NSString *const kLinphoneEphemeralMessageDeletedInRoom; extern NSString *const kLinphoneMsgNotificationAppGroupId; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 2c922c24e..1b2da6af8 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -74,6 +74,8 @@ NSString *const kLinphoneFileTransferSendUpdate = @"LinphoneFileTransferSendUpda NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpdate"; NSString *const kLinphoneQRCodeFound = @"LinphoneQRCodeFound"; NSString *const kLinphoneChatCreateViewChange = @"LinphoneChatCreateViewChange"; +NSString *const kLinphoneEphemeralMessageDeletedInRoom = @"LinphoneEphemeralMessageDeletedInRoom"; + NSString *const kLinphoneMsgNotificationAppGroupId = @"group.org.linphone.phone.msgNotification"; @@ -591,6 +593,18 @@ static void linphone_iphone_display_status(struct _LinphoneCore *lc, const char } } +#pragma mark - Ephemeral State Functions +static void linphone_iphone_ephemeral_message_deleted(LinphoneCore *lc, LinphoneChatRoom *cr) { + LinphoneManager *lm = (__bridge LinphoneManager *)linphone_core_cbs_get_user_data(linphone_core_get_current_callbacks(lc)); + NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:cr], @"room", nil]; + + // dispatch the notification asynchronously + dispatch_async(dispatch_get_main_queue(), ^(void) { + [NSNotificationCenter.defaultCenter postNotificationName:kLinphoneEphemeralMessageDeletedInRoom object:lm userInfo:dict]; + }); + +} + #pragma mark - Transfert State Functions static void linphone_iphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState state) { @@ -1356,6 +1370,8 @@ void popup_link_account_cb(LinphoneAccountCreator *creator, LinphoneAccountCreat linphone_core_cbs_set_call_log_updated(cbs, linphone_iphone_call_log_updated); linphone_core_cbs_set_call_id_updated(cbs, linphone_iphone_call_id_updated); linphone_core_cbs_set_user_data(cbs, (__bridge void *)(self)); + linphone_core_cbs_set_chat_room_ephemeral_message_deleted(cbs, linphone_iphone_ephemeral_message_deleted); + theLinphoneCore = linphone_factory_create_shared_core_with_config(factory, _configDb, NULL, [kLinphoneMsgNotificationAppGroupId UTF8String], true); linphone_core_add_callbacks(theLinphoneCore, cbs); diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib index da225bc9d..d320d6580 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib @@ -1,9 +1,9 @@ - + - + @@ -15,6 +15,8 @@ + + @@ -167,6 +169,17 @@ + + @@ -177,7 +190,7 @@ - + @@ -202,6 +215,7 @@ + diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib index bcdf8588c..481e4541a 100644 --- a/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib +++ b/Classes/LinphoneUI/Base.lproj/UIChatBubbleTextCell.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -15,21 +13,23 @@ + + - + - - + - - + + + diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h index bf34937d2..6778a8143 100644 --- a/Classes/LinphoneUI/UIChatBubbleTextCell.h +++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h @@ -45,6 +45,8 @@ //@property(weak, nonatomic) IBOutlet UILabel *imdmLabel; @property (nonatomic, strong) UIDocumentPickerViewController *documentPicker; @property (weak, nonatomic) IBOutlet UIView *innerView; +@property (weak, nonatomic) IBOutlet UILabel *ephemeralTime; +@property (weak, nonatomic) IBOutlet UIImageView *ephemeralIcon; @property(nonatomic) BOOL isFirst; @property(nonatomic) BOOL isLast; diff --git a/Classes/LinphoneUI/UIChatNotifiedEventCell.m b/Classes/LinphoneUI/UIChatNotifiedEventCell.m index 3057bc138..510d07e93 100644 --- a/Classes/LinphoneUI/UIChatNotifiedEventCell.m +++ b/Classes/LinphoneUI/UIChatNotifiedEventCell.m @@ -146,7 +146,20 @@ static const CGFloat NOTIFIED_CELL_HEIGHT = 44; break; } - + + case LinphoneEventLogTypeConferenceEphemeralMessageDisabled: { + eventString = [NSString stringWithFormat:NSLocalizedString(@"You disabled ephemeral messages", nil)]; + break; + } + case LinphoneEventLogTypeConferenceEphemeralMessageEnabled: { + eventString = [NSString stringWithFormat:NSLocalizedString(@"You enabled ephemeral messages", nil)]; + break; + } + case LinphoneEventLogTypeConferenceEphemeralMessageLifetimeChanged: { + eventString = [NSString stringWithFormat:NSLocalizedString(@"Ephemeral messages expiry date: %@",nil),[self formatEphemeralExpiration:linphone_event_log_get_ephemeral_message_lifetime(event)]]; + break; + } + default: return; } @@ -174,4 +187,17 @@ static const CGFloat NOTIFIED_CELL_HEIGHT = 44; [super layoutSubviews]; } +- (NSString *) formatEphemeralExpiration:(long)duration { + switch (duration) { + case 0:return NSLocalizedString(@"Disabled",nil);break; + case 60:return NSLocalizedString(@"1 minute",nil);break; + case 3600:return NSLocalizedString(@"1 hour",nil);break; + case 86400:return NSLocalizedString(@"1 day",nil);break; + case 259200:return NSLocalizedString(@"3 days",nil);break; + case 604800L:return NSLocalizedString(@"1 week",nil);break; + } + return NSLocalizedString(@"Unexpected duration",nil); +} + + @end diff --git a/Classes/Utils/Utils.h b/Classes/Utils/Utils.h index 0cee92791..7289bbe83 100644 --- a/Classes/Utils/Utils.h +++ b/Classes/Utils/Utils.h @@ -22,6 +22,11 @@ #define IPAD (LinphoneManager.runningOnIpad) #define ANIMATED ([LinphoneManager.instance lpConfigBoolForKey:@"animations_preference"]) #define LC ([LinphoneManager getLc]) +#define UIColorFromRGB(rgbValue) \ +[UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ + green:((float)((rgbValue & 0x00FF00) >> 8))/255.0 \ + blue:((float)((rgbValue & 0x0000FF) >> 0))/255.0 \ + alpha:1.0] @interface LinphoneUtils : NSObject @@ -31,6 +36,7 @@ + (void)buttonMultiViewAddAttributes:(NSMutableDictionary*)attributes button:(UIButton*)button; + (void)buttonMultiViewApplyAttributes:(NSDictionary*)attributes button:(UIButton*)button; + (NSString *)deviceModelIdentifier; ++ (UIImage *)resizeImage:(UIImage *)imageToResize newSize:(CGSize)newSize; + (LinphoneAddress *)normalizeSipOrPhoneAddress:(NSString *)addr; + (UIAlertController *)networkErrorView; diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index 0fc436eac..4f6d1249d 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -30,6 +30,15 @@ @implementation LinphoneUtils + ++ (UIImage *)resizeImage:(UIImage *)imageToResize newSize:(CGSize)newSize { + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize]; + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) { + [imageToResize drawInRect:(CGRect) {.origin = CGPointZero, .size = newSize}]; + }]; + return [image imageWithRenderingMode:imageToResize.renderingMode]; +} + + (BOOL)hasSelfAvatar { return [LinphoneManager.instance lpConfigStringForKey:@"avatar"] != nil; } @@ -918,4 +927,5 @@ return imgRef; } + @end diff --git a/Resources/en.lproj/Localizable.strings b/Resources/en.lproj/Localizable.strings index 6b66641c8..a69217772 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 b44a1e848..98505bc0a 100644 Binary files a/Resources/fr.lproj/Localizable.strings and b/Resources/fr.lproj/Localizable.strings differ diff --git a/Resources/images/ephemeral_messages_color_A.png b/Resources/images/ephemeral_messages_color_A.png new file mode 100644 index 000000000..19753e7f1 Binary files /dev/null and b/Resources/images/ephemeral_messages_color_A.png differ diff --git a/Resources/images/ephemeral_messages_default.png b/Resources/images/ephemeral_messages_default.png new file mode 100644 index 000000000..fed52afb5 Binary files /dev/null and b/Resources/images/ephemeral_messages_default.png differ diff --git a/Resources/images/menu_security_default.png b/Resources/images/menu_security_default.png new file mode 100644 index 000000000..51ee24fd9 Binary files /dev/null and b/Resources/images/menu_security_default.png differ diff --git a/Resources/images/more_menu_default.png b/Resources/images/more_menu_default.png new file mode 100644 index 000000000..aa544d0ed Binary files /dev/null and b/Resources/images/more_menu_default.png differ diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 71986178a..0a53db91c 100644 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -674,6 +674,12 @@ 8CF25D9E1F9F76BD00BEA0C1 /* chat_group_informations@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D9C1F9F76BD00BEA0C1 /* chat_group_informations@2x.png */; }; 93566413F75DA69D2811A716 /* Pods_msgNotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F30EA7BEA39DA427CE0754E /* Pods_msgNotificationService.framework */; }; A634ABAFCB39B6AAE4CA991D /* Pods_linphone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65CEDD144CABFAA70A29AF27 /* Pods_linphone.framework */; }; + 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 */; }; + 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 */; }; C6DA657C261C950C0020CB43 /* VFSUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6DA657B261C950C0020CB43 /* VFSUtil.swift */; }; @@ -1710,6 +1716,13 @@ ADCA571A7CF61077747BFE53 /* Pods-msgNotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationService.debug.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationService/Pods-msgNotificationService.debug.xcconfig"; sourceTree = ""; }; BAD0A9494E833034EB559687 /* Pods-msgNotificationContent.distributionadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-msgNotificationContent.distributionadhoc.xcconfig"; path = "Pods/Target Support Files/Pods-msgNotificationContent/Pods-msgNotificationContent.distributionadhoc.xcconfig"; sourceTree = ""; }; BE06BDE664323B2A53469696 /* Pods-liblinphoneTesterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-liblinphoneTesterTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-liblinphoneTesterTests/Pods-liblinphoneTesterTests.release.xcconfig"; sourceTree = ""; }; + 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 = ""; }; + 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 = ""; }; 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 = ""; }; @@ -2063,6 +2076,9 @@ 631098471D4660580041F2B3 /* CountryListView.h */, 631098481D4660580041F2B3 /* CountryListView.m */, 631098501D4660630041F2B3 /* CountryListView.xib */, + C64A854C2667B66900252AD2 /* EphemeralSettingsView.h */, + C64A854D2667B67200252AD2 /* EphemeralSettingsView.m */, + C64A854F2667B67A00252AD2 /* EphemeralSettingsView.xib */, 61AEBEB5219198EF00F35E7F /* DevicesListView.h */, 61AEBEBC2191990A00F35E7F /* DevicesListView.m */, 61AEBEBE2191991F00F35E7F /* DevicesListView.xib */, @@ -2439,6 +2455,10 @@ 633FEBE11D3CD5570014B822 /* images */ = { isa = PBXGroup; children = ( + C61B1BF62667EC6B001A4E4A /* ephemeral_messages_color_A.png */, + C61B1BF32667D202001A4E4A /* more_menu_default.png */, + C61B1BF12667D075001A4E4A /* menu_security_default.png */, + C64A85512667B74100252AD2 /* ephemeral_messages_default.png */, 633FEBE21D3CD5570014B822 /* add_field_default.png */, 633FEBE31D3CD5570014B822 /* add_field_default@2x.png */, 633FEBE41D3CD5570014B822 /* add_field_over.png */, @@ -3387,6 +3407,7 @@ 633FEE9C1D3CD55A0014B822 /* numpad_0_default@2x.png in Resources */, 633FEE3C1D3CD5590014B822 /* contacts_all_default.png in Resources */, 633FEE171D3CD5590014B822 /* chat_send_disabled@2x.png in Resources */, + C61B1BF22667D075001A4E4A /* menu_security_default.png in Resources */, 633FEE6E1D3CD5590014B822 /* footer_history_default.png in Resources */, 633FEEB21D3CD55A0014B822 /* numpad_2~ipad@2x.png in Resources */, 633FEDC61D3CD5590014B822 /* call_incoming.png in Resources */, @@ -3530,6 +3551,7 @@ 633FEDED1D3CD5590014B822 /* call_status_outgoing~ipad@2x.png in Resources */, 633FEE2D1D3CD5590014B822 /* color_E.png in Resources */, 633FEED01D3CD55A0014B822 /* numpad_6_over~ipad@2x.png in Resources */, + C64A85502667B67A00252AD2 /* EphemeralSettingsView.xib in Resources */, 633FEEC81D3CD55A0014B822 /* numpad_5_over~ipad@2x.png in Resources */, 61586B91217A175D0038AC45 /* menu_recordings.png in Resources */, 633FEF1B1D3CD55A0014B822 /* presence_away@2x.png in Resources */, @@ -3684,7 +3706,9 @@ 633FEEBC1D3CD55A0014B822 /* numpad_4_default@2x.png in Resources */, 633FEEA91D3CD55A0014B822 /* numpad_1~ipad.png in Resources */, 615A28402180A2620060F920 /* invite_linphone@2x.png in Resources */, + C61B1BF42667D202001A4E4A /* more_menu_default.png in Resources */, 633FEDF71D3CD5590014B822 /* camera_default@2x.png in Resources */, + C64A85522667B74100252AD2 /* ephemeral_messages_default.png in Resources */, 633FEDB31D3CD5590014B822 /* call_alt_back_default@2x.png in Resources */, 633FEDCF1D3CD5590014B822 /* call_quality_indicator_1@2x.png in Resources */, 633FEF131D3CD55A0014B822 /* pause_big_over_selected@2x.png in Resources */, @@ -3861,6 +3885,7 @@ 633FEF3B1D3CD55A0014B822 /* security_ko@2x.png in Resources */, 633FEE4A1D3CD5590014B822 /* delete_disabled.png in Resources */, 614D09CE21E74D5400C43EDF /* GoogleService-Info.plist 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 */, 633FEDCB1D3CD5590014B822 /* call_outgoing@2x.png in Resources */, @@ -4299,6 +4324,7 @@ D380800015C2894A005BE9BC /* IASKSwitch.m in Sources */, D380800215C2894A005BE9BC /* IASKTextField.m in Sources */, D380801315C299D0005BE9BC /* ColorSpaceUtilites.m in Sources */, + C64A854E2667B67200252AD2 /* EphemeralSettingsView.m in Sources */, 8C92ABF31FA773E50006FB5D /* UIChatNotifiedEventCell.m in Sources */, 633FEF581D3CD5E00014B822 /* UIAvatarPresence.m in Sources */, 637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */, @@ -4933,7 +4959,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"4.5.0\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5056,7 +5082,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"4.5.0\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5178,7 +5204,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"4.5.0\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone; @@ -5299,7 +5325,7 @@ "-DENABLE_QRCODE=TRUE", "-DENABLE_SMS_INVITE=TRUE", "$(inherited)", - "-DLINPHONE_SDK_VERSION=\\\"4.5.0\\\"", + "-DLINPHONE_SDK_VERSION=\\\"5.0.0-alpha.109+40dd0cf\\\"", ); OTHER_SWIFT_FLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone;