/* * 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 "ChatConversationInfoView.h" #import "PhoneMainView.h" #import "UIChatConversationInfoTableViewCell.h" #import "linphone/core.h" @implementation ChatConversationInfoView #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; } + (void)displayCreationError { static UIAlertController *errorView = nil; // avoid having multiple popups [PhoneMainView.instance dismissViewControllerAnimated:YES completion:nil]; errorView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Chat room creation error", nil) message:NSLocalizedString(@"Chat room could not be created on server", nil) preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; [errorView addAction:defaultAction]; [PhoneMainView.instance presentViewController:errorView animated:YES completion:nil]; } - (void)viewDidLoad { [super viewDidLoad]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboards)]; tap.delegate = self; [self.view addGestureRecognizer:tap]; UITapGestureRecognizer *particpantsBarTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onAddClick:)]; particpantsBarTap.delegate = self; [_participantsBar addGestureRecognizer:particpantsBarTap]; _nameLabel.delegate = self; _tableView.dataSource = self; _tableView.delegate = self; _admins = [[NSMutableArray alloc] init]; _oldAdmins = [[NSMutableArray alloc] init]; _oldContacts = [[NSMutableArray alloc] init]; _room = NULL; _chatRoomCbs = NULL; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; _waitView.hidden = YES; if (_create) _room = NULL; _nameLabel.text = _room && linphone_chat_room_get_subject(_room) ? [NSString stringWithUTF8String:linphone_chat_room_get_subject(_room)] : @""; _nextButton.enabled = _nameLabel.text.length > 0 && _contacts.count > 0; LinphoneParticipant *me = _room && !linphone_chat_room_has_been_left(_room) ? linphone_chat_room_get_me(_room) : NULL; _imAdmin = me ? linphone_participant_is_admin(me) : false; _quitButton.hidden = _create || (me == NULL); _nameLabel.enabled = _create || _imAdmin; _addButton.hidden = !_create && !_imAdmin; _nextButton.hidden = !_create && !_imAdmin; CGFloat height = _quitButton.hidden ? self.view.frame.size.height - _tableView.frame.origin.y : _quitButton.frame.origin.y - _tableView.frame.origin.y - 10; [_tableView setFrame:CGRectMake( _tableView.frame.origin.x, _tableView.frame.origin.y, _tableView.frame.size.width, height )]; if (_room) { _chatRoomCbs = linphone_factory_create_chat_room_cbs(linphone_factory_get()); linphone_chat_room_cbs_set_state_changed(_chatRoomCbs, main_view_chat_room_state_changed); linphone_chat_room_cbs_set_subject_changed(_chatRoomCbs, chat_room_subject_changed); linphone_chat_room_cbs_set_participant_added(_chatRoomCbs, chat_room_participant_added); linphone_chat_room_cbs_set_participant_removed(_chatRoomCbs, chat_room_participant_removed); linphone_chat_room_cbs_set_participant_admin_status_changed(_chatRoomCbs, chat_room_participant_admin_status_changed); linphone_chat_room_cbs_set_user_data(_chatRoomCbs, (__bridge void*)self); linphone_chat_room_add_callbacks(_room, _chatRoomCbs); } [_tableView reloadData]; } - (void)viewWillDisappear:(BOOL)animated { [self removeCallbacks]; } - (void)removeCallbacks { if (!_room || !_chatRoomCbs) return; linphone_chat_room_remove_callbacks(_room, _chatRoomCbs); _chatRoomCbs = NULL; } #pragma mark - next functions - (void)onCreate { bctbx_list_t *addresses = NULL; for (NSString *addr in _contacts) { LinphoneAddress *linphoneAddress = linphone_address_new(addr.UTF8String); if (!linphoneAddress) continue; if (!addresses) { addresses = bctbx_list_new((void *)linphoneAddress); continue; } addresses = bctbx_list_append(addresses, (void *)linphoneAddress); } [PhoneMainView.instance createChatRoom:_nameLabel.text.UTF8String addresses:addresses andWaitView:_waitView isEncrypted:_encrypted isGroup:TRUE]; bctbx_list_free_with_data(addresses, (void (*)(void *))linphone_address_unref); } - (void)onValidate { ChatConversationView *view = VIEW(ChatConversationView); // Change subject if necessary if (![_oldSubject isEqualToString:_nameLabel.text]) linphone_chat_room_set_subject(_room, _nameLabel.text.UTF8String); // Add participants if necessary bctbx_list_t *addedPartipants = NULL; for (NSString *uri in _contacts) { if ([_oldContacts containsObject:uri]) continue; LinphoneAddress *addr = linphone_address_new(uri.UTF8String); linphone_address_clean(addr);//keep only username@domain if (addedPartipants) addedPartipants = bctbx_list_append(addedPartipants, addr); else addedPartipants = bctbx_list_new(addr); } if (addedPartipants) { linphone_chat_room_add_participants(_room, addedPartipants); bctbx_list_free_with_data(addedPartipants, (void (*)(void *))linphone_address_unref); } // Remove participants if necessary bctbx_list_t *removedPartipants = NULL; for (NSString *uri in _oldContacts) { if ([_contacts containsObject:uri]) continue; LinphoneAddress *addr = linphone_address_new(uri.UTF8String); LinphoneParticipant *participant = linphone_participant_ref(linphone_chat_room_find_participant(_room, addr)); if (!participant) continue; if (removedPartipants) removedPartipants = bctbx_list_append(removedPartipants, participant); else removedPartipants = bctbx_list_new(participant); linphone_address_unref(addr); } if (removedPartipants) { linphone_chat_room_remove_participants(_room, removedPartipants); bctbx_list_free_with_data(removedPartipants, (void (*)(void *))linphone_participant_unref); } // add admins if necessary for (NSString *admin in _admins) { if ([_oldAdmins containsObject:admin]) continue; LinphoneAddress *addr = linphone_address_new(admin.UTF8String); LinphoneParticipant *participant = linphone_chat_room_find_participant(_room, addr); if (!participant) continue; linphone_chat_room_set_participant_admin_status(_room, participant, true); linphone_address_unref(addr); } // remove admins if necessary for (NSString *admin in _oldAdmins) { if ([_admins containsObject:admin]) continue; LinphoneAddress *addr = linphone_address_new(admin.UTF8String); LinphoneParticipant *participant = linphone_chat_room_find_participant(_room, addr); if (!participant) continue; linphone_chat_room_set_participant_admin_status(_room, participant, false); linphone_address_unref(addr); } [PhoneMainView.instance changeCurrentView:view.compositeViewDescription]; } #pragma mark - Buttons responders - (IBAction)onNextClick:(id)sender { if(_create) [self onCreate]; else [self onValidate]; } - (IBAction)onBackClick:(id)sender { if(_create) { ChatConversationCreateView *view = VIEW(ChatConversationCreateView); view.tableController.contactsGroup = [_contacts mutableCopy]; view.tableController.notFirstTime = TRUE; view.isForEditing = FALSE; [PhoneMainView.instance popToView:view.compositeViewDescription]; } else { ChatConversationView *view = VIEW(ChatConversationView); [PhoneMainView.instance popToView:view.compositeViewDescription]; } } - (IBAction)onQuitClick:(id)sender { NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"Do you want to leave this conversation?", nil)]; [UIConfirmationDialog ShowWithMessage:msg cancelMessage:nil confirmMessage:NSLocalizedString(@"LEAVE", nil) onCancelClick:^() {} onConfirmationClick:^() { linphone_chat_room_leave(_room); }]; } - (IBAction)onAddClick:(id)sender { if (_create || _imAdmin) { ChatConversationCreateView *view = VIEW(ChatConversationCreateView); view.tableController.notFirstTime = TRUE; view.isForEditing = !_create; view.isGroupChat = TRUE; view.tableController.contactsGroup = [_contacts mutableCopy]; [PhoneMainView.instance popToView:view.compositeViewDescription]; } } #pragma mark - TableView - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _contacts.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *kCellId = NSStringFromClass(UIChatConversationInfoTableViewCell.class); UIChatConversationInfoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellId]; if (cell == nil) { cell = [[UIChatConversationInfoTableViewCell alloc] initWithIdentifier:kCellId]; } cell.uri = _contacts[indexPath.row]; LinphoneAddress *addr = linphone_address_new(cell.uri.UTF8String); cell.nameLabel.text = (addr == nil? cell.uri : [FastAddressBook displayNameForAddress:addr]); [cell.avatarImage setImage:[FastAddressBook imageForAddress:addr] bordered:YES withRoundedRadius:YES]; cell.controllerView = self; if(![_admins containsObject:cell.uri]) { cell.adminLabel.enabled = FALSE; cell.adminImage.image = [UIImage imageNamed:@"check_unselected.png"]; } cell.adminButton.hidden = _create || (!_imAdmin && !cell.adminLabel.enabled) || ![_oldContacts containsObject:cell.uri]; cell.adminButton.userInteractionEnabled = _imAdmin; cell.removeButton.hidden = !_create && !_imAdmin; if (addr) linphone_address_unref(addr); return cell; } #pragma mark - searchBar delegate - (void)dismissKeyboards { if ([_nameLabel isFirstResponder]) { [_nameLabel resignFirstResponder]; } } #pragma mark - UITextFieldDelegate - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { _nextButton.enabled = (!((string.length == 0 || string == nil || [string isEqual:@""]) && (textField.text.length == 1)) && _contacts.count > 0); return TRUE; } #pragma mark - chat room callbacks - (void)myAdminStatusChanged:(BOOL)admin { NSString *message = admin ? NSLocalizedString(@"You are now an admin of the chat room", nil) : NSLocalizedString(@"You are no longer an admin of the chat room", nil); static UIAlertController *alertView = nil; // avoid having multiple popups [PhoneMainView.instance dismissViewControllerAnimated:YES completion:nil]; alertView = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"%@", message] message:nil preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; [alertView addAction:defaultAction]; [PhoneMainView.instance presentViewController:alertView animated:YES completion:nil]; } void chat_room_subject_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) { ChatConversationInfoView *view = (__bridge ChatConversationInfoView *)linphone_chat_room_cbs_get_user_data(linphone_chat_room_get_current_callbacks(cr)); view.nameLabel.text = [NSString stringWithUTF8String:linphone_event_log_get_subject(event_log)]; } void chat_room_participant_added(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) { ChatConversationInfoView *view = (__bridge ChatConversationInfoView *)linphone_chat_room_cbs_get_user_data(linphone_chat_room_get_current_callbacks(cr)); char *str = linphone_address_as_string(linphone_event_log_get_participant_address(event_log)); NSString *participantAddress = [NSString stringWithUTF8String:str]; ms_free(str); [view.oldContacts addObject:participantAddress]; [view.contacts addObject:participantAddress]; [view.tableView reloadData]; } void chat_room_participant_removed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) { ChatConversationInfoView *view = (__bridge ChatConversationInfoView *)linphone_chat_room_cbs_get_user_data(linphone_chat_room_get_current_callbacks(cr)); char *str = linphone_address_as_string(linphone_event_log_get_participant_address(event_log)); NSString *participantAddress = [NSString stringWithUTF8String:str]; ms_free(str); [view.oldContacts removeObject:participantAddress]; [view.contacts removeObject:participantAddress]; [view.tableView reloadData]; } void chat_room_participant_admin_status_changed(LinphoneChatRoom *cr, const LinphoneEventLog *event_log) { ChatConversationInfoView *view = (__bridge ChatConversationInfoView *)linphone_chat_room_cbs_get_user_data(linphone_chat_room_get_current_callbacks(cr)); char *str = linphone_address_as_string(linphone_event_log_get_participant_address(event_log)); NSString *participantAddress = [NSString stringWithUTF8String:str]; ms_free(str); LinphoneParticipant *me = linphone_chat_room_get_me(cr); if (me && linphone_address_equal(linphone_participant_get_address(me), linphone_event_log_get_participant_address(event_log))) { [view myAdminStatusChanged:(linphone_event_log_get_type(event_log) == LinphoneEventLogTypeConferenceParticipantSetAdmin)]; [view viewWillAppear:TRUE]; return; } if (linphone_event_log_get_type(event_log) == LinphoneEventLogTypeConferenceParticipantSetAdmin) { [view.admins addObject:participantAddress]; [view.oldAdmins addObject:participantAddress]; } else { // linphone_event_log_get_type(event_log) == LinphoneEventLogTypeConferenceParticipantUnsetAdmin [view.admins removeObject:participantAddress]; [view.oldAdmins removeObject:participantAddress]; } [view.tableView reloadData]; } @end