diff --git a/Classes/AssistantView.m b/Classes/AssistantView.m index c367566f1..2e0d68ad1 100644 --- a/Classes/AssistantView.m +++ b/Classes/AssistantView.m @@ -478,7 +478,7 @@ static UICompositeViewDescription *compositeDescription = nil; switch (state) { case LinphoneRegistrationOk: { _waitView.hidden = true; - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]]; break; } case LinphoneRegistrationNone: @@ -604,7 +604,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (IBAction)onDialerBackClick:(id)sender { - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]]; } - (IBAction)onGotoCreateAccountClick:(id)sender { @@ -689,7 +689,7 @@ static UICompositeViewDescription *compositeDescription = nil; block:^{ _waitView.hidden = true; [self addProxyConfig:username password:password domain:domain withTransport:transport]; - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]]; }]; [alert show]; } else { diff --git a/Classes/CallIncomingView.m b/Classes/CallIncomingView.m index 6a50f7a7f..dd22f86a8 100644 --- a/Classes/CallIncomingView.m +++ b/Classes/CallIncomingView.m @@ -92,8 +92,8 @@ static UICompositeViewDescription *compositeDescription = nil; } - (void)dismiss { - if ([[[PhoneMainView instance] currentView] equal:[CallIncomingView compositeViewDescription]]) { - [[PhoneMainView instance] popCurrentView]; + if ([[PhoneMainView.instance currentView] equal:[CallIncomingView compositeViewDescription]]) { + [PhoneMainView.instance popCurrentView]; } } diff --git a/Classes/CallOutgoingView.m b/Classes/CallOutgoingView.m index de16f25cc..a9aecad4a 100644 --- a/Classes/CallOutgoingView.m +++ b/Classes/CallOutgoingView.m @@ -44,7 +44,7 @@ static UICompositeViewDescription *compositeDescription = nil; LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]); if (!call) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } else { const LinphoneAddress *addr = linphone_call_get_remote_address(call); [ContactDisplay setDisplayNameLabel:_nameLabel forAddress:addr]; @@ -61,6 +61,6 @@ static UICompositeViewDescription *compositeDescription = nil; if (call) { linphone_core_terminate_call([LinphoneManager getLc], call); } - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } @end diff --git a/Classes/CallView.m b/Classes/CallView.m index f74a55107..c52a7ca5a 100644 --- a/Classes/CallView.m +++ b/Classes/CallView.m @@ -62,7 +62,7 @@ const NSInteger SECURE_BUTTON_TAG = 5; } - (void)dealloc { - [[PhoneMainView instance].view removeGestureRecognizer:singleFingerTap]; + [PhoneMainView.instance.view removeGestureRecognizer:singleFingerTap]; // Remove all observer [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -94,7 +94,7 @@ static UICompositeViewDescription *compositeDescription = nil; UIDevice *device = [UIDevice currentDevice]; device.proximityMonitoringEnabled = YES; - [[PhoneMainView instance] setVolumeHidden:TRUE]; + [PhoneMainView.instance setVolumeHidden:TRUE]; hiddenVolume = TRUE; } @@ -106,7 +106,7 @@ static UICompositeViewDescription *compositeDescription = nil; } if (hiddenVolume) { - [[PhoneMainView instance] setVolumeHidden:FALSE]; + [PhoneMainView.instance setVolumeHidden:FALSE]; hiddenVolume = FALSE; } @@ -142,7 +142,7 @@ static UICompositeViewDescription *compositeDescription = nil; UIDevice *device = [UIDevice currentDevice]; device.proximityMonitoringEnabled = NO; - [[PhoneMainView instance] fullScreen:false]; + [PhoneMainView.instance fullScreen:false]; // Disable tap [singleFingerTap setEnabled:FALSE]; } @@ -152,7 +152,7 @@ static UICompositeViewDescription *compositeDescription = nil; [singleFingerTap setNumberOfTapsRequired:1]; [singleFingerTap setCancelsTouchesInView:FALSE]; - [[PhoneMainView instance].view addGestureRecognizer:singleFingerTap]; + [PhoneMainView.instance.view addGestureRecognizer:singleFingerTap]; [videoZoomHandler setup:videoGroup]; videoGroup.alpha = 0; @@ -167,7 +167,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)viewDidUnload { [super viewDidUnload]; - [[PhoneMainView instance].view removeGestureRecognizer:singleFingerTap]; + [PhoneMainView.instance.view removeGestureRecognizer:singleFingerTap]; } - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation @@ -187,7 +187,7 @@ static UICompositeViewDescription *compositeDescription = nil; LinphoneCore *lc = [LinphoneManager getLc]; if (hiddenVolume) { - [[PhoneMainView instance] setVolumeHidden:FALSE]; + [PhoneMainView.instance setVolumeHidden:FALSE]; hiddenVolume = FALSE; } @@ -272,12 +272,12 @@ static UICompositeViewDescription *compositeDescription = nil; hideControlsTimer = nil; } - if ([[[PhoneMainView instance] currentView] equal:[CallView compositeViewDescription]] && videoShown) { + if ([[PhoneMainView.instance currentView] equal:[CallView compositeViewDescription]] && videoShown) { // show controls [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:0.3]; - [[PhoneMainView instance] showTabBar:true]; - [[PhoneMainView instance] showStateBar:true]; + [PhoneMainView.instance showTabBar:true]; + [PhoneMainView.instance showStateBar:true]; [callTableView setAlpha:1.0]; [videoCameraSwitch setAlpha:1.0]; [UIView commitAnimations]; @@ -297,15 +297,15 @@ static UICompositeViewDescription *compositeDescription = nil; hideControlsTimer = nil; } - if ([[[PhoneMainView instance] currentView] equal:[CallView compositeViewDescription]] && videoShown) { + if ([[PhoneMainView.instance currentView] equal:[CallView compositeViewDescription]] && videoShown) { [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:0.3]; [videoCameraSwitch setAlpha:0.0]; [callTableView setAlpha:0.0]; [UIView commitAnimations]; - [[PhoneMainView instance] showTabBar:false]; - [[PhoneMainView instance] showStateBar:false]; + [PhoneMainView.instance showTabBar:false]; + [PhoneMainView.instance showStateBar:false]; } } @@ -359,9 +359,9 @@ static UICompositeViewDescription *compositeDescription = nil; } [videoCameraSwitch setAlpha:0.0]; - [[PhoneMainView instance] fullScreen:true]; - [[PhoneMainView instance] showTabBar:false]; - [[PhoneMainView instance] showStateBar:false]; + [PhoneMainView.instance fullScreen:true]; + [PhoneMainView.instance showTabBar:false]; + [PhoneMainView.instance showStateBar:false]; #ifdef TEST_VIDEO_VIEW_CHANGE [NSTimer scheduledTimerWithTimeInterval:5.0 @@ -393,7 +393,7 @@ static UICompositeViewDescription *compositeDescription = nil; } [videoGroup setAlpha:0.0]; - [[PhoneMainView instance] showTabBar:true]; + [PhoneMainView.instance showTabBar:true]; UIEdgeInsets insets = {10, 0, 25, 0}; [callTableView setContentInset:insets]; @@ -415,7 +415,7 @@ static UICompositeViewDescription *compositeDescription = nil; hideControlsTimer = nil; } - [[PhoneMainView instance] fullScreen:false]; + [PhoneMainView.instance fullScreen:false]; } - (void)displayVideoCall:(BOOL)animated { @@ -486,7 +486,7 @@ static void hideSpinner(LinphoneCall *call, void *user_data) { if ([LinphoneManager runningOnIpad]) { [sheet addCancelButtonWithTitle:NSLocalizedString(@"Decline", nil) block:cancelBlock]; } - [sheet showInView:[PhoneMainView instance].view]; + [sheet showInView:PhoneMainView.instance.view]; } - (void)dismissVideoActionSheet:(NSTimer *)timer { diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m index 791cabc24..46d059313 100644 --- a/Classes/ChatConversationTableView.m +++ b/Classes/ChatConversationTableView.m @@ -19,7 +19,7 @@ #import "LinphoneManager.h" #import "ChatConversationTableView.h" -#import "UIChatConversationCell.h" +#import "UIChatBubbleCell.h" #import "PhoneMainView.h" @implementation ChatConversationTableView diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m index c9e4648ca..d2f7e711a 100644 --- a/Classes/ChatConversationView.m +++ b/Classes/ChatConversationView.m @@ -21,7 +21,7 @@ #import "PhoneMainView.h" #import "Utils.h" #import "FileTransferDelegate.h" -#import "UIChatConversationCell.h" +#import "UIChatBubbleCell.h" @implementation ChatConversationView @@ -183,7 +183,7 @@ static UICompositeViewDescription *compositeDescription = nil; const LinphoneAddress *linphoneAddress = linphone_chat_room_get_peer_address(chatRoom); if (linphoneAddress == NULL) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; UIAlertView *error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address", nil) message:NSLocalizedString(@"Either configure a SIP proxy server from settings prior to send a " @@ -277,7 +277,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st } [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; dispatch_async(dispatch_get_main_queue(), ^{ - [sheet showInView:[PhoneMainView instance].view]; + [sheet showInView:PhoneMainView.instance.view]; }); }); } @@ -425,7 +425,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st - (IBAction)onBackClick:(id)event { [self.tableController setChatRoom:NULL]; - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } - (IBAction)onEditClick:(id)event { @@ -482,12 +482,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st - (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info { // Dismiss popover on iPad if ([LinphoneManager runningOnIpad]) { - UICompositeViewDescription *description = [ImagePickerView compositeViewDescription]; - ImagePickerView *controller = DYNAMIC_CAST( - [[PhoneMainView instance].mainViewController getCachedController:description.content], ImagePickerView); - if (controller != nil) { - [controller.popoverController dismissPopoverAnimated:TRUE]; - } + [VIEW(ImagePickerView).popoverController dismissPopoverAnimated:TRUE]; } NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL]; @@ -566,7 +561,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st // Resize chat view { CGRect viewFrame = [[self view] frame]; - CGRect rect = [PhoneMainView instance].view.bounds; + CGRect rect = PhoneMainView.instance.view.bounds; CGPoint pos = {viewFrame.size.width, viewFrame.size.height}; CGPoint gPos = [self.view convertPoint:pos diff --git a/Classes/ChatsListTableView.m b/Classes/ChatsListTableView.m index b061781b0..1a1c17e87 100644 --- a/Classes/ChatsListTableView.m +++ b/Classes/ChatsListTableView.m @@ -138,12 +138,9 @@ static void chatTable_free_chatrooms(void *data) { - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; LinphoneChatRoom *chatRoom = (LinphoneChatRoom *)ms_list_nth_data(data, (int)[indexPath row]); - - // Go to ChatRoom view - ChatConversationView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], - ChatConversationView); - [controller setChatRoom:chatRoom]; + ChatsListTableView *view = VIEW(ChatConversationView); + [PhoneMainView.instance changeCurrentView:view push:TRUE]; + [view setChatRoom:chatRoom]; } - (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView diff --git a/Classes/ChatsListView.m b/Classes/ChatsListView.m index 3c5aec2ed..5db2c8b0d 100644 --- a/Classes/ChatsListView.m +++ b/Classes/ChatsListView.m @@ -80,12 +80,8 @@ static UICompositeViewDescription *compositeDescription = nil; LinphoneChatRoom *room = linphone_core_get_chat_room_from_uri([LinphoneManager getLc], [addressField.text UTF8String]); if (room != nil) { - ChatConversationView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], - ChatConversationView); - if (controller != nil) { - [controller setChatRoom:room]; - } + ChatConversationView *view = VIEW(ChatConversationView); + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription push:TRUE] [view setChatRoom:room]; } else { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid address", nil) message:@"Please specify the entire SIP address for the chat" @@ -103,7 +99,7 @@ static UICompositeViewDescription *compositeDescription = nil; [ContactSelection setSipFilter:[LinphoneManager instance].contactFilter]; [ContactSelection enableEmailFilter:FALSE]; [ContactSelection setNameOrEmailFilter:nil]; - [[PhoneMainView instance] changeCurrentView:[ContactsListView compositeViewDescription] push:TRUE]; + [PhoneMainView.instance changeCurrentView:[ContactsListView compositeViewDescription] push:TRUE]; } else { [self startChatRoom]; } diff --git a/Classes/ContactDetailsLabelView.m b/Classes/ContactDetailsLabelView.m index b92586ff0..eb8d9ec9b 100644 --- a/Classes/ContactDetailsLabelView.m +++ b/Classes/ContactDetailsLabelView.m @@ -49,8 +49,8 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - - (void)dismiss { - if ([[[PhoneMainView instance] currentView] equal:[ContactDetailsLabelView compositeViewDescription]]) { - [[PhoneMainView instance] popCurrentView]; + if ([[PhoneMainView.instance currentView] equal:[ContactDetailsLabelView compositeViewDescription]]) { + [PhoneMainView.instance popCurrentView]; } } diff --git a/Classes/ContactDetailsTableView.m b/Classes/ContactDetailsTableView.m index 413abaf57..b7ce8d9d4 100644 --- a/Classes/ContactDetailsTableView.m +++ b/Classes/ContactDetailsTableView.m @@ -610,24 +610,18 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSe NSString *displayName = [FastAddressBook getContactDisplayName:contact]; if ([ContactSelection getSelectionMode] != ContactSelectionModeMessage) { // Go to dialer view - DialerView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]], DialerView); - if (controller != nil) { - [controller call:dest displayName:displayName]; - } + DialerView *view = VIEW(DialerView); + [PhoneMainView.instance changeCurrentView:view]; + [view call:dest displayName:displayName]; } else { // Go to Chat room view - [[PhoneMainView instance] - popToView:[ChatsListView compositeViewDescription]]; // Got to Chat and push ChatRoom - ChatConversationView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ChatConversationView compositeViewDescription] - push:TRUE], - ChatConversationView); - if (controller != nil) { - LinphoneChatRoom *room = - linphone_core_get_chat_room_from_uri([LinphoneManager getLc], [dest UTF8String]); - [controller setChatRoom:room]; - } + [PhoneMainView.instance popToView:ChatsListView.compositeViewDescription]; + // Then push ChatRoom + ChatConversationView *view = VIEW(ChatConversationView); + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription push:TRUE]; + LinphoneChatRoom *room = + linphone_core_get_chat_room_from_uri([LinphoneManager getLc], [dest UTF8String]); + [view setChatRoom:room]; } } } else { @@ -646,8 +640,7 @@ static const ContactSections_e contactSections[ContactSections_MAX] = {ContactSe if (key != nil) { editingIndexPath = indexPath; ContactDetailsLabelView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ContactDetailsLabelView compositeViewDescription] - push:TRUE], + [PhoneMainView.instance changeCurrentView:[ContactDetailsLabelView compositeViewDescription] push:TRUE], ContactDetailsLabelView); if (controller != nil) { [controller setDataList:[self getLocalizedLabels]]; diff --git a/Classes/ContactDetailsView.m b/Classes/ContactDetailsView.m index dc49f9435..8826a5154 100644 --- a/Classes/ContactDetailsView.m +++ b/Classes/ContactDetailsView.m @@ -61,7 +61,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info ABAddressBookRevert(addressBook); contact = ABAddressBookGetPersonWithRecordID(addressBook, recordID); if (contact == NULL) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; return; } [tableController setContact:contact]; @@ -76,7 +76,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info - (void)removeContact { if (contact == NULL) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; return; } @@ -107,7 +107,7 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info - (void)saveData { if (contact == NULL) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; return; } @@ -248,7 +248,7 @@ static UICompositeViewDescription *compositeDescription = nil; if ([ContactSelection getSelectionMode] == ContactSelectionModeEdit) { [ContactSelection setSelectionMode:ContactSelectionModeNone]; } - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } - (IBAction)onEditClick:(id)event { @@ -265,7 +265,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)onRemove:(id)event { [self disableEdit:FALSE]; [self removeContact]; - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } - (void)onModification:(id)event { diff --git a/Classes/ContactsListTableView.m b/Classes/ContactsListTableView.m index 2331a3c15..cab86579b 100644 --- a/Classes/ContactsListTableView.m +++ b/Classes/ContactsListTableView.m @@ -230,9 +230,9 @@ static void sync_address_book(ABAddressBookRef addressBook, CFDictionaryRef info ABRecordRef lPerson = (__bridge ABRecordRef)([subDic objectForKey:[subDic keyAtIndex:[indexPath row]]]); // Go to Contact details view - ContactDetailsView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], - ContactDetailsView); + ContactDetailsView *controller = + DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], + ContactDetailsView); if (controller != nil) { if ([ContactSelection getSelectionMode] != ContactSelectionModeEdit) { [controller setContact:lPerson]; diff --git a/Classes/ContactsListView.m b/Classes/ContactsListView.m index 77cd03879..5cd226aa3 100644 --- a/Classes/ContactsListView.m +++ b/Classes/ContactsListView.m @@ -157,7 +157,7 @@ static UICompositeViewDescription *compositeDescription = nil; cancelButtonTitle:NSLocalizedString(@"Continue", nil) otherButtonTitles:nil]; [error show]; - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]]; } } @@ -234,9 +234,9 @@ static UICompositeViewDescription *compositeDescription = nil; - (IBAction)onAddContactClick:(id)event { // Go to Contact details view - ContactDetailsView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], - ContactDetailsView); + ContactDetailsView *controller = + DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], + ContactDetailsView); if (controller != nil) { if ([ContactSelection getAddAddress] == nil) { [controller newContact]; @@ -247,7 +247,7 @@ static UICompositeViewDescription *compositeDescription = nil; } - (IBAction)onBackClick:(id)event { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { @@ -266,7 +266,7 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - ABPeoplePickerDelegate - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; return; } @@ -285,7 +285,7 @@ static UICompositeViewDescription *compositeDescription = nil; NSString *phoneNumber = (NSString *)CFBridgingRelease(ABMultiValueCopyValueAtIndex(multiValue, valueIdx)); // Go to dialer view DialerView *controller = - DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]], DialerView); + DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]], DialerView); if (controller != nil) { [controller call:phoneNumber displayName:(NSString *)CFBridgingRelease(ABRecordCopyCompositeName(person))]; } diff --git a/Classes/DialerView.m b/Classes/DialerView.m index a7dcc6293..07cb372f3 100644 --- a/Classes/DialerView.m +++ b/Classes/DialerView.m @@ -398,15 +398,12 @@ static UICompositeViewDescription *compositeDescription = nil; [ContactSelection setSipFilter:nil]; [ContactSelection setNameOrEmailFilter:nil]; [ContactSelection enableEmailFilter:FALSE]; - ContactsListView *controller = - DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ContactsListView compositeViewDescription] push:TRUE], - ContactsListView); - if (controller != nil) { - } + ContactsListView *view = VIEW(ContactsListView); + [PhoneMainView.instance changeCurrentView:view.compositeViewDescription push:TRUE]; } - (IBAction)onBackClick:(id)event { - [[PhoneMainView instance] changeCurrentView:[CallView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[CallView compositeViewDescription]]; } - (IBAction)onAddressChange:(id)sender { diff --git a/Classes/HistoryDetailsView.m b/Classes/HistoryDetailsView.m index 9a8fe26f1..d9aacfb6e 100644 --- a/Classes/HistoryDetailsView.m +++ b/Classes/HistoryDetailsView.m @@ -150,7 +150,7 @@ static UICompositeViewDescription *compositeDescription = nil; // Pop if callLog is null [self retrieveCallLog]; if (callLog == NULL) { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; return; } @@ -169,13 +169,13 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - Action Functions - (IBAction)onBackClick:(id)event { - [[PhoneMainView instance] popCurrentView]; + [PhoneMainView.instance popCurrentView]; } - (IBAction)onContactClick:(id)event { if (contact) { ContactDetailsView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[ContactDetailsView compositeViewDescription] push:TRUE], ContactDetailsView); if (controller != nil) { [ContactSelection setSelectionMode:ContactSelectionModeNone]; @@ -198,7 +198,7 @@ static UICompositeViewDescription *compositeDescription = nil; [ContactSelection enableEmailFilter:FALSE]; [ContactSelection setNameOrEmailFilter:nil]; DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ContactsListView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[ContactsListView compositeViewDescription] push:TRUE], ContactsListView); ms_free(lAddress); } @@ -213,7 +213,7 @@ static UICompositeViewDescription *compositeDescription = nil; NSString *displayName = [FastAddressBook displayNameForAddress:addr]; DialerView *controller = - DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]], DialerView); + DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]], DialerView); if (controller != nil) { [controller call:[NSString stringWithUTF8String:lAddress] displayName:displayName]; } @@ -225,9 +225,9 @@ static UICompositeViewDescription *compositeDescription = nil; if (addr == NULL) return; // Go to ChatRoom view - [[PhoneMainView instance] changeCurrentView:[ChatsListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[ChatsListView compositeViewDescription]]; ChatConversationView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], ChatConversationView); if (controller != nil) { LinphoneChatRoom *room = linphone_core_get_chat_room([LinphoneManager getLc], addr); diff --git a/Classes/HistoryListTableView.m b/Classes/HistoryListTableView.m index 64b15d42b..285353488 100644 --- a/Classes/HistoryListTableView.m +++ b/Classes/HistoryListTableView.m @@ -145,8 +145,8 @@ char *uri = linphone_address_as_string(addr); // Go to dialer view - DialerView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]], DialerView); + DialerView *controller = + DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]], DialerView); if (controller != nil) { [controller call:[NSString stringWithUTF8String:uri] displayName:[FastAddressBook displayNameForAddress:addr]]; diff --git a/Classes/ImagePickerView.m b/Classes/ImagePickerView.m index dbfde612b..f63043e43 100644 --- a/Classes/ImagePickerView.m +++ b/Classes/ImagePickerView.m @@ -124,8 +124,8 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - - (void)dismiss { - if ([[[PhoneMainView instance] currentView] equal:[ImagePickerView compositeViewDescription]]) { - [[PhoneMainView instance] popCurrentView]; + if ([[PhoneMainView.instance currentView] equal:[ImagePickerView compositeViewDescription]]) { + [PhoneMainView.instance popCurrentView]; } } @@ -169,11 +169,10 @@ static UICompositeViewDescription *compositeDescription = nil; UICompositeViewDescription *description = [ImagePickerView compositeViewDescription]; ImagePickerView *controller; if ([LinphoneManager runningOnIpad] && view) { - controller = DYNAMIC_CAST( - [[PhoneMainView instance].mainViewController getCachedController:description.content], ImagePickerView); + controller = DYNAMIC_CAST([PhoneMainView.instance.mainViewController getCachedController:description.content], + ImagePickerView); } else { - controller = - DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:description push:TRUE], ImagePickerView); + controller = DYNAMIC_CAST([PhoneMainView.instance changeCurrentView:description push:TRUE], ImagePickerView); } if (controller != nil) { controller.sourceType = type; @@ -211,7 +210,7 @@ static UICompositeViewDescription *compositeDescription = nil; } [sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil]; - [sheet showInView:[PhoneMainView instance].view]; + [sheet showInView:PhoneMainView.instance.view]; } @end diff --git a/Classes/ImageView.m b/Classes/ImageView.m index 5e08e1391..c879f8195 100644 --- a/Classes/ImageView.m +++ b/Classes/ImageView.m @@ -147,8 +147,8 @@ static UICompositeViewDescription *compositeDescription = nil; #pragma mark - Action Functions - (IBAction)onBackClick:(id)sender { - if ([[[PhoneMainView instance] currentView] equal:[ImageView compositeViewDescription]]) { - [[PhoneMainView instance] popCurrentView]; + if ([[PhoneMainView.instance currentView] equal:[ImageView compositeViewDescription]]) { + [PhoneMainView.instance popCurrentView]; } } diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index 643747b60..8d21e465e 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -77,8 +77,8 @@ if (startedInBackground) { startedInBackground = FALSE; - [[PhoneMainView instance] startUp]; - [[PhoneMainView instance] updateStatusBar:nil]; + [PhoneMainView.instance startUp]; + [PhoneMainView.instance updateStatusBar:nil]; } LinphoneManager *instance = [LinphoneManager instance]; @@ -95,7 +95,7 @@ } instance->currentCallContextBeforeGoingBackground.call = 0; } else if (linphone_call_get_state(call) == LinphoneCallIncomingReceived) { - [[PhoneMainView instance] displayIncomingCall:call]; + [PhoneMainView.instance displayIncomingCall:call]; // in this case, the ringing sound comes from the notification. // To stop it we have to do the iOS7 ring fix... [self fixRing]; @@ -203,8 +203,8 @@ // initialize UI [self.window makeKeyAndVisible]; [RootViewManager setupWithPortrait:(PhoneMainView *)self.window.rootViewController]; - [[PhoneMainView instance] startUp]; - [[PhoneMainView instance] updateStatusBar:nil]; + [PhoneMainView.instance startUp]; + [PhoneMainView.instance updateStatusBar:nil]; NSDictionary *remoteNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey]; if (remoteNotif) { @@ -253,7 +253,7 @@ stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]]; DialerView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]], DialerView); + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]], DialerView); if (controller != nil) { [controller setAddress:sipUri]; } @@ -297,7 +297,7 @@ if ([loc_key isEqualToString:@"IM_MSG"]) { - [[PhoneMainView instance] changeCurrentView:[ChatsListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[ChatsListView compositeViewDescription]]; } else if ([loc_key isEqualToString:@"IC_MSG"]) { @@ -348,10 +348,10 @@ } else if ([notification.userInfo objectForKey:@"from_addr"] != nil) { NSString *remoteContact = (NSString *)[notification.userInfo objectForKey:@"from_addr"]; // Go to ChatRoom view - [[PhoneMainView instance] changeCurrentView:[ChatsListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[ChatsListView compositeViewDescription]]; LinphoneChatRoom *room = [self findChatRoomForContact:remoteContact]; ChatConversationView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[ChatConversationView compositeViewDescription] push:TRUE], ChatConversationView); if (controller != nil && room != nil) { [controller setChatRoom:room]; @@ -359,9 +359,9 @@ } else if ([notification.userInfo objectForKey:@"callLog"] != nil) { NSString *callLog = (NSString *)[notification.userInfo objectForKey:@"callLog"]; // Go to HistoryDetails view - [[PhoneMainView instance] changeCurrentView:[HistoryListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[HistoryListView compositeViewDescription]]; HistoryDetailsView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[HistoryDetailsView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[HistoryDetailsView compositeViewDescription] push:TRUE], HistoryDetailsView); if (controller != nil) { [controller setCallLogId:callLog]; @@ -446,7 +446,7 @@ LinphoneChatRoom *room = linphone_core_get_chat_room_from_uri(lc, [from UTF8String]); if (room) { linphone_chat_room_mark_as_read(room); - [[PhoneMainView instance] updateApplicationBadgeNumber]; + [PhoneMainView.instance updateApplicationBadgeNumber]; } } } @@ -477,7 +477,7 @@ cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil]; [error show]; - [[PhoneMainView instance] startUp]; + [PhoneMainView.instance startUp]; } if (state == LinphoneConfiguringFailed) { [[NSNotificationCenter defaultCenter] removeObserver:self name:kLinphoneConfiguringStateUpdate object:nil]; diff --git a/Classes/LinphoneUI/StatusBarView.m b/Classes/LinphoneUI/StatusBarView.m index d735fad4f..3645597f9 100644 --- a/Classes/LinphoneUI/StatusBarView.m +++ b/Classes/LinphoneUI/StatusBarView.m @@ -320,7 +320,7 @@ block:^() { weakSelf->securitySheet = nil; }]; - [securitySheet showInView:[PhoneMainView instance].view]; + [securitySheet showInView:PhoneMainView.instance.view]; } } } diff --git a/Classes/LinphoneUI/TabBarView.m b/Classes/LinphoneUI/TabBarView.m index 09eccbcd9..7408930b1 100644 --- a/Classes/LinphoneUI/TabBarView.m +++ b/Classes/LinphoneUI/TabBarView.m @@ -114,7 +114,7 @@ static NSString *const kDisappearAnimation = @"disappear"; - (void)changeViewEvent:(NSNotification *)notif { // UICompositeViewDescription *view = [notif.userInfo objectForKey: @"view"]; // if(view != nil) - [self updateSelectedButton:[[PhoneMainView instance] firstView]]; + [self updateSelectedButton:[PhoneMainView.instance firstView]]; } - (void)settingsUpdate:(NSNotification *)notif { @@ -141,7 +141,7 @@ static NSString *const kDisappearAnimation = @"disappear"; #pragma mark - UI Update - (void)update:(BOOL)appear { - [self updateSelectedButton:[[PhoneMainView instance] firstView]]; + [self updateSelectedButton:[PhoneMainView.instance firstView]]; [self updateMissedCall:linphone_core_get_missed_calls_count([LinphoneManager getLc]) appear:appear]; [self updateUnreadMessage:appear]; } @@ -236,7 +236,7 @@ static NSString *const kDisappearAnimation = @"disappear"; #pragma mark - Action Functions - (IBAction)onHistoryClick:(id)event { - [[PhoneMainView instance] changeCurrentView:[HistoryListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[HistoryListView compositeViewDescription]]; } - (IBAction)onContactsClick:(id)event { @@ -245,19 +245,19 @@ static NSString *const kDisappearAnimation = @"disappear"; [ContactSelection setSipFilter:nil]; [ContactSelection enableEmailFilter:FALSE]; [ContactSelection setNameOrEmailFilter:nil]; - [[PhoneMainView instance] changeCurrentView:[ContactsListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[ContactsListView compositeViewDescription]]; } - (IBAction)onDialerClick:(id)event { - [[PhoneMainView instance] changeCurrentView:[DialerView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[DialerView compositeViewDescription]]; } - (IBAction)onSettingsClick:(id)event { - [[PhoneMainView instance] changeCurrentView:[SettingsView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[SettingsView compositeViewDescription]]; } - (IBAction)onChatClick:(id)event { - [[PhoneMainView instance] changeCurrentView:[ChatsListView compositeViewDescription]]; + [PhoneMainView.instance changeCurrentView:[ChatsListView compositeViewDescription]]; } #pragma mark - Animation diff --git a/Classes/LinphoneUI/UIChatBubbleCell.m b/Classes/LinphoneUI/UIChatBubbleCell.m index 7baca4532..48bed3369 100644 --- a/Classes/LinphoneUI/UIChatBubbleCell.m +++ b/Classes/LinphoneUI/UIChatBubbleCell.m @@ -392,7 +392,7 @@ static UIFont *CELL_FONT = nil; } else { if (![messageImageView isLoading]) { ImageView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[ImageView compositeViewDescription] push:TRUE], ImageView); + [PhoneMainView.instance changeCurrentView:[ImageView compositeViewDescription] push:TRUE], ImageView); if (controller != nil) { CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; UIImage *fullScreen = [UIImage imageWithCGImage:fullScreenRef]; @@ -453,7 +453,7 @@ static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState st // message, so we must refresh the table when we change to this state to ensure that // all transient messages apppear // ChatRoomViewController *controller = DYNAMIC_CAST( - // [[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] + // [PhoneMainView.instance changeCurrentView:[ChatRoomViewController compositeViewDescription] // push:TRUE], // ChatRoomViewController); // [controller.tableController setChatRoom:linphone_chat_message_get_chat_room(msg)]; diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.h b/Classes/LinphoneUI/UIChatBubblePhotoCell.h index 1da692434..2fae8fe35 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.h +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.h @@ -1,13 +1,54 @@ -// -// UIChatPhotoBubbleCell.h -// linphone -// -// Created by Gautier Pelloux-Prayer on 09/09/15. -// -// +/* UIChatRoomCell.h + * + * Copyright (C) 2012 Belledonne Comunications, Grenoble, France + * + * 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 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#import + +#import "UILoadingImageView.h" #import "UITransparentTVCell.h" +#import "UITextViewNoDefine.h" +#import "FileTransferDelegate.h" +#import "ChatConversationTableView.h" @interface UIChatBubblePhotoCell : UITransparentTVCell +@property(nonatomic, strong) IBOutlet UIView *innerView; +@property(nonatomic, strong) IBOutlet UIView *bubbleView; +@property(nonatomic, strong) IBOutlet UIImageView *backgroundImage; +@property(nonatomic, strong) IBOutlet UITextViewNoDefine *messageText; +@property(nonatomic, strong) IBOutlet UILoadingImageView *messageImageView; +@property(nonatomic, strong) IBOutlet UIButton *deleteButton; +@property(nonatomic, strong) IBOutlet UILabel *dateLabel; +@property(nonatomic, strong) IBOutlet UIImageView *statusImage; +@property(nonatomic, strong) IBOutlet UIButton *downloadButton; +@property(weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress; +@property(weak, nonatomic) IBOutlet UIButton *cancelButton; +@property(nonatomic, strong) id chatRoomDelegate; + ++ (CGFloat)height:(LinphoneChatMessage *)chatMessage width:(int)width; + +- (void)setChatMessage:(LinphoneChatMessage *)message; +- (void)connectToFileDelegate:(FileTransferDelegate *)ftd; + +- (IBAction)onDeleteClick:(id)event; +- (IBAction)onDownloadClick:(id)event; +- (IBAction)onImageClick:(id)event; +- (IBAction)onCancelDownloadClick:(id)sender; +- (IBAction)onResendClick:(id)event; + @end diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m index db1d48ee0..402483b68 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m @@ -1,21 +1,459 @@ -// -// UIChatPhotoBubbleCell.m -// linphone -// -// Created by Gautier Pelloux-Prayer on 09/09/15. -// -// +/* UIChatRoomCell.m + * + * Copyright (C) 2012 Belledonne Comunications, Grenoble, France + * + * 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 2 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 Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ #import "UIChatBubblePhotoCell.h" +#import "LinphoneManager.h" +#import "PhoneMainView.h" -@implementation UIChatBubblePhotoCell +#import +#import -/* -// Only override drawRect: if you perform custom drawing. -// An empty implementation adversely affects performance during animation. -- (void)drawRect:(CGRect)rect { - // Drawing code +@implementation UIChatBubblePhotoCell { + LinphoneChatMessage *message; + FileTransferDelegate *ftd; +} + +static const CGFloat CELL_MIN_HEIGHT = 50.0f; +static const CGFloat CELL_MIN_WIDTH = 150.0f; +static const CGFloat CELL_MESSAGE_X_MARGIN = 26.0f + 10.0f; +static const CGFloat CELL_MESSAGE_Y_MARGIN = 36.0f; +static const CGFloat CELL_FONT_SIZE = 17.0f; +static const CGFloat CELL_IMAGE_HEIGHT = 100.0f; +static const CGFloat CELL_IMAGE_WIDTH = 100.0f; +static UIFont *CELL_FONT = nil; + +#pragma mark - Lifecycle Functions + +- (id)initWithIdentifier:(NSString *)identifier { + if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) { + [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil]; + + // shift message box, otherwise it will collide with the bubble + CGRect messageCoords = _messageText.frame; + messageCoords.origin.x += 2; + messageCoords.origin.y += 2; + messageCoords.size.width -= 5; + + _messageText.frame = messageCoords; + _messageText.allowSelectAll = TRUE; + } + + return self; +} + +- (void)dealloc { + [self disconnectFromFileDelegate]; + if (message) { + linphone_chat_message_set_user_data(message, NULL); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), NULL); + linphone_chat_message_unref(message); + message = NULL; + } +} + +#pragma mark - + +- (void)setChatMessage:(LinphoneChatMessage *)amessage { + if (amessage == message) { + return; + } + + [self disconnectFromFileDelegate]; + _messageImageView.image = nil; + + if (message) { + linphone_chat_message_unref(message); + linphone_chat_message_set_user_data(message, NULL); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), NULL); + } + + message = amessage; + if (amessage) { + linphone_chat_message_ref(message); + linphone_chat_message_set_user_data(message, (void *)CFBridgingRetain(self)); + linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(message), message_status); + + const LinphoneContent *c = linphone_chat_message_get_file_transfer_information(message); + if (c) { + const char *name = linphone_content_get_name(c); + for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) { + if (linphone_chat_message_get_file_transfer_information(aftd.message) && + strcmp(name, linphone_content_get_name( + linphone_chat_message_get_file_transfer_information(aftd.message))) == 0) { + LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message, aftd); + [self connectToFileDelegate:aftd]; + break; + } + } + } + [self update]; + } +} + ++ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message { + const char *text = linphone_chat_message_get_text(message); + return [NSString stringWithUTF8String:text] ?: [NSString stringWithCString:text encoding:NSASCIIStringEncoding] + ?: NSLocalizedString(@"(invalid string)", nil); +} + +- (NSString *)textMessage { + return [self.class TextMessageForChat:message]; +} + +- (void)update { + if (message == nil) { + LOGW(@"Cannot update message room cell: null message"); + return; + } + const char *url = linphone_chat_message_get_external_body_url(message); + BOOL is_external = + (url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(message); + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:message]; + + // this is an image (either to download or already downloaded) + if (is_external || localImage) { + if (localImage) { + if (_messageImageView.image == nil) { + NSURL *imageUrl = [NSURL URLWithString:localImage]; + _messageText.hidden = YES; + [_messageImageView startLoading]; + __block LinphoneChatMessage *achat = message; + [LinphoneManager.instance.photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + if (achat == message) { // Avoid glitch and scrolling + UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]]; + dispatch_async(dispatch_get_main_queue(), ^{ + [_messageImageView setImage:image]; + [_messageImageView setFullImageUrl:asset]; + [_messageImageView stopLoading]; + _messageImageView.hidden = NO; + }); + } + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } + if (ftd.message != nil) { + _cancelButton.hidden = NO; + _fileTransferProgress.hidden = NO; + _downloadButton.hidden = YES; + } else { + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES; + } + } else { + _messageText.hidden = YES; + _messageImageView.hidden = _cancelButton.hidden = _fileTransferProgress.hidden = (ftd.message == nil); + _downloadButton.hidden = !_cancelButton.hidden; + } + // simple text message + } else { + [_messageText setHidden:FALSE]; + /* We need to use an attributed string here so that data detector don't mess + * with the text style. See http://stackoverflow.com/a/20669356 */ + + NSAttributedString *attr_text = + [[NSAttributedString alloc] initWithString:self.textMessage + attributes:@{ + NSFontAttributeName : [UIFont systemFontOfSize:17.0], + NSForegroundColorAttributeName : [UIColor darkGrayColor] + }]; + _messageText.attributedText = attr_text; + _messageImageView.hidden = YES; + _cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = YES; + } + + // Date + _dateLabel.text = + [LinphoneUtils timeToString:linphone_chat_message_get_time(message) withStyle:NSDateFormatterMediumStyle]; + + LinphoneChatMessageState state = linphone_chat_message_get_state(message); + BOOL outgoing = linphone_chat_message_is_outgoing(message); + + if (!outgoing) { + [_statusImage setAccessibilityValue:@"incoming"]; + _statusImage.hidden = TRUE; // not useful for incoming chats.. + } else if (state == LinphoneChatMessageStateInProgress) { + [_statusImage setImage:[UIImage imageNamed:@"chat_message_inprogress.png"]]; + [_statusImage setAccessibilityValue:@"in progress"]; + _statusImage.hidden = FALSE; + } else if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateFileTransferDone) { + [_statusImage setImage:[UIImage imageNamed:@"chat_message_delivered.png"]]; + [_statusImage setAccessibilityValue:@"delivered"]; + _statusImage.hidden = FALSE; + } else { + [_statusImage setImage:[UIImage imageNamed:@"chat_message_not_delivered.png"]]; + [_statusImage setAccessibilityValue:@"not delivered"]; + _statusImage.hidden = FALSE; + + NSAttributedString *resend_text = + [[NSAttributedString alloc] initWithString:NSLocalizedString(@"Resend", @"Resend") + attributes:@{NSForegroundColorAttributeName : [UIColor redColor]}]; + [_dateLabel setAttributedText:resend_text]; + } + + if (outgoing) { + [_messageText setAccessibilityLabel:@"Outgoing message"]; + } else { + [_messageText setAccessibilityLabel:@"Incoming message"]; + } +} + +- (void)setEditing:(BOOL)editing { + [self setEditing:editing animated:FALSE]; +} + +- (void)setEditing:(BOOL)editing animated:(BOOL)animated { + if (animated) { + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:0.3]; + } + _deleteButton.hidden = !editing; + if (animated) { + [UIView commitAnimations]; + } +} + ++ (CGSize)viewSize:(LinphoneChatMessage *)message width:(int)width { + CGSize messageSize; + const char *url = linphone_chat_message_get_external_body_url(message); + if (url == nil && linphone_chat_message_get_file_transfer_information(message) == NULL) { + NSString *text = [self.class TextMessageForChat:message]; + if (CELL_FONT == nil) { + CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE]; + } +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 + if (UIDevice.currentDevice.systemVersion.doubleValue >= 7) { + messageSize = + [text boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX) + options:(NSStringDrawingUsesLineFragmentOrigin | + NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading) + attributes:@{ + NSFontAttributeName : CELL_FONT + } context:nil] + .size; + } else +#endif + { + messageSize = [text sizeWithFont:CELL_FONT + constrainedToSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f) + lineBreakMode:NSLineBreakByTruncatingTail]; + } + } else { + messageSize = CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT); + } + messageSize.height += CELL_MESSAGE_Y_MARGIN; + if (messageSize.height < CELL_MIN_HEIGHT) + messageSize.height = CELL_MIN_HEIGHT; + messageSize.width += CELL_MESSAGE_X_MARGIN; + if (messageSize.width < CELL_MIN_WIDTH) + messageSize.width = CELL_MIN_WIDTH; + return messageSize; +} + ++ (CGFloat)height:(LinphoneChatMessage *)chatMessage width:(int)width { + return [self.class viewSize:chatMessage width:width].height; +} + +#pragma mark - View Functions + +- (void)layoutSubviews { + [super layoutSubviews]; + if (message != nil) { + BOOL is_outgoing = linphone_chat_message_is_outgoing(message); + CGRect innerFrame; + innerFrame.size = [self.class viewSize:message width:[self frame].size.width]; + innerFrame.origin.y = 0.0f; + innerFrame.origin.x = is_outgoing ? self.frame.size.width - innerFrame.size.width : 0; + _innerView.frame = innerFrame; + + CGRect messageFrame = _bubbleView.frame; + messageFrame.origin.y = (_innerView.frame.size.height - messageFrame.size.height) / 2; + if (!is_outgoing) { + messageFrame.origin.y += 5; + } else { + messageFrame.origin.y -= 5; + } + _backgroundImage.image = + is_outgoing ? [UIImage imageNamed:@"chat_bubble_outgoing"] : [UIImage imageNamed:@"chat_bubble_incoming"]; + _bubbleView.frame = messageFrame; + } +} + +#pragma mark - Action Functions + +- (IBAction)onDeleteClick:(id)event { + if (message != NULL) { + [ftd cancel]; + UITableView *tableView = VIEW(ChatConversationView).tableController.tableView; + NSIndexPath *indexPath = [tableView indexPathForCell:self]; + [tableView.dataSource tableView:tableView + commitEditingStyle:UITableViewCellEditingStyleDelete + forRowAtIndexPath:indexPath]; + } +} + +- (IBAction)onDownloadClick:(id)event { + [ftd cancel]; + ftd = [[FileTransferDelegate alloc] init]; + [self connectToFileDelegate:ftd]; + [ftd download:message]; + _cancelButton.hidden = NO; + _downloadButton.hidden = YES; +} + +- (IBAction)onCancelDownloadClick:(id)sender { + FileTransferDelegate *tmp = ftd; + [self disconnectFromFileDelegate]; + [tmp cancel]; + [self update]; +} + +- (IBAction)onImageClick:(id)event { + LinphoneChatMessageState state = linphone_chat_message_get_state(message); + if (state == LinphoneChatMessageStateNotDelivered) { + [self onResendClick:event]; + } else { + if (![_messageImageView isLoading]) { + ImageView *controller = DYNAMIC_CAST( + [PhoneMainView.instance changeCurrentView:[ImageView compositeViewDescription] push:TRUE], ImageView); + if (controller != nil) { + CGImageRef fullScreenRef = [[_messageImageView.fullImageUrl defaultRepresentation] fullScreenImage]; + UIImage *fullScreen = [UIImage imageWithCGImage:fullScreenRef]; + [controller setImage:fullScreen]; + } + } + } +} + +- (IBAction)onResendClick:(id)event { + if (message == nil) + return; + + LinphoneChatMessageState state = linphone_chat_message_get_state(message); + if (state == LinphoneChatMessageStateNotDelivered) { + if (linphone_chat_message_get_file_transfer_information(message) != NULL) { + NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:message]; + NSURL *imageUrl = [NSURL URLWithString:localImage]; + + [self onDeleteClick:nil]; + + [[LinphoneManager instance] + .photoLibrary assetForURL:imageUrl + resultBlock:^(ALAsset *asset) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), + ^(void) { + UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]]; + [_chatRoomDelegate startImageUpload:image url:imageUrl]; + }); + } + failureBlock:^(NSError *error) { + LOGE(@"Can't read image"); + }]; + } else { + [self onDeleteClick:nil]; + + 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) { + UIChatBubblePhotoCell *thiz = (__bridge UIChatBubblePhotoCell *)linphone_chat_message_get_user_data(msg); + LOGI(@"State for message [%p] changed to %s", msg, linphone_chat_message_state_to_string(state)); + if (linphone_chat_message_get_file_transfer_information(msg) != NULL) { + if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { + // we need to refresh the tableview because the filetransfer delegate unreffed + // the message message before state was LinphoneChatMessageStateFileTransferDone - + // if we are coming back from another view between unreffing and change of state, + // the transient message will not be found and it will not appear in the list of + // message, so we must refresh the table when we change to this state to ensure that + // all transient messages apppear + // ChatRoomViewController *controller = DYNAMIC_CAST( + // [PhoneMainView.instance changeCurrentView:[ChatRoomViewController compositeViewDescription] + // push:TRUE], + // ChatRoomViewController); + // [controller.tableController setChatRoom:linphone_chat_message_get_chat_room(msg)]; + // This is breaking interface too much, it must be fixed in file transfer cb.. meanwhile, disabling it. + + if (thiz->ftd) { + [thiz->ftd stopAndDestroy]; + thiz->ftd = nil; + } + } + } + [thiz update]; +} + +#pragma mark - LinphoneFileTransfer Notifications Handling + +- (void)connectToFileDelegate:(FileTransferDelegate *)aftd { + ftd = aftd; + _fileTransferProgress.progress = 0; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onFileTransferSendUpdate:) + name:kLinphoneFileTransferSendUpdate + object:ftd]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(onFileTransferRecvUpdate:) + name:kLinphoneFileTransferRecvUpdate + object:ftd]; +} + +- (void)disconnectFromFileDelegate { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + ftd = nil; +} + +- (void)onFileTransferSendUpdate:(NSNotification *)notif { + LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue]; + + if (state == LinphoneChatMessageStateInProgress) { + float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue]; + // When uploading a file, the message file is first uploaded to the server, + // so we are in progress state. Then state goes to filetransfertdone. Then, + // the exact same message is sent to the other participant and we come + // back to in progress again. This second time is NOT an upload, so we must + // not update progress! + _fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress); + _fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f); + } else { + [self update]; + } +} +- (void)onFileTransferRecvUpdate:(NSNotification *)notif { + LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue]; + if (state == LinphoneChatMessageStateInProgress) { + float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue]; + _fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress); + _fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f); + } else { + [self update]; + } } -*/ @end diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/UIChatBubblePhotoCell.xib index 29c42af34..c9b012581 100644 --- a/Classes/LinphoneUI/UIChatBubblePhotoCell.xib +++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.xib @@ -45,8 +45,8 @@ - - + + @@ -71,6 +71,10 @@ + + + + + + + @@ -91,6 +98,16 @@ + + + + + + + + + + diff --git a/Classes/LinphoneUI/UIHistoryCell.m b/Classes/LinphoneUI/UIHistoryCell.m index be6fcc2fd..e967d811b 100644 --- a/Classes/LinphoneUI/UIHistoryCell.m +++ b/Classes/LinphoneUI/UIHistoryCell.m @@ -56,7 +56,7 @@ if (callLog != NULL && linphone_call_log_get_call_id(callLog) != NULL) { // Go to History details view HistoryDetailsView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[HistoryDetailsView compositeViewDescription] push:TRUE], + [PhoneMainView.instance changeCurrentView:[HistoryDetailsView compositeViewDescription] push:TRUE], HistoryDetailsView); if (controller != nil) { [controller setCallLogId:[NSString stringWithUTF8String:linphone_call_log_get_call_id(callLog)]]; diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h index dc96ee1ff..42d8a62fb 100644 --- a/Classes/PhoneMainView.h +++ b/Classes/PhoneMainView.h @@ -44,6 +44,9 @@ #import "DTActionSheet.h" #import "Utils.h" +#define VIEW(x) \ + DYNAMIC_CAST([PhoneMainView.instance.mainViewController getCachedController:x.compositeViewDescription.content], x) + @class PhoneMainView; @interface RootViewManager : NSObject @@ -70,9 +73,9 @@ @property (weak, readonly) UICompositeViewDescription *currentView; @property (readonly, strong) MPVolumeView* volumeView; -- (UIViewController*)changeCurrentView:(UICompositeViewDescription *)currentView; -- (UIViewController*)changeCurrentView:(UICompositeViewDescription *)currentView push:(BOOL)push; -- (UIViewController *)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push animated:(BOOL)animated; +- (void)changeCurrentView:(UICompositeViewDescription *)currentView; +- (void)changeCurrentView:(UICompositeViewDescription *)currentView push:(BOOL)push; +- (void)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push animated:(BOOL)animated; - (UIViewController*)popCurrentView; - (void)popToView:(UICompositeViewDescription *)currentView; - (UICompositeViewDescription *)firstView; diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 5c7ddc241..a9ed43985 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -296,7 +296,7 @@ static RootViewManager *rootViewManagerInstance = nil; if ([[LinphoneManager instance] lpConfigBoolForKey:@"show_login_view" forSection:@"app"] && conf == NULL) { already_shown = TRUE; AssistantView *controller = DYNAMIC_CAST( - [[PhoneMainView instance] changeCurrentView:[AssistantView compositeViewDescription]], AssistantView); + [PhoneMainView.instance changeCurrentView:[AssistantView compositeViewDescription]], AssistantView); if (controller != nil) { [controller fillDefaultValues]; } @@ -422,9 +422,8 @@ static RootViewManager *rootViewManagerInstance = nil; if (list != NULL || ([lm lpConfigBoolForKey:@"hide_assistant_preference"] == true) || lm.isTesting) { [self changeCurrentView:[DialerView compositeViewDescription]]; } else { - AssistantView *controller = - DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[AssistantView compositeViewDescription]], - AssistantView); + AssistantView *controller = DYNAMIC_CAST( + [PhoneMainView.instance changeCurrentView:[AssistantView compositeViewDescription]], AssistantView); if (controller != nil) { [controller reset]; } @@ -544,17 +543,17 @@ static RootViewManager *rootViewManagerInstance = nil; [mainViewController setFullScreen:enabled]; } -- (UIViewController *)changeCurrentView:(UICompositeViewDescription *)view { - return [self changeCurrentView:view push:FALSE]; +- (void)changeCurrentView:(UICompositeViewDescription *)view { + [self changeCurrentView:view push:FALSE]; } -- (UIViewController *)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push { - return [self changeCurrentView:view - push:push - animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]]; +- (void)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push { + [self changeCurrentView:view + push:push + animated:[[LinphoneManager instance] lpConfigBoolForKey:@"animations_preference"]]; } -- (UIViewController *)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push animated:(BOOL)animated { +- (void)changeCurrentView:(UICompositeViewDescription *)view push:(BOOL)push animated:(BOOL)animated { BOOL force = push; NSMutableArray *viewStack = [RootViewManager instance].viewDescriptionStack; if (!push) { @@ -562,7 +561,7 @@ static RootViewManager *rootViewManagerInstance = nil; [viewStack removeAllObjects]; } [viewStack addObject:view]; - return [self _changeCurrentView:view transition:nil force:force animated:animated]; + [self _changeCurrentView:view transition:nil force:force animated:animated]; } - (UIViewController *)_changeCurrentView:(UICompositeViewDescription *)view diff --git a/Classes/SettingsView.m b/Classes/SettingsView.m index 0094ac374..532d36bbb 100644 --- a/Classes/SettingsView.m +++ b/Classes/SettingsView.m @@ -266,7 +266,7 @@ } - (IBAction)onAboutClick:(id)sender { - [[PhoneMainView instance] changeCurrentView:[AboutView compositeViewDescription] push:TRUE]; + [PhoneMainView.instance changeCurrentView:[AboutView compositeViewDescription] push:TRUE]; } @end @@ -691,8 +691,8 @@ static UICompositeViewDescription *compositeDescription = nil; [[LinphoneManager instance] destroyLinphoneCore]; [LinphoneManager instanceRelease]; } else if ([key isEqual:@"clear_cache_button"]) { - [[PhoneMainView instance] - .mainViewController clearCache:[NSArray arrayWithObject:[[PhoneMainView instance] currentView]]]; + [PhoneMainView.instance.mainViewController + clearCache:[NSArray arrayWithObject:[PhoneMainView.instance currentView]]]; } else if ([key isEqual:@"battery_alert_button"]) { [[UIDevice currentDevice] _setBatteryState:UIDeviceBatteryStateUnplugged]; [[UIDevice currentDevice] _setBatteryLevel:0.01f]; @@ -723,7 +723,7 @@ static UICompositeViewDescription *compositeDescription = nil; [alert show]; } else if ([key isEqual:@"about_button"]) { - [[PhoneMainView instance] changeCurrentView:[AboutView compositeViewDescription] push:TRUE]; + [PhoneMainView.instance changeCurrentView:[AboutView compositeViewDescription] push:TRUE]; } else if ([key isEqualToString:@"reset_logs_button"]) { linphone_core_reset_log_collection(); } else if ([key isEqual:@"send_logs_button"]) { diff --git a/Classes/SideMenuView.m b/Classes/SideMenuView.m index 4b5c7fbd3..18c2730f9 100644 --- a/Classes/SideMenuView.m +++ b/Classes/SideMenuView.m @@ -55,7 +55,7 @@ } - (IBAction)onLateralSwipe:(id)sender { - [[PhoneMainView instance].mainViewController hideSideMenu:YES]; + [PhoneMainView.instance.mainViewController hideSideMenu:YES]; } - (IBAction)onHeaderClick:(id)sender {