From 4b62c7970c4d680f7ca8d208cc18364e13826dc8 Mon Sep 17 00:00:00 2001 From: Yann Diorcet Date: Thu, 5 Jul 2012 18:06:24 +0200 Subject: [PATCH] Change observers strategy Start chat views --- Classes/ChatRoomTableViewController.h | 29 + Classes/ChatRoomTableViewController.m | 60 ++ Classes/ChatRoomViewController.h | 44 ++ Classes/ChatRoomViewController.m | 160 +++++ Classes/ChatRoomViewController.xib | 580 ++++++++++++++++++ Classes/ChatTableViewController.h | 4 +- Classes/ChatTableViewController.m | 34 +- Classes/ChatViewController.h | 7 +- Classes/ChatViewController.m | 43 +- Classes/ChatViewController.xib | 40 +- Classes/ContactsTableViewController.h | 2 +- Classes/ContactsTableViewController.m | 3 +- Classes/ContactsViewController.h | 4 +- Classes/ContactsViewController.m | 15 + Classes/Data/ChatData.h | 13 + Classes/Data/ChatData.m | 13 + Classes/DialerViewController.h | 4 +- Classes/DialerViewController.m | 59 +- Classes/DialerViewController.xib | 12 +- Classes/FirstLoginViewController.h | 4 +- Classes/FirstLoginViewController.m | 69 ++- Classes/HistoryTableViewController.h | 2 +- Classes/HistoryTableViewController.m | 9 +- Classes/HistoryViewController.h | 3 +- Classes/HistoryViewController.m | 13 + Classes/InCallTableViewController.h | 2 +- Classes/InCallViewController.h | 3 +- Classes/InCallViewController.m | 215 ++++--- Classes/IncomingCallViewController.h | 5 +- Classes/IncomingCallViewController.m | 46 +- Classes/LinphoneAppDelegate.m | 6 +- Classes/LinphoneManager.h | 24 +- Classes/LinphoneManager.m | 76 ++- Classes/LinphoneUI/UICallBar.m | 40 +- Classes/LinphoneUI/UIChatCell.h | 11 +- Classes/LinphoneUI/UIChatCell.m | 23 +- Classes/LinphoneUI/UIChatCell.xib | 89 ++- .../LinphoneUI/UICompositeViewController.h | 6 + .../LinphoneUI/UICompositeViewController.m | 21 +- Classes/LinphoneUI/UIHistoryCell.h | 4 +- Classes/LinphoneUI/UIHistoryCell.m | 13 +- Classes/LinphoneUI/UIMainBar.m | 49 +- Classes/LinphoneUI/UIStateBar.m | 34 +- Classes/LinphoneUI/UIStateBar.xib | 4 +- Classes/Model/ChatModel.h | 47 ++ Classes/Model/ChatModel.m | 229 +++++++ Classes/MoreViewController.h | 2 +- Classes/PhoneMainView.h | 32 +- Classes/PhoneMainView.m | 276 ++++----- Classes/SettingsViewController.h | 3 +- Classes/SettingsViewController.m | 14 + Classes/WizardViewController.h | 4 +- Classes/WizardViewController.m | 18 +- Resources/chat_back_default.png | Bin 0 -> 4647 bytes Resources/chat_back_over.png | Bin 0 -> 4368 bytes Resources/chat_field.png | Bin 0 -> 4375 bytes Resources/chat_ok_default.png | Bin 0 -> 4336 bytes Resources/chat_ok_over.png | Bin 0 -> 4006 bytes Resources/chat_send_default.png | Bin 0 -> 5101 bytes Resources/chat_send_disabled.png | Bin 0 -> 2879 bytes Resources/chat_send_over.png | Bin 0 -> 4533 bytes Resources/database.sqlite | Bin 0 -> 3072 bytes linphone.xcodeproj/project.pbxproj | 96 +++ 63 files changed, 2148 insertions(+), 470 deletions(-) create mode 100644 Classes/ChatRoomTableViewController.h create mode 100644 Classes/ChatRoomTableViewController.m create mode 100644 Classes/ChatRoomViewController.h create mode 100644 Classes/ChatRoomViewController.m create mode 100644 Classes/ChatRoomViewController.xib create mode 100644 Classes/Data/ChatData.h create mode 100644 Classes/Data/ChatData.m create mode 100644 Classes/Model/ChatModel.h create mode 100644 Classes/Model/ChatModel.m create mode 100644 Resources/chat_back_default.png create mode 100644 Resources/chat_back_over.png create mode 100644 Resources/chat_field.png create mode 100644 Resources/chat_ok_default.png create mode 100644 Resources/chat_ok_over.png create mode 100644 Resources/chat_send_default.png create mode 100644 Resources/chat_send_disabled.png create mode 100644 Resources/chat_send_over.png create mode 100644 Resources/database.sqlite diff --git a/Classes/ChatRoomTableViewController.h b/Classes/ChatRoomTableViewController.h new file mode 100644 index 000000000..16aba4943 --- /dev/null +++ b/Classes/ChatRoomTableViewController.h @@ -0,0 +1,29 @@ +/* ChatRoomTableViewController.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 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 + +@interface ChatRoomTableViewController : UITableViewController { + NSArray *data; +} + +@property (nonatomic, retain) NSArray *data; + +@end diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m new file mode 100644 index 000000000..1600d97c5 --- /dev/null +++ b/Classes/ChatRoomTableViewController.m @@ -0,0 +1,60 @@ +/* ChatRoomTableViewController.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 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 "ChatRoomTableViewController.h" +#import "UIChatCell.h" + +@implementation ChatRoomTableViewController + +@synthesize data; + + +#pragma mark - + +- (void)setData:(NSArray *)adata { + if(self->data != nil) + [self->data release]; + self->data = [adata retain]; + [[self tableView] reloadData]; +} + + +#pragma mark - UITableViewDataSource Functions + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return [data count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UIChatCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UIChatCell"]; + if (cell == nil) { + cell = [[UIChatCell alloc] init]; + } + + [cell setChat:[data objectAtIndex:[indexPath row]]]; + [cell update]; + + return cell; +} + +@end diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h new file mode 100644 index 000000000..7890a147c --- /dev/null +++ b/Classes/ChatRoomViewController.h @@ -0,0 +1,44 @@ +/* ChatRoomViewController.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 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 "UICompositeViewController.h" +#import "ChatRoomTableViewController.h" +#import "ChatModel.h" + +@interface ChatRoomViewController : UIViewController { + ChatRoomTableViewController *tableController; + UITextField *messageField; + UIButton *sendButton; +} + +- (void) setRemoteContact:(NSString*)remoteContact; + +@property (nonatomic, retain) IBOutlet ChatRoomTableViewController* tableController; + +@property (nonatomic, retain) IBOutlet UITextField* messageField; +@property (nonatomic, retain) IBOutlet UIButton* sendButton; + +- (IBAction)onBackClick:(id)event; +- (IBAction)onEditClick:(id)event; +- (IBAction)onMessageChange:(id)sender; +- (IBAction)onSendClick:(id)event; + +@end diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m new file mode 100644 index 000000000..5f517b280 --- /dev/null +++ b/Classes/ChatRoomViewController.m @@ -0,0 +1,160 @@ +/* ChatRoomViewController.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 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 "ChatRoomViewController.h" +#import "PhoneMainView.h" + +@implementation ChatRoomViewController + + +@synthesize tableController; +@synthesize sendButton; +@synthesize messageField; + + +#pragma mark - Lifecycle Functions + +- (id)init { + return [super initWithNibName:@"ChatRoomViewController" bundle:[NSBundle mainBundle]]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; +} + +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"ChatRoomViewController"; + description->tabBar = nil; + description->tabBarEnabled = false; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + +#pragma mark - ViewController Functions + +- (void)viewWillAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillShow:) + name:UIKeyboardWillShowNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillHide:) + name:UIKeyboardWillHideNotification + object:nil]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + [[tableController tableView] reloadData]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIKeyboardWillShowNotification + object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIKeyboardWillHideNotification + object:nil]; +} + + +#pragma mark - + +- (void)setRemoteContact:(NSString*)remoteContact { + [tableController setData:[ChatModel listMessages:remoteContact]]; +} + + +#pragma mark - Keyboard Event Functions + +- (void)keyboardWillHide:(NSNotification *)notif { + //CGRect beginFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; + UIViewAnimationCurve curve = [[[notif userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]; + NSTimeInterval duration = [[[notif userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + [UIView beginAnimations:@"resize" context:nil]; + [UIView setAnimationDuration:duration]; + [UIView setAnimationCurve:curve]; + [UIView setAnimationBeginsFromCurrentState:TRUE]; + CGRect endFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; + CGRect frame = [[self view] frame]; + CGPoint pos = {0, 0}; + CGPoint gPos = [[self view] convertPoint:pos toView:nil]; + frame.size.height = endFrame.origin.y - gPos.y; + [[self view] setFrame:frame]; + [UIView commitAnimations]; +} + +- (void)keyboardWillShow:(NSNotification *)notif { + //CGRect beginFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; + UIViewAnimationCurve curve = [[[notif userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]; + NSTimeInterval duration = [[[notif userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + [UIView beginAnimations:@"resize" context:nil]; + [UIView setAnimationDuration:duration]; + [UIView setAnimationCurve:curve]; + [UIView setAnimationBeginsFromCurrentState:TRUE]; + CGRect endFrame = [[[notif userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; + CGRect frame = [[self view] frame]; + CGPoint pos = {0, 0}; + CGPoint gPos = [[self view] convertPoint:pos toView:nil]; + frame.size.height = endFrame.origin.y - gPos.y; + [[self view] setFrame:frame]; + [UIView commitAnimations]; +} + +#pragma mark - UITextFieldDelegate Functions + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + + +#pragma mark - Action Functions + +- (IBAction)onBackClick:(id)event { + [[PhoneMainView instance] popView]; +} + +- (IBAction)onEditClick:(id)event { + +} + +- (IBAction)onSendClick:(id)event { + [messageField endEditing:TRUE]; +} + +- (IBAction)onMessageChange:(id)sender { + if([[messageField text] length] > 0) { + [sendButton setEnabled:TRUE]; + } else { + [sendButton setEnabled:FALSE]; + } +} + +@end diff --git a/Classes/ChatRoomViewController.xib b/Classes/ChatRoomViewController.xib new file mode 100644 index 000000000..a363aec5e --- /dev/null +++ b/Classes/ChatRoomViewController.xib @@ -0,0 +1,580 @@ + + + + 1296 + 11E53 + 2182 + 1138.47 + 569.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1181 + + + IBUIView + IBUIImageView + IBProxyObject + IBUITextField + IBUITableViewController + IBUITableView + IBUIButton + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 292 + + + + 290 + + + + 292 + {160, 58} + + + + _NS:9 + NO + + All + + IBCocoaTouchFramework + 0 + 0 + NO + + 3 + MC41AA + + + NSImage + chat_back_over.png + + + NSImage + chat_back_default.png + + + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + + + + 292 + {{160, 0}, {160, 58}} + + + + _NS:9 + NO + + Missed + + IBCocoaTouchFramework + 0 + 0 + NO + + + NSImage + chat_edit_over.png + + + NSImage + chat_edit_default.png + + + + + + {320, 58} + + + + _NS:9 + + 3 + MQA + + 2 + + + IBCocoaTouchFramework + + + + 274 + {{0, 58}, {320, 344}} + + + + _NS:9 + + 1 + MC45NDExNzY0NzA2IDAuOTY0NzA1ODgyNCAwLjk2NDcwNTg4MjQAA + + YES + IBCocoaTouchFramework + YES + 1 + 0 + YES + 44 + 22 + 22 + + + + 266 + + + + 292 + {{250, 0}, {70, 59}} + + + + _NS:9 + NO + + Missed + + IBCocoaTouchFramework + NO + 0 + 0 + NO + NO + + + NSImage + chat_send_over.png + + + NSImage + chat_send_disabled.png + + + NSImage + chat_send_default.png + + + + + + + 292 + {250, 59} + + + + _NS:9 + NO + IBCocoaTouchFramework + + NSImage + chat_field.png + + + + + 292 + {{10, 10}, {230, 39}} + + + + _NS:9 + NO + YES + IBCocoaTouchFramework + 0 + + Type your message here + + 3 + MAA + + + YES + 17 + + IBCocoaTouchFramework + + + 1 + 18 + + + Helvetica + 18 + 16 + + + + {{0, 401}, {320, 59}} + + + + _NS:9 + + 3 + MQA + + + IBCocoaTouchFramework + + + {320, 460} + + + + _NS:9 + + 3 + MQA + + + IBCocoaTouchFramework + + + NO + + + 1 + 1 + + IBCocoaTouchFramework + NO + + + + + + + view + + + + 11 + + + + messageField + + + + 26 + + + + sendButton + + + + 27 + + + + tableController + + + + 32 + + + + dataSource + + + + 30 + + + + delegate + + + + 31 + + + + onBackClick: + + + 7 + + 12 + + + + onEditClick: + + + 7 + + 13 + + + + onSendClick: + + + 7 + + 25 + + + + delegate + + + + 20 + + + + onMessageChange: + + + 18 + + 28 + + + + view + + + + 33 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 6 + + + + + + + + + + 7 + + + + + + + header + + + 8 + + + + tableView + + + 9 + + + backButton + + + 10 + + + editButton + + + 14 + + + + + + + + footer + + + 15 + + + sendButton + + + 19 + + + messageField + + + 21 + + + fieldBackground + + + 29 + + + tableController + + + + + ChatRoomViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + ChatRoomTableViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + 33 + + + + + ChatRoomTableViewController + UITableViewController + + IBProjectSource + ./Classes/ChatRoomTableViewController.h + + + + ChatRoomViewController + UIViewController + + id + id + id + id + + + + onBackClick: + id + + + onEditClick: + id + + + onMessageChange: + id + + + onSendClick: + id + + + + UITextField + UIButton + ChatRoomTableViewController + + + + messageField + UITextField + + + sendButton + UIButton + + + tableController + ChatRoomTableViewController + + + + IBProjectSource + ./Classes/ChatRoomViewController.h + + + + + 0 + IBCocoaTouchFramework + + com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS + + + YES + 3 + + {320, 117} + {320, 117} + {320, 117} + {320, 117} + {500, 117} + {140, 117} + {140, 117} + {140, 117} + + 1181 + + diff --git a/Classes/ChatTableViewController.h b/Classes/ChatTableViewController.h index 2b9367245..32cd1f67e 100644 --- a/Classes/ChatTableViewController.h +++ b/Classes/ChatTableViewController.h @@ -20,7 +20,9 @@ #import @interface ChatTableViewController : UITableViewController { - + NSArray *data; } +@property (nonatomic, retain) NSArray *data; + @end diff --git a/Classes/ChatTableViewController.m b/Classes/ChatTableViewController.m index 969125b08..b72bd9a6f 100644 --- a/Classes/ChatTableViewController.m +++ b/Classes/ChatTableViewController.m @@ -20,8 +20,24 @@ #import "ChatTableViewController.h" #import "UIChatCell.h" +#import "linphonecore.h" +#import "PhoneMainView.h" + @implementation ChatTableViewController +@synthesize data; + + +#pragma mark - + +- (void)setData:(NSArray *)adata { + if(self->data != nil) + [self->data release]; + self->data = [adata retain]; + [[self tableView] reloadData]; +} + +#pragma mark - UITableViewDataSource Functions - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -30,7 +46,7 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return 1; + return [data count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath @@ -40,9 +56,25 @@ cell = [[UIChatCell alloc] init]; } + [cell setChat:[data objectAtIndex:[indexPath row]]]; [cell update]; return cell; } + +#pragma mark - UITableViewDelegate Functions + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + [tableView deselectRowAtIndexPath:indexPath animated:NO]; + ChatModel *chat = [data objectAtIndex:[indexPath row]]; + + // Go to dialer view + NSDictionary *dict = [[[NSDictionary alloc] initWithObjectsAndKeys: + [[[NSArray alloc] initWithObjects: [chat remoteContact], nil] autorelease] + , @"setRemoteContact:", + nil] autorelease]; + [[PhoneMainView instance] changeView:PhoneView_ChatRoom dict:dict push:TRUE]; +} + @end diff --git a/Classes/ChatViewController.h b/Classes/ChatViewController.h index a6df7bda6..ac61c32c0 100644 --- a/Classes/ChatViewController.h +++ b/Classes/ChatViewController.h @@ -20,14 +20,15 @@ #import #import "ChatTableViewController.h" +#import "UICompositeViewController.h" -@interface ChatViewController : UIViewController { +@interface ChatViewController : UIViewController { ChatTableViewController *tableController; } @property (nonatomic, retain) IBOutlet ChatTableViewController* tableController; -- (IBAction)onAdd:(id) event; -- (IBAction)onEdit:(id) event; +- (IBAction)onAddClick:(id) event; +- (IBAction)onEditClick:(id) event; @end diff --git a/Classes/ChatViewController.m b/Classes/ChatViewController.m index 5f52c3bd7..2e769e36c 100644 --- a/Classes/ChatViewController.m +++ b/Classes/ChatViewController.m @@ -18,21 +18,58 @@ */ #import "ChatViewController.h" +#import "PhoneMainView.h" +#import "ChatModel.h" @implementation ChatViewController @synthesize tableController; + +#pragma mark - Lifecycle Functions + - (id)init { return [super initWithNibName:@"ChatViewController" bundle:[NSBundle mainBundle]]; } -- (IBAction)onAdd: (id) event { - + +#pragma mark - ViewController Functions + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [tableController setData:[ChatModel listConversations]]; } -- (IBAction)onEdit: (id) event { +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"ChatViewController"; + description->tabBar = @"UIMainBar"; + description->tabBarEnabled = true; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + +#pragma mark - Action Functions + +- (IBAction)onAddClick:(id)event { + [[PhoneMainView instance] changeView:PhoneView_ChatRoom push:TRUE]; +} + +- (IBAction)onEditClick:(id)event { + ChatModel* line= [[ChatModel alloc] init]; + line.localContact = @""; + line.remoteContact = @"truc"; + line.message = @"blabla"; + line.direction = [NSNumber numberWithInt:1]; + line.time = [NSDate date]; + [line create]; + [tableController setData:[ChatModel listConversations]]; } @end diff --git a/Classes/ChatViewController.xib b/Classes/ChatViewController.xib index 3145cd267..bd88f20eb 100644 --- a/Classes/ChatViewController.xib +++ b/Classes/ChatViewController.xib @@ -69,10 +69,6 @@ NSImage chat_add_default.png - - NSImage - all-call-selectionne.png - 2 15 @@ -108,10 +104,6 @@ NSImage chat_edit_default.png - - NSImage - missed-selectionne.png - @@ -139,8 +131,8 @@ _NS:9 - 3 - MQA + 1 + MC45NDExNzY0NzA2IDAuOTY0NzA1ODgyNCAwLjk2NDcwNTg4MjQAA YES IBCocoaTouchFramework @@ -224,21 +216,21 @@ - onEdit: + onEditClick: 7 - 17 + 21 - onAdd: + onAddClick: 7 - 19 + 20 @@ -311,20 +303,20 @@ UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + ChatTableViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + - 19 + 21 @@ -340,16 +332,16 @@ ChatViewController UIViewController - id - id + id + id - - onAdd: + + onAddClick: id - - onEdit: + + onEditClick: id @@ -380,12 +372,10 @@ YES 3 - {213, 117} {320, 117} {320, 117} {320, 117} {320, 117} - {213, 117} 1181 diff --git a/Classes/ContactsTableViewController.h b/Classes/ContactsTableViewController.h index 5ef07e6ea..696b0ef7e 100644 --- a/Classes/ContactsTableViewController.h +++ b/Classes/ContactsTableViewController.h @@ -22,7 +22,7 @@ #import "OrderedDictionary.h" -@interface ContactsTableViewController : UITableViewController { +@interface ContactsTableViewController : UITableViewController { OrderedDictionary* addressBookMap; ABAddressBookRef addressBook; diff --git a/Classes/ContactsTableViewController.m b/Classes/ContactsTableViewController.m index 55c1b33d2..f67ce8f71 100644 --- a/Classes/ContactsTableViewController.m +++ b/Classes/ContactsTableViewController.m @@ -20,6 +20,7 @@ #import "ContactsTableViewController.h" #import "UIContactCell.h" #import "LinphoneManager.h" +#import "PhoneMainView.h" @implementation ContactsTableViewController @@ -127,7 +128,7 @@ void sync_toc_address_book (ABAddressBookRef addressBook, CFDictionaryRef info, [[[NSArray alloc] initWithObjects: number, nil] autorelease] , @"setAddress:", nil] autorelease]; - [[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict]; + [[PhoneMainView instance] changeView:PhoneView_Dialer dict:dict]; CFRelease(lNumber); break; diff --git a/Classes/ContactsViewController.h b/Classes/ContactsViewController.h index 50326d42f..f713dd8b7 100644 --- a/Classes/ContactsViewController.h +++ b/Classes/ContactsViewController.h @@ -19,9 +19,11 @@ #import +#import "UICompositeViewController.h" + #import "ContactsTableViewController.h" -@interface ContactsViewController : UIViewController { +@interface ContactsViewController : UIViewController { ContactsTableViewController *tableController; UITableView *tableView; diff --git a/Classes/ContactsViewController.m b/Classes/ContactsViewController.m index c5fa9e9b7..436f5739b 100644 --- a/Classes/ContactsViewController.m +++ b/Classes/ContactsViewController.m @@ -51,6 +51,21 @@ typedef enum _HistoryView { [super dealloc]; } + +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"ContactsViewController"; + description->tabBar = @"UIMainBar"; + description->tabBarEnabled = true; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions - (void)viewDidAppear:(BOOL)animated { diff --git a/Classes/Data/ChatData.h b/Classes/Data/ChatData.h new file mode 100644 index 000000000..dddef8c50 --- /dev/null +++ b/Classes/Data/ChatData.h @@ -0,0 +1,13 @@ +// +// ChatData.h +// linphone +// +// Created by Diorcet Yann on 05/07/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +@interface ChatData : NSObject + +@end diff --git a/Classes/Data/ChatData.m b/Classes/Data/ChatData.m new file mode 100644 index 000000000..f8aa72dc1 --- /dev/null +++ b/Classes/Data/ChatData.m @@ -0,0 +1,13 @@ +// +// ChatData.m +// linphone +// +// Created by Diorcet Yann on 05/07/12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "ChatData.h" + +@implementation ChatData + +@end diff --git a/Classes/DialerViewController.h b/Classes/DialerViewController.h index f08360063..8a90e2b63 100644 --- a/Classes/DialerViewController.h +++ b/Classes/DialerViewController.h @@ -19,12 +19,14 @@ #import +#import "UICompositeViewController.h" + #import "UIEraseButton.h" #import "UICallButton.h" #import "UITransferButton.h" #import "UIDigitButton.h" -@interface DialerViewController : UIViewController { +@interface DialerViewController : UIViewController { @private //Buttons UITextField* addressField; diff --git a/Classes/DialerViewController.m b/Classes/DialerViewController.m index a8774c35f..90bc9123c 100644 --- a/Classes/DialerViewController.m +++ b/Classes/DialerViewController.m @@ -83,17 +83,52 @@ [zeroButton release]; [sharpButton release]; + + // Remove all observers [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription *)compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"DialerViewController"; + description->tabBar = @"UIMainBar"; + description->tabBarEnabled = true; + description->stateBar = @"UIStateBar"; + description->stateBarEnabled = true; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - [self update]; + + // Set observer + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(callUpdateEvent:) + name:@"LinphoneCallUpdate" + object:nil]; + + // Update on show + LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]); + LinphoneCallState state = (call != NULL)?linphone_call_get_state(call): 0; + [self callUpdate:call state:state]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // Remove observer + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneCallUpdate" + object:nil]; } - (void)viewDidLoad { @@ -111,26 +146,20 @@ [nineButton setDigit:'9']; [starButton setDigit:'*']; [sharpButton setDigit:'#']; - - // Set observer - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callUpdate:) name:@"LinphoneCallUpdate" object:nil]; } -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - #pragma mark - Event Functions -- (void)callUpdate:(NSNotification*)notif { - [self update]; +- (void)callUpdateEvent:(NSNotification*)notif { + LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue]; + LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue]; + [self callUpdate:call state:state]; } #pragma mark - -- (void)update { +- (void)callUpdate:(LinphoneCall*)call state:(LinphoneCallState)state { if([LinphoneManager isLcReady]) { LinphoneCore *lc = [LinphoneManager getLc]; if(linphone_core_get_calls_nb(lc) > 0) { @@ -160,7 +189,9 @@ - (void)setTransferMode:(NSNumber*) n { transferMode = [n boolValue]; - [self update]; + LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]); + LinphoneCallState state = (call != NULL)?linphone_call_get_state(call): 0; + [self callUpdate:call state:state]; } @@ -181,7 +212,7 @@ } - (IBAction)onBackClick: (id) event { - [[LinphoneManager instance] changeView:PhoneView_InCall]; + [[PhoneMainView instance] changeView:PhoneView_InCall]; } - (IBAction)onAddressChange: (id)sender { diff --git a/Classes/DialerViewController.xib b/Classes/DialerViewController.xib index dfe28c0d4..952fbc8bd 100644 --- a/Classes/DialerViewController.xib +++ b/Classes/DialerViewController.xib @@ -521,7 +521,7 @@ NSImage - cancel_white_bg_disabled.png + back_disabled.png @@ -1286,7 +1286,7 @@ com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + UICallButton com.apple.InterfaceBuilder.IBCocoaTouchPlugin @@ -1677,6 +1677,7 @@ add_contact_disabled.png add_contact_over.png back_default.png + back_disabled.png back_over.png backspace_default.png backspace_disabled.png @@ -1684,7 +1685,6 @@ call_default.png call_disabled.png call_over.png - cancel_white_bg_disabled.png dialer_address_background.png numpad_background.png numpad_eight_default.png @@ -1725,10 +1725,10 @@ {213, 138} {213, 138} {213, 138} - {214, 138} - {214, 138} - {214, 138} {213, 138} + {214, 138} + {214, 138} + {214, 138} {640, 135} {640, 523} {220, 113} diff --git a/Classes/FirstLoginViewController.h b/Classes/FirstLoginViewController.h index 12e3f0ace..5f9961cbf 100644 --- a/Classes/FirstLoginViewController.h +++ b/Classes/FirstLoginViewController.h @@ -19,7 +19,9 @@ #import -@interface FirstLoginViewController : UIViewController{ +#import "UICompositeViewController.h" + +@interface FirstLoginViewController : UIViewController { UIButton* loginButton; UIButton* siteButton; UITextField* usernameField; diff --git a/Classes/FirstLoginViewController.m b/Classes/FirstLoginViewController.m index d3f202da5..cf47635c9 100644 --- a/Classes/FirstLoginViewController.m +++ b/Classes/FirstLoginViewController.m @@ -20,6 +20,7 @@ #import "FirstLoginViewController.h" #import "LinphoneManager.h" +#import "PhoneMainView.h" @implementation FirstLoginViewController @@ -36,21 +37,63 @@ } - (void)dealloc { - [super dealloc]; [loginButton dealloc]; [siteButton dealloc]; [usernameField dealloc]; [passwordField dealloc]; [waitView dealloc]; + + // Remove all observer [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [super dealloc]; } + +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription *)compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"FirstLoginViewController"; + description->tabBar = nil; + description->tabBarEnabled = false; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; [usernameField setText:[[LinphoneManager instance].settingsStore objectForKey:@"username_preference"]]; [passwordField setText:[[LinphoneManager instance].settingsStore objectForKey:@"password_preference"]]; + + // Set observer + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(registrationUpdateEvent:) + name:@"LinphoneRegistrationUpdate" + object:nil]; + + // Update on show + const MSList* list = linphone_core_get_proxy_config_list([LinphoneManager getLc]); + if(list != NULL) { + LinphoneProxyConfig *config = (LinphoneProxyConfig*) list->data; + if(config) { + [self registrationUpdate:linphone_proxy_config_get_state(config)]; + } + } +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // Remove observer + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneRegistrationUpdate" + object:nil]; } - (void)viewDidLoad { @@ -59,26 +102,24 @@ siteUrl=@"http://www.linphone.org"; } [siteButton setTitle:siteUrl forState:UIControlStateNormal]; - - // Set observer - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registrationUpdate:) name:@"LinphoneRegistrationUpdate" object:nil]; } -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - #pragma mark - Event Functions -- (void)registrationUpdate: (NSNotification*) notif { - LinphoneRegistrationState state = [[notif.userInfo objectForKey: @"state"] intValue]; +- (void)registrationUpdateEvent:(NSNotification*)notif { + [self registrationUpdate:[[notif.userInfo objectForKey: @"state"] intValue]]; +} + + +#pragma mark - + +- (void)registrationUpdate:(LinphoneRegistrationState)state { switch (state) { case LinphoneRegistrationOk: { [[LinphoneManager instance].settingsStore setBool:false forKey:@"enable_first_login_view_preference"]; [self.waitView setHidden:true]; - [[LinphoneManager instance] changeView:PhoneView_Dialer]; + [[PhoneMainView instance] changeView:PhoneView_Dialer]; break; } case LinphoneRegistrationNone: diff --git a/Classes/HistoryTableViewController.h b/Classes/HistoryTableViewController.h index b668e5fc4..09f55b9e7 100644 --- a/Classes/HistoryTableViewController.h +++ b/Classes/HistoryTableViewController.h @@ -19,7 +19,7 @@ #import -@interface HistoryTableViewController : UITableViewController { +@interface HistoryTableViewController : UITableViewController { @private BOOL editMode; } diff --git a/Classes/HistoryTableViewController.m b/Classes/HistoryTableViewController.m index 83635f53a..33747e013 100644 --- a/Classes/HistoryTableViewController.m +++ b/Classes/HistoryTableViewController.m @@ -20,6 +20,7 @@ #import "HistoryTableViewController.h" #import "UIHistoryCell.h" #import "LinphoneManager.h" +#import "PhoneMainView.h" @implementation HistoryTableViewController @@ -58,11 +59,15 @@ else [cell exitEditMode]; - [cell update:callLogs]; + [cell setCallLog:callLogs]; + [cell update]; return cell; } + +#pragma mark - UITableViewDelegate Functions + - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; @@ -96,7 +101,7 @@ [[[NSArray alloc] initWithObjects: phoneNumber, nil] autorelease] , @"setAddress:", nil] autorelease]; - [[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict]; + [[PhoneMainView instance] changeView:PhoneView_Dialer dict:dict]; [phoneNumber release]; [dispName release]; diff --git a/Classes/HistoryViewController.h b/Classes/HistoryViewController.h index 10b329ab0..93025f1b7 100644 --- a/Classes/HistoryViewController.h +++ b/Classes/HistoryViewController.h @@ -19,10 +19,11 @@ #import +#import "UICompositeViewController.h" #import "HistoryTableViewController.h" #import "UIToggleButton.h" -@interface HistoryViewController : UIViewController { +@interface HistoryViewController : UIViewController { @private HistoryTableViewController *tableController; UITableView *tableView; diff --git a/Classes/HistoryViewController.m b/Classes/HistoryViewController.m index 766282145..8b2aa9e46 100644 --- a/Classes/HistoryViewController.m +++ b/Classes/HistoryViewController.m @@ -53,6 +53,19 @@ typedef enum _HistoryView { } +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"HistoryViewController"; + description->tabBar = @"UIMainBar"; + description->tabBarEnabled = true; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + #pragma mark - ViewController Functions - (void)viewDidAppear:(BOOL)animated { diff --git a/Classes/InCallTableViewController.h b/Classes/InCallTableViewController.h index 1ccd38a08..99abc4d60 100644 --- a/Classes/InCallTableViewController.h +++ b/Classes/InCallTableViewController.h @@ -23,7 +23,7 @@ #include "linphonecore.h" -@interface InCallTableViewController : UITableViewController { +@interface InCallTableViewController : UITableViewController { @private NSMutableDictionary* callCellData; NSTimer *updateTime; diff --git a/Classes/InCallViewController.h b/Classes/InCallViewController.h index 651baac8e..b11f30ae3 100644 --- a/Classes/InCallViewController.h +++ b/Classes/InCallViewController.h @@ -23,11 +23,12 @@ #import "UICamSwitch.h" #import "CallDelegate.h" +#import "UICompositeViewController.h" #import "InCallTableViewController.h" @class VideoViewController; -@interface InCallViewController : UIViewController { +@interface InCallViewController : UIViewController { InCallTableViewController* callTableController; UITableView* callTableView; diff --git a/Classes/InCallViewController.m b/Classes/InCallViewController.m index 01b0699fc..e3690a931 100644 --- a/Classes/InCallViewController.m +++ b/Classes/InCallViewController.m @@ -27,6 +27,7 @@ #import "IncallViewController.h" #import "UICallCell.h" #import "LinphoneManager.h" +#import "PhoneMainView.h" #include "linphonecore.h" #include "private.h" @@ -71,10 +72,27 @@ const NSInteger SECURE_BUTTON_TAG=5; [videoZoomHandler release]; + // Remove all observer + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; } +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"InCallViewController"; + description->tabBar = @"UICallBar"; + description->tabBarEnabled = true; + description->stateBar = @"UIStateBar"; + description->stateBarEnabled = true; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions - (void)viewDidAppear:(BOOL)animated { @@ -101,6 +119,12 @@ const NSInteger SECURE_BUTTON_TAG=5; if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) { [callTableController viewWillDisappear:NO]; } + + + // Remove observer + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneCallUpdate" + object:nil]; } - (void)viewWillAppear:(BOOL)animated { @@ -108,6 +132,17 @@ const NSInteger SECURE_BUTTON_TAG=5; if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) { [callTableController viewWillAppear:NO]; } + + // Set observer + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(callUpdateEvent:) + name:@"LinphoneCallUpdate" + object:nil]; + + // Update on show + LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]); + LinphoneCallState state = (call != NULL)?linphone_call_get_state(call): 0; + [self callUpdate:call state:state]; } - (void)viewDidDisappear:(BOOL)animated { @@ -122,10 +157,6 @@ const NSInteger SECURE_BUTTON_TAG=5; } } -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (void)viewDidLoad { [super viewDidLoad]; @@ -133,10 +164,6 @@ const NSInteger SECURE_BUTTON_TAG=5; linphone_core_set_native_video_window_id([LinphoneManager getLc],(unsigned long)videoView); linphone_core_set_native_preview_window_id([LinphoneManager getLc],(unsigned long)videoPreview); - // Set observer - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callUpdate:) name:@"LinphoneCallUpdate" object:nil]; - - UITapGestureRecognizer* singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showControls:)]; [singleFingerTap setNumberOfTapsRequired:1]; [singleFingerTap setCancelsTouchesInView: FALSE]; @@ -153,6 +180,80 @@ const NSInteger SECURE_BUTTON_TAG=5; #pragma mark - + +- (void)callUpdate:(LinphoneCall *)call state:(LinphoneCallState) state { + // Update table + [callTableView reloadData]; + + // Fake call update + if(call == NULL) { + return; + } + + // Handle data associated with the call + if(state == LinphoneCallReleased) { + [callTableController removeCallData: call]; + } else { + [callTableController addCallData: call]; + } + + switch (state) { + case LinphoneCallIncomingReceived: + case LinphoneCallOutgoingInit: + { + if(linphone_core_get_calls_nb([LinphoneManager getLc]) > 1) { + [callTableController minimizeAll]; + } + } + case LinphoneCallConnected: + case LinphoneCallStreamsRunning: + case LinphoneCallUpdated: + { + //check video + if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { + [self displayVideoCall]; + } else { + [self displayTableCall]; + } + break; + } + case LinphoneCallUpdatedByRemote: + { + const LinphoneCallParams* current = linphone_call_get_current_params(call); + const LinphoneCallParams* remote = linphone_call_get_remote_params(call); + + /* remote wants to add video */ + if (!linphone_call_params_video_enabled(current) && + linphone_call_params_video_enabled(remote) && + !linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept) { + linphone_core_defer_call_update([LinphoneManager getLc], call); + [self displayAskToEnableVideoCall:call]; + } else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) { + [self displayTableCall]; + } + break; + } + case LinphoneCallPausing: + case LinphoneCallPaused: + case LinphoneCallPausedByRemote: + { + [self displayTableCall]; + break; + } + case LinphoneCallEnd: + case LinphoneCallError: + { + if(linphone_core_get_calls_nb([LinphoneManager getLc]) <= 1) { + [callTableController maximizeAll]; + } + break; + } + default: + break; + } + +} + - (void)showControls:(id)sender { if (hideControlsTimer) { [hideControlsTimer invalidate]; @@ -162,7 +263,7 @@ const NSInteger SECURE_BUTTON_TAG=5; // show controls [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:0.3]; - [[LinphoneManager instance] showTabBar: true]; + [[PhoneMainView instance] showTabBar: true]; if ([LinphoneManager instance].frontCamId !=nil ) { // only show camera switch button if we have more than 1 camera [videoCameraSwitch setAlpha:1.0]; @@ -183,8 +284,8 @@ const NSInteger SECURE_BUTTON_TAG=5; [videoCameraSwitch setAlpha:0.0]; [UIView commitAnimations]; - if([[LinphoneManager instance] currentView] == PhoneView_InCall && videoShown) - [[LinphoneManager instance] showTabBar: false]; + if([[PhoneMainView instance] currentView] == PhoneView_InCall && videoShown) + [[PhoneMainView instance] showTabBar: false]; if (hideControlsTimer) { [hideControlsTimer invalidate]; @@ -228,8 +329,8 @@ const NSInteger SECURE_BUTTON_TAG=5; videoView.alpha = 1.0; videoView.hidden = FALSE; - [[LinphoneManager instance] fullScreen: true]; - [[LinphoneManager instance] showTabBar: false]; + [[PhoneMainView instance] fullScreen: true]; + [[PhoneMainView instance] showTabBar: false]; #ifdef TEST_VIDEO_VIEW_CHANGE [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(_debugChangeVideoView) userInfo:nil repeats:YES]; @@ -256,7 +357,7 @@ const NSInteger SECURE_BUTTON_TAG=5; } [videoGroup setAlpha:0.0]; - [[LinphoneManager instance] showTabBar: true]; + [[PhoneMainView instance] showTabBar: true]; [callTableView setAlpha:1.0]; [videoCameraSwitch setAlpha:0.0]; @@ -269,7 +370,7 @@ const NSInteger SECURE_BUTTON_TAG=5; hideControlsTimer = nil; } - [[LinphoneManager instance] fullScreen:false]; + [[PhoneMainView instance] fullScreen:false]; } - (void)transferPressed { @@ -314,7 +415,7 @@ const NSInteger SECURE_BUTTON_TAG=5; //TODO /*[UICallButton enableTransforMode:YES];*/ - [[LinphoneManager instance] changeView:PhoneView_Dialer]; + [[PhoneMainView instance] changeView:PhoneView_Dialer]; } else { // add 'Other' option [visibleActionSheet addButtonWithTitle:NSLocalizedString(@"Other...",nil)]; @@ -332,11 +433,11 @@ const NSInteger SECURE_BUTTON_TAG=5; } } -- (void)displayVideoCall:(LinphoneCall*) call { +- (void)displayVideoCall { [self enableVideoDisplay: TRUE]; } -- (void)displayTableCall:(LinphoneCall*) call { +- (void)displayTableCall { [self disableVideoDisplay: TRUE]; } @@ -352,84 +453,16 @@ static void hideSpinner(LinphoneCall* call, void* user_data) { [thiz hideSpinnerIndicator:call]; } + #pragma mark - Event Functions -- (void)callUpdate: (NSNotification*) notif { +- (void)callUpdateEvent: (NSNotification*) notif { LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue]; LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue]; - - // Update table - [callTableView reloadData]; - - // Fake call update - if(call == NULL) { - return; - } - - // Handle data associated with the call - if(state == LinphoneCallReleased) { - [callTableController removeCallData: call]; - } else { - [callTableController addCallData: call]; - } - - switch (state) { - case LinphoneCallIncomingReceived: - case LinphoneCallOutgoingInit: - { - if(linphone_core_get_calls_nb([LinphoneManager getLc]) > 1) { - [callTableController minimizeAll]; - } - } - case LinphoneCallConnected: - case LinphoneCallStreamsRunning: - case LinphoneCallUpdated: - { - //check video - if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) { - [self displayVideoCall:call]; - } else { - [self displayTableCall:call]; - } - break; - } - case LinphoneCallUpdatedByRemote: - { - const LinphoneCallParams* current = linphone_call_get_current_params(call); - const LinphoneCallParams* remote = linphone_call_get_remote_params(call); - - /* remote wants to add video */ - if (!linphone_call_params_video_enabled(current) && - linphone_call_params_video_enabled(remote) && - !linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept) { - linphone_core_defer_call_update([LinphoneManager getLc], call); - [self displayAskToEnableVideoCall:call]; - } else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) { - [self displayTableCall:call]; - } - break; - } - case LinphoneCallPausing: - case LinphoneCallPaused: - case LinphoneCallPausedByRemote: - { - [self displayTableCall: call]; - break; - } - case LinphoneCallEnd: - case LinphoneCallError: - { - if(linphone_core_get_calls_nb([LinphoneManager getLc]) <= 1) { - [callTableController maximizeAll]; - } - break; - } - default: - break; - } - + [self callUpdate:call state:state]; } + #pragma mark - ActionSheet Functions - (void)dismissActionSheet: (id)o { @@ -523,7 +556,7 @@ static void hideSpinner(LinphoneCall* call, void* user_data) { // with the correct indice //TODO //[UICallButton enableTransforMode:YES]; - [[LinphoneManager instance] changeView:PhoneView_Dialer]; + [[PhoneMainView instance] changeView:PhoneView_Dialer]; break; } default: diff --git a/Classes/IncomingCallViewController.h b/Classes/IncomingCallViewController.h index ba2a9563a..dbdbc41e0 100644 --- a/Classes/IncomingCallViewController.h +++ b/Classes/IncomingCallViewController.h @@ -38,12 +38,9 @@ typedef enum _IncomingCallStates { @property (nonatomic, retain) IBOutlet UILabel* addressLabel; @property (nonatomic, retain) IBOutlet UIImageView* avatarImage; +@property (nonatomic, assign) LinphoneCall* call; - (IBAction)onAcceptClick:(id) event; - (IBAction)onDeclineClick:(id) event; -- (void)update:(LinphoneCall*)call; - -- (LinphoneCall*) getCall; - @end diff --git a/Classes/IncomingCallViewController.m b/Classes/IncomingCallViewController.m index 47965e2c3..744422fea 100644 --- a/Classes/IncomingCallViewController.m +++ b/Classes/IncomingCallViewController.m @@ -24,19 +24,13 @@ @synthesize addressLabel; @synthesize avatarImage; +@synthesize call; #pragma mark - Lifecycle Functions - (id)init { - self = [super initWithNibName:@"IncomingCallViewController" bundle:[NSBundle mainBundle]]; - if(self) { - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(callUpdate:) - name:@"LinphoneCallUpdate" - object:nil]; - } - return self; + return [super initWithNibName:@"IncomingCallViewController" bundle:[NSBundle mainBundle]]; } - (void)dealloc { @@ -46,20 +40,50 @@ } +#pragma mark - ViewController Functions + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(callUpdateEvent:) + name:@"LinphoneCallUpdate" + object:nil]; + + [self callUpdate:call state:linphone_call_get_state(call)]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneCallUpdate" + object:nil]; +} + + + #pragma mark - Event Functions -- (void)callUpdate:(NSNotification*)notif { +- (void)callUpdateEvent:(NSNotification*)notif { LinphoneCall *acall = [[notif.userInfo objectForKey: @"call"] pointerValue]; LinphoneCallState astate = [[notif.userInfo objectForKey: @"state"] intValue]; + [self callUpdate:acall state:astate]; +} + + +#pragma mark - + +- (void)callUpdate:(LinphoneCall *)acall state:(LinphoneCallState)astate { if(call == acall && (astate == LinphoneCallEnd || astate == LinphoneCallError)) { [self dismiss: IncomingCall_Aborted]; } } -#pragma mark - +#pragma mark - Property Functions -- (void)update:(LinphoneCall*)acall { +- (void)setCall:(LinphoneCall*)acall { [self view]; //Force view load call = acall; diff --git a/Classes/LinphoneAppDelegate.m b/Classes/LinphoneAppDelegate.m index d3428ce89..6f9234573 100644 --- a/Classes/LinphoneAppDelegate.m +++ b/Classes/LinphoneAppDelegate.m @@ -143,14 +143,14 @@ int __aeabi_idiv(int a, int b) { - (void)setupUI { if ([[LinphoneManager instance].settingsStore boolForKey:@"enable_first_login_view_preference"] == true) { // Change to fist login view - [[LinphoneManager instance] changeView: PhoneView_FirstLogin]; + [[PhoneMainView instance] changeView: PhoneView_FirstLogin]; } else { // Change to default view const MSList *list = linphone_core_get_proxy_config_list([LinphoneManager getLc]); if(list != NULL) { - [[LinphoneManager instance] changeView: PhoneView_Dialer]; + [[PhoneMainView instance] changeView: PhoneView_Dialer]; } else { - [[LinphoneManager instance] changeView: PhoneView_Wizard]; + [[PhoneMainView instance] changeView: PhoneView_Wizard]; } } diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 0079dd8e3..7328d6df2 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -20,6 +20,7 @@ #import #import #import +#import #import "LogView.h" #import "IASKSettingsReader.h" @@ -28,19 +29,6 @@ #include "linphonecore.h" -typedef enum _PhoneView { - PhoneView_Wizard, - PhoneView_FirstLogin, - PhoneView_Dialer, - PhoneView_History, - PhoneView_Settings, - PhoneView_Chat, - PhoneView_Contacts, - PhoneView_InCall, - PhoneView_IncomingCall, - PhoneView_END -} PhoneView; - typedef enum _Connectivity { wifi, wwan @@ -79,9 +67,8 @@ typedef struct _LinphoneCallAppData { const char* frontCamId; const char* backCamId; - PhoneView currentView; - id settingsStore; + sqlite3 *database; @public CallContext currentCallContextBeforeGoingBackground; @@ -108,12 +95,6 @@ typedef struct _LinphoneCallAppData { - (void)setupNetworkReachabilityCallback; - (void)refreshRegisters; -- (void)changeView:(PhoneView) view; -- (void)changeView:(PhoneView) view dict:(NSDictionary *)dict; -- (void)showTabBar:(BOOL) show; -- (void)fullScreen:(BOOL) enabled; -- (PhoneView) currentView; - - (void)enableSpeaker:(BOOL)enable; - (BOOL)isSpeakerEnabled; @@ -123,6 +104,7 @@ typedef struct _LinphoneCallAppData { @property (nonatomic) int defaultExpires; @property (readonly) const char* frontCamId; @property (readonly) const char* backCamId; +@property (readonly) sqlite3* database; @end diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index cbff80a55..fd56aacc4 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -58,13 +58,12 @@ extern void libmsbcg729_init(); @implementation LinphoneManager -PhoneView currentView = -1; - @synthesize connectivity; @synthesize frontCamId; @synthesize backCamId; @synthesize defaultExpires; @synthesize settingsStore; +@synthesize database; struct codec_name_pref_table{ const char *name; @@ -110,46 +109,59 @@ struct codec_name_pref_table codec_pref_table[]={ - (id)init { assert (!theLinphoneManager); - if ((self= [super init])) { + if ((self = [super init])) { mFastAddressBook = [[FastAddressBook alloc] init]; + database = NULL; theLinphoneManager = self; - self.defaultExpires=600; + self.defaultExpires = 600; + [self openDatabase]; } return self; } +- (void)dealloc { + [mFastAddressBook release]; + [self closeDatabase]; + + [super dealloc]; +} + +- (void)openDatabase { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentsPath = [paths objectAtIndex:0]; + NSString *databaseDocumentPath = [documentsPath stringByAppendingPathComponent:@"database.txt"]; + + // Copy default database + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + //[fileManager removeItemAtPath:databaseDocumentPath error:&error]; //TODO REMOVE + if ([fileManager fileExistsAtPath:databaseDocumentPath] == NO) { + NSLog(@"Create sqlite 3 database"); + NSString *resourceDocumentPath = [[NSBundle mainBundle] pathForResource:@"database" ofType:@"sqlite"]; + [fileManager copyItemAtPath:resourceDocumentPath toPath:databaseDocumentPath error:&error]; + if(error != nil) { + NSLog(@"Can't copy database: %@", [error localizedDescription]); + return; + } + } + + if(sqlite3_open([databaseDocumentPath UTF8String], &database) != SQLITE_OK) { + NSLog(@"Can't open \"%@\" sqlite3 database.", databaseDocumentPath); + } +} + +- (void)closeDatabase { + if(database != NULL) { + if(sqlite3_close(database) != SQLITE_OK) { + NSLog(@"Can't close sqlite3 database."); + } + } +} + + (LinphoneManager*)instance { return theLinphoneManager; } -- (void) showTabBar:(BOOL) show { - NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithBool:show] forKey:@"tabBar"]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneMainViewChange" object:self userInfo:mdict]; -} - -- (void)fullScreen:(BOOL) enabled { - NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithBool:enabled] forKey:@"fullscreen"]; - [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneMainViewChange" object:self userInfo:mdict]; -} - -- (void)changeView:(PhoneView) view { - [self changeView:view dict:nil]; -} - -- (void)changeView:(PhoneView) view dict:(NSDictionary *)dict { - currentView = view; - - NSMutableDictionary* mdict = [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithInt:currentView] forKey:@"view"]; - if(dict != nil) - [mdict setObject:dict forKey:@"args"]; - - [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneMainViewChange" object:self userInfo:mdict]; -} - -- (PhoneView)currentView { - return currentView; -} - -(NSString*) getDisplayNameFromAddressBook:(NSString*) number andUpdateCallLog:(LinphoneCallLog*)log { //1 normalize NSString* lNormalizedNumber = [FastAddressBook normalizePhoneNumber:number]; diff --git a/Classes/LinphoneUI/UICallBar.m b/Classes/LinphoneUI/UICallBar.m index 4e0b4d8b7..dad26c74b 100644 --- a/Classes/LinphoneUI/UICallBar.m +++ b/Classes/LinphoneUI/UICallBar.m @@ -19,6 +19,7 @@ #import "UICallBar.h" #import "LinphoneManager.h" +#import "PhoneMainView.h" #import "CPAnimationSequence.h" #import "CPAnimationStep.h" @@ -125,8 +126,6 @@ [sharpButton setDigit:'#']; [sharpButton setDtmf:true]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callUpdate:) name:@"LinphoneCallUpdate" object:nil]; - // Set selected+disabled background: IB lack ! [videoButton setImage:[UIImage imageNamed:@"video_on_disabled.png"] forState:(UIControlStateDisabled | UIControlStateSelected)]; @@ -153,17 +152,40 @@ forState:(UIControlStateHighlighted | UIControlStateSelected)]; } -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(callUpdateEvent:) + name:@"LinphoneCallUpdate" + object:nil]; + + // Update on show + LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]); + LinphoneCallState state = (call != NULL)?linphone_call_get_state(call): 0; + [self callUpdate:call state:state]; } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneCallUpdate" + object:nil]; +} #pragma mark - Event Functions -- (void)callUpdate: (NSNotification*) notif { - //LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue]; +- (void)callUpdateEvent:(NSNotification*)notif { + LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue]; LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue]; - + [self callUpdate:call state:state]; +} + + +#pragma mark - + +- (void)callUpdate:(LinphoneCall*)call state:(LinphoneCallState)state { LinphoneCore* lc = [LinphoneManager getLc]; [speakerButton update]; @@ -335,7 +357,7 @@ [[[NSArray alloc] initWithObjects: [NSNumber numberWithInt: TRUE], nil] autorelease] , @"setTransferMode:", nil] autorelease]; - [[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict]; + [[PhoneMainView instance] changeView:PhoneView_Dialer dict:dict]; } - (IBAction)onOptionsAddClick:(id)sender { @@ -347,7 +369,7 @@ [[[NSArray alloc] initWithObjects: [NSNumber numberWithInt: FALSE], nil] autorelease] , @"setTransferMode:", nil] autorelease]; - [[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict]; + [[PhoneMainView instance] changeView:PhoneView_Dialer dict:dict]; } - (IBAction)onOptionsClick:(id)sender { diff --git a/Classes/LinphoneUI/UIChatCell.h b/Classes/LinphoneUI/UIChatCell.h index 6d10e6374..2cfdede30 100644 --- a/Classes/LinphoneUI/UIChatCell.h +++ b/Classes/LinphoneUI/UIChatCell.h @@ -19,17 +19,24 @@ #import +#import "ChatModel.h" + @interface UIChatCell : UITableViewCell { UIImageView *avatarView; UILabel *displayNameLabel; UILabel *chatContentLabel; + + ChatModel *chat; } +- (void)update; + +@property (weak) ChatModel *chat; + @property (nonatomic, retain) IBOutlet UIImageView *avatarView; @property (nonatomic, retain) IBOutlet UILabel* displayNameLabel; @property (nonatomic, retain) IBOutlet UILabel* chatContentLabel; -- (IBAction)onDetails: (id) event; +- (IBAction)onDetails:(id)event; -- (void)update; @end diff --git a/Classes/LinphoneUI/UIChatCell.m b/Classes/LinphoneUI/UIChatCell.m index 6d0a7737d..5f3973769 100644 --- a/Classes/LinphoneUI/UIChatCell.m +++ b/Classes/LinphoneUI/UIChatCell.m @@ -25,6 +25,7 @@ @synthesize displayNameLabel; @synthesize chatContentLabel; +@synthesize chat; #pragma mark - Lifecycle Functions @@ -50,31 +51,33 @@ #pragma mark - -- (void)update{ +- (void)update { + [avatarView setImage:[UIImage imageNamed:@"avatar_unknown_small.png"]]; - [avatarView setImage:[UIImage imageNamed:@"avatar-small.png"]]; + [displayNameLabel setText:[chat remoteContact]]; + [chatContentLabel setText:[chat message]]; // // Adapt size // - CGRect firstNameFrame = [displayNameLabel frame]; - CGRect lastNameFrame = [chatContentLabel frame]; + CGRect displayNameFrame = [displayNameLabel frame]; + CGRect chatContentFrame = [chatContentLabel frame]; - lastNameFrame.origin.x -= firstNameFrame.size.width; + chatContentFrame.origin.x -= displayNameFrame.size.width; // Compute firstName size CGSize contraints; contraints.height = [displayNameLabel frame].size.height; contraints.width = ([chatContentLabel frame].size.width + [chatContentLabel frame].origin.x) - [displayNameLabel frame].origin.x; CGSize firstNameSize = [[displayNameLabel text] sizeWithFont:[displayNameLabel font] constrainedToSize: contraints]; - firstNameFrame.size.width = firstNameSize.width; + displayNameFrame.size.width = firstNameSize.width; // Compute lastName size & position - lastNameFrame.origin.x += firstNameFrame.size.width; - lastNameFrame.size.width = (contraints.width + [displayNameLabel frame].origin.x) - lastNameFrame.origin.x; + chatContentFrame.origin.x += displayNameFrame.size.width; + chatContentFrame.size.width = (contraints.width + [displayNameLabel frame].origin.x) - chatContentFrame.origin.x; - [displayNameLabel setFrame: firstNameFrame]; - [chatContentLabel setFrame: lastNameFrame]; + [displayNameLabel setFrame: displayNameFrame]; + [chatContentLabel setFrame: chatContentFrame]; } diff --git a/Classes/LinphoneUI/UIChatCell.xib b/Classes/LinphoneUI/UIChatCell.xib index dcdc7cd9d..dbf9b0730 100644 --- a/Classes/LinphoneUI/UIChatCell.xib +++ b/Classes/LinphoneUI/UIChatCell.xib @@ -47,6 +47,10 @@ _NS:9 NO IBCocoaTouchFramework + + NSImage + avatar_unknown_small.png + @@ -123,6 +127,7 @@ {{276, 0}, {44, 44}} + _NS:9 NO IBCocoaTouchFramework @@ -133,25 +138,17 @@ 11 11 11 - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - 3 MC41AA NSImage - bouton-detail-contact-over.png + list_details_over.png NSImage - bouton-detail-contact-actif.png + list_details_default.png 2 @@ -169,15 +166,39 @@ _NS:9 - + 3 - MQA - - 2 - + MCAwAA IBCocoaTouchFramework + + + 292 + {320, 44} + + + + _NS:9 + NO + IBCocoaTouchFramework + + NSImage + list_hightlight.png + + + + + 292 + {320, 44} + + + + _NS:9 + + NO + IBCocoaTouchFramework + @@ -205,6 +226,22 @@ 25 + + + backgroundView + + + + 28 + + + + selectedBackgroundView + + + + 29 + onDetails: @@ -269,6 +306,18 @@ chatContentLabel + + 26 + + + selectedBackground + + + 27 + + + background + @@ -283,12 +332,14 @@ com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 25 + 29 @@ -341,8 +392,10 @@ YES 3 - {45, 45} - {45, 45} + {131, 131} + {45, 45} + {45, 45} + {640, 88} 1181 diff --git a/Classes/LinphoneUI/UICompositeViewController.h b/Classes/LinphoneUI/UICompositeViewController.h index 0a551c8a7..32c7a3439 100644 --- a/Classes/LinphoneUI/UICompositeViewController.h +++ b/Classes/LinphoneUI/UICompositeViewController.h @@ -40,6 +40,12 @@ @end +@protocol UICompositeViewDelegate + ++ (UICompositeViewDescription*) compositeViewDescription; + +@end + @interface UICompositeViewController : UIViewController { @private UIView *stateBarView; diff --git a/Classes/LinphoneUI/UICompositeViewController.m b/Classes/LinphoneUI/UICompositeViewController.m index 76efd4cde..934d17e7c 100644 --- a/Classes/LinphoneUI/UICompositeViewController.m +++ b/Classes/LinphoneUI/UICompositeViewController.m @@ -24,9 +24,10 @@ - (id)copy { UICompositeViewDescription *copy = [UICompositeViewDescription alloc]; copy->content = self->content; + copy->stateBar = self->stateBar; + copy->stateBarEnabled = self->stateBarEnabled; copy->tabBar = self->tabBar; copy->tabBarEnabled = self->tabBarEnabled; - copy->stateBarEnabled = self->stateBarEnabled; copy->fullscreen = self->fullscreen; return copy; } @@ -156,13 +157,13 @@ } } - if(contentViewController != nil) { + if(oldViewDescription != nil && contentViewController != nil && oldViewDescription->content != currentViewDescription->content) { [UICompositeViewController removeSubView: contentViewController]; } - if(tabBarViewController != nil) { + if(oldViewDescription != nil && tabBarViewController != nil && oldViewDescription->tabBar != currentViewDescription->tabBar) { [UICompositeViewController removeSubView: tabBarViewController]; } - if(stateBarViewController != nil) { + if(oldViewDescription != nil && stateBarViewController != nil && oldViewDescription->stateBar != currentViewDescription->stateBar) { [UICompositeViewController removeSubView: stateBarViewController]; } @@ -253,9 +254,15 @@ // Change view if(description != nil) { - [UICompositeViewController addSubView: contentViewController view:contentView]; - [UICompositeViewController addSubView: tabBarViewController view:tabBarView]; - [UICompositeViewController addSubView: stateBarViewController view:stateBarView]; + if(oldViewDescription == nil || oldViewDescription->content != currentViewDescription->content) { + [UICompositeViewController addSubView: contentViewController view:contentView]; + } + if(oldViewDescription == nil || oldViewDescription->tabBar != currentViewDescription->tabBar) { + [UICompositeViewController addSubView: tabBarViewController view:tabBarView]; + } + if(oldViewDescription == nil || oldViewDescription->stateBar != currentViewDescription->stateBar) { + [UICompositeViewController addSubView: stateBarViewController view:stateBarView]; + } } // Dealloc old view description diff --git a/Classes/LinphoneUI/UIHistoryCell.h b/Classes/LinphoneUI/UIHistoryCell.h index 7500e1c8a..59e4b8ea9 100644 --- a/Classes/LinphoneUI/UIHistoryCell.h +++ b/Classes/LinphoneUI/UIHistoryCell.h @@ -30,6 +30,8 @@ LinphoneCallLog *callLog; } +@property (assign) LinphoneCallLog *callLog; + @property (nonatomic, retain) IBOutlet UIImageView* imageView; @property (nonatomic, retain) IBOutlet UILabel* displayNameLabel; @property (nonatomic, retain) IBOutlet UIButton* detailsButton; @@ -40,7 +42,7 @@ - (IBAction)onDetails:(id) event; - (IBAction)onDelete:(id) event; -- (void)update:(LinphoneCallLog*) callLogs; +- (void)update; - (void)enterEditMode; - (void)exitEditMode; diff --git a/Classes/LinphoneUI/UIHistoryCell.m b/Classes/LinphoneUI/UIHistoryCell.m index 248431b35..3ca3d5592 100644 --- a/Classes/LinphoneUI/UIHistoryCell.m +++ b/Classes/LinphoneUI/UIHistoryCell.m @@ -22,6 +22,7 @@ @implementation UIHistoryCell +@synthesize callLog; @synthesize displayNameLabel; @synthesize imageView; @synthesize deleteButton; @@ -75,21 +76,21 @@ #pragma mark - -- (void)update:(LinphoneCallLog*) aCallLog { - self->callLog = aCallLog; +- (void)update { + // Set up the cell... LinphoneAddress* partyToDisplay; UIImage *image; - if (aCallLog->dir == LinphoneCallIncoming) { - if (aCallLog->status == LinphoneCallSuccess) { + if (callLog->dir == LinphoneCallIncoming) { + if (callLog->status == LinphoneCallSuccess) { image = [UIImage imageNamed:@"call_status_incoming.png"]; } else { image = [UIImage imageNamed:@"call_status_missed.png"]; } - partyToDisplay = aCallLog->from; + partyToDisplay = callLog->from; } else { image = [UIImage imageNamed:@"call_status_outgoing.png"]; - partyToDisplay = aCallLog->to; + partyToDisplay = callLog->to; } const char* username = linphone_address_get_username(partyToDisplay)!=0?linphone_address_get_username(partyToDisplay):""; diff --git a/Classes/LinphoneUI/UIMainBar.m b/Classes/LinphoneUI/UIMainBar.m index 36150e13c..f49ba5535 100644 --- a/Classes/LinphoneUI/UIMainBar.m +++ b/Classes/LinphoneUI/UIMainBar.m @@ -37,34 +37,49 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [historyButton release]; + [contactsButton release]; + [dialerButton release]; + [settingsButton release]; + [chatButton release]; + [super dealloc]; } #pragma mark - ViewController Functions -- (void)viewDidLoad { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeView:) name:@"LinphoneMainViewChange" object:nil]; - [self update:[[LinphoneManager instance] currentView]]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(changeViewEvent:) + name:@"LinphoneMainViewChange" + object:nil]; + [self update:[[PhoneMainView instance] currentView]]; } -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - [historyButton release]; - [contactsButton release]; - [dialerButton release]; - [settingsButton release]; - [chatButton release]; +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneMainViewChange" + object:nil]; } -#pragma mark - -- (void)changeView: (NSNotification*) notif { +#pragma mark - Event Functions + +- (void)changeViewEvent: (NSNotification*) notif { NSNumber *viewNumber = [notif.userInfo objectForKey: @"view"]; if(viewNumber != nil) [self update:[viewNumber intValue]]; } + +#pragma mark - + - (void)update:(PhoneView) view { if(view == PhoneView_History) { historyButton.selected = TRUE; @@ -97,23 +112,23 @@ #pragma mark - Action Functions - (IBAction)onHistoryClick: (id) sender { - [[LinphoneManager instance] changeView:PhoneView_History]; + [[PhoneMainView instance] changeView:PhoneView_History]; } - (IBAction)onContactsClick: (id) event { - [[LinphoneManager instance] changeView:PhoneView_Contacts]; + [[PhoneMainView instance] changeView:PhoneView_Contacts]; } - (IBAction)onDialerClick: (id) event { - [[LinphoneManager instance] changeView:PhoneView_Dialer]; + [[PhoneMainView instance] changeView:PhoneView_Dialer]; } - (IBAction)onSettingsClick: (id) event { - [[LinphoneManager instance] changeView:PhoneView_Settings]; + [[PhoneMainView instance] changeView:PhoneView_Settings]; } - (IBAction)onChatClick: (id) event { - [[LinphoneManager instance] changeView:PhoneView_Chat]; + [[PhoneMainView instance] changeView:PhoneView_Chat]; } diff --git a/Classes/LinphoneUI/UIStateBar.m b/Classes/LinphoneUI/UIStateBar.m index 8df168b19..97ea70e3d 100644 --- a/Classes/LinphoneUI/UIStateBar.m +++ b/Classes/LinphoneUI/UIStateBar.m @@ -47,19 +47,22 @@ NSTimer *callQualityTimer; #pragma mark - ViewController Functions -- (void)viewDidLoad { - [super viewDidLoad]; - - // Set observer - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(registrationUpdate:) name:@"LinphoneRegistrationUpdate" object:nil]; +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; // Set callQualityTimer [callQualityImage setHidden: true]; callQualityTimer = [NSTimer scheduledTimerWithTimeInterval:1 - target:self - selector:@selector(callQualityUpdate) - userInfo:nil - repeats:YES]; + target:self + selector:@selector(callQualityUpdate) + userInfo:nil + repeats:YES]; + + // Set observer + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(registrationUpdate:) + name:@"LinphoneRegistrationUpdate" + object:nil]; // Update to default state LinphoneProxyConfig* config = NULL; @@ -68,8 +71,14 @@ NSTimer *callQualityTimer; [self proxyConfigUpdate: config]; } -- (void) viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self]; +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // Remove observer + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneRegistrationUpdate" + object:nil]; + [callQualityTimer invalidate]; } @@ -82,6 +91,9 @@ NSTimer *callQualityTimer; [self proxyConfigUpdate:config]; } + +#pragma mark - + - (void)proxyConfigUpdate: (LinphoneProxyConfig*) config { LinphoneRegistrationState state; NSString* message = nil; diff --git a/Classes/LinphoneUI/UIStateBar.xib b/Classes/LinphoneUI/UIStateBar.xib index 7ef29c7d7..ff171f256 100644 --- a/Classes/LinphoneUI/UIStateBar.xib +++ b/Classes/LinphoneUI/UIStateBar.xib @@ -63,7 +63,7 @@ IBCocoaTouchFramework NSImage - status_disconnected.png + led_disconnected.png @@ -269,8 +269,8 @@ YES 3 + {18, 17} {640, 46} - {18, 17} 1181 diff --git a/Classes/Model/ChatModel.h b/Classes/Model/ChatModel.h new file mode 100644 index 000000000..4c2f11963 --- /dev/null +++ b/Classes/Model/ChatModel.h @@ -0,0 +1,47 @@ +/* ChatModel.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 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 + +@interface ChatModel : NSObject { + @private + NSNumber *chatId; + NSString *localContact; + NSString *remoteContact; + NSNumber *direction; + NSString *message; + NSDate *time; +} + +@property (nonatomic, readonly) NSNumber *chatId; +@property (nonatomic, copy) NSString *localContact; +@property (nonatomic, copy) NSString *remoteContact; +@property (nonatomic, copy) NSNumber *direction; +@property (nonatomic, copy) NSString *message; +@property (nonatomic, copy) NSDate *time; + +- (void) create; ++ (ChatModel*) read:(NSNumber*)id; +- (void) update; +- (void) delete; + ++ (NSArray *) listConversations; ++ (NSArray *) listMessages:(NSString *)contact; + +@end diff --git a/Classes/Model/ChatModel.m b/Classes/Model/ChatModel.m new file mode 100644 index 000000000..5c5ef40ed --- /dev/null +++ b/Classes/Model/ChatModel.m @@ -0,0 +1,229 @@ +/* ChatModel.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 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 "ChatModel.h" +#import "LinphoneManager.h" + +@implementation ChatModel + +@synthesize chatId; +@synthesize localContact; +@synthesize remoteContact; +@synthesize message; +@synthesize direction; +@synthesize time; + + +#pragma mark - Lifecycle Functions + +- (id)initWithData:(sqlite3_stmt *)sqlStatement { + self = [super init]; + if (self != nil) { + self->chatId = [[NSNumber alloc] initWithInt: sqlite3_column_int(sqlStatement, 0)]; + self.localContact = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 1)]; + self.remoteContact = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 2)]; + self.direction = [NSNumber numberWithInt:sqlite3_column_int(sqlStatement, 3)]; + self.message = [NSString stringWithUTF8String: (const char*) sqlite3_column_text(sqlStatement, 4)]; + self.time = [NSDate dateWithTimeIntervalSince1970:sqlite3_column_int(sqlStatement, 5)]; + } + return self; +} + +- (void)dealloc { + [chatId release]; + [localContact release]; + [remoteContact release]; + [message release]; + [direction release]; + [time release]; + + [super dealloc]; +} + + +#pragma mark - CRUD Functions + +- (void)create { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return; + } + const char *sql = [[NSString stringWithFormat:@"INSERT INTO chat (localContact, remoteContact, direction, message, time) VALUES (\"%@\", \"%@\", %i, \"%@\", %i)", + localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970]] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return; + } + + if (sqlite3_step(sqlStatement) != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + } +} + ++ (ChatModel*)read:(NSNumber*)chatId { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return nil; + } + + const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time FROM chat WHERE id=%@", + chatId] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return nil; + } + + ChatModel* line = nil; + int err = sqlite3_step(sqlStatement); + if (err == SQLITE_ROW) { + line = [[ChatModel alloc] initWithData:sqlStatement]; + } else if (err != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + return nil; + } + + sqlite3_finalize(sqlStatement); + return line; +} + +- (void)update { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return; + } + + const char *sql = [[NSString stringWithFormat:@"UPDATE chat SET localContact=\"%@\", remoteContact=\"%@\", direction=%i, message=\"%@\", time=%i WHERE id=%@", + localContact, remoteContact, [direction intValue], message, [time timeIntervalSince1970], chatId] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return; + } + + if (sqlite3_step(sqlStatement) != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + return; + } + + sqlite3_finalize(sqlStatement); +} + +- (void)delete { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return; + } + + const char *sql = [[NSString stringWithFormat:@"DELETE chat WHERE id=%@", + chatId] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't prepare the query: %s (%s)", sql, sqlite3_errmsg(database)); + return; + } + + if (sqlite3_step(sqlStatement) != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + sqlite3_finalize(sqlStatement); + return; + } + + sqlite3_finalize(sqlStatement); +} + + +#pragma mark - + ++ (NSArray *)listConversations { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return [[[NSArray alloc] init] autorelease]; + } + + const char *sql = "SELECT id, localContact, remoteContact, direction, message, time FROM chat GROUP BY remoteContact ORDER BY time DESC"; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)); + return [[[NSArray alloc] init] autorelease]; + } + + NSMutableArray *array = [[NSMutableArray alloc] init]; + int err; + while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { + ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; + [array addObject:line]; + } + + if (err != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + return [[[NSArray alloc] init] autorelease]; + } + + sqlite3_finalize(sqlStatement); + + NSArray *fArray = [NSArray arrayWithArray: array]; + [array release]; + return fArray; +} + ++ (NSArray *)listMessages:(NSString *)contact { + sqlite3* database = [[LinphoneManager instance] database]; + if(database == NULL) { + NSLog(@"Database not ready"); + return [[[NSArray alloc] init] autorelease]; + } + + const char *sql = [[NSString stringWithFormat:@"SELECT id, localContact, remoteContact, direction, message, time FROM chat WHERE remoteContact=\"%@\" ORDER BY time ASC", + contact] UTF8String]; + sqlite3_stmt *sqlStatement; + if (sqlite3_prepare(database, sql, -1, &sqlStatement, NULL) != SQLITE_OK) { + NSLog(@"Can't execute the query: %s (%s)", sql, sqlite3_errmsg(database)); + return [[[NSArray alloc] init] autorelease]; + } + + NSMutableArray *array = [[NSMutableArray alloc] init]; + int err; + while ((err = sqlite3_step(sqlStatement)) == SQLITE_ROW) { + ChatModel *line = [[ChatModel alloc] initWithData:sqlStatement]; + [array addObject:line]; + } + + if (err != SQLITE_DONE) { + NSLog(@"Error during execution of query: %s (%s)", sql, sqlite3_errmsg(database)); + return [[[NSArray alloc] init] autorelease]; + } + + sqlite3_finalize(sqlStatement); + + NSArray *fArray = [NSArray arrayWithArray: array]; + [array release]; + return fArray; +} + +@end diff --git a/Classes/MoreViewController.h b/Classes/MoreViewController.h index 4cc2a28d4..896a3a003 100644 --- a/Classes/MoreViewController.h +++ b/Classes/MoreViewController.h @@ -20,7 +20,7 @@ #import @class ConsoleViewController; -@interface MoreViewController : UITableViewController { +@interface MoreViewController : UITableViewController { bool isLogViewEnabled; diff --git a/Classes/PhoneMainView.h b/Classes/PhoneMainView.h index b8dc86c26..3bb0af14d 100644 --- a/Classes/PhoneMainView.h +++ b/Classes/PhoneMainView.h @@ -24,6 +24,20 @@ #import "UICompositeViewController.h" #import "UIModalViewController.h" +typedef enum _PhoneView { + PhoneView_Wizard, + PhoneView_FirstLogin, + PhoneView_Dialer, + PhoneView_History, + PhoneView_Settings, + PhoneView_Chat, + PhoneView_ChatRoom, + PhoneView_Contacts, + PhoneView_InCall, + PhoneView_IncomingCall, + PhoneView_END +} PhoneView; + @interface PhoneMainView : UIViewController { @private UICompositeViewController *mainViewController; @@ -31,14 +45,28 @@ NSMutableArray *modalControllers; NSMutableDictionary *viewDescriptions; - PhoneView currentPhoneView; - + UIActionSheet *incomingCallActionSheet; UIActionSheet *batteryActionSheet; int loadCount; + + PhoneView currentView; + NSMutableArray* viewStack; } @property (nonatomic, retain) IBOutlet UICompositeViewController *mainViewController; +- (void)changeView:(PhoneView)view; +- (void)changeView:(PhoneView)view push:(BOOL)push; +- (void)changeView:(PhoneView)view dict:(NSDictionary *)dict; +- (void)changeView:(PhoneView)view dict:(NSDictionary *)dict push:(BOOL)push; +- (void)popView; +- (void)popView:(NSDictionary *)dict; +- (void)showTabBar:(BOOL)show; +- (void)fullScreen:(BOOL)enabled; +- (PhoneView)currentView; + ++ (PhoneMainView*) instance; + @end diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m index 1a6cecd47..7b2cc2ef4 100644 --- a/Classes/PhoneMainView.m +++ b/Classes/PhoneMainView.m @@ -24,8 +24,20 @@ #import "FirstLoginViewController.h" #import "IncomingCallViewController.h" +#import "ChatRoomViewController.h" +#import "ChatViewController.h" +#import "DialerViewController.h" +#import "ContactsViewController.h" +#import "HistoryViewController.h" +#import "InCallViewController.h" +#import "SettingsViewController.h" +#import "FirstLoginViewController.h" +#import "WizardViewController.h" + #import "AbstractCall.h" +static PhoneMainView* phoneMainViewInstance=nil; + @implementation PhoneMainView @synthesize mainViewController; @@ -34,7 +46,10 @@ #pragma mark - Lifecycle Functions - (void)initPhoneMainView { - currentPhoneView = -1; + assert (!phoneMainViewInstance); + phoneMainViewInstance = self; + currentView = -1; + viewStack = [[NSMutableArray alloc] init]; loadCount = 0; // For avoiding IOS 4 bug // Init view descriptions @@ -77,6 +92,8 @@ [modalControllers removeAllObjects]; [modalControllers release]; + [viewStack release]; + [super dealloc]; } @@ -91,110 +108,22 @@ [super viewDidLoad]; [[self view] addSubview: mainViewController.view]; - // - // Main View - // - UICompositeViewDescription *dialerDescription = [UICompositeViewDescription alloc]; - dialerDescription->content = @"DialerViewController"; - dialerDescription->tabBar = @"UIMainBar"; - dialerDescription->tabBarEnabled = true; - dialerDescription->stateBar = @"UIStateBar"; - dialerDescription->stateBarEnabled = true; - dialerDescription->fullscreen = false; - [viewDescriptions setObject:dialerDescription forKey:[NSNumber numberWithInt: PhoneView_Dialer]]; - - - // - // Contacts View - // - UICompositeViewDescription *contactsDescription = [UICompositeViewDescription alloc]; - contactsDescription->content = @"ContactsViewController"; - contactsDescription->tabBar = @"UIMainBar"; - contactsDescription->tabBarEnabled = true; - contactsDescription->stateBar = nil; - contactsDescription->stateBarEnabled = false; - contactsDescription->fullscreen = false; - [viewDescriptions setObject:contactsDescription forKey:[NSNumber numberWithInt: PhoneView_Contacts]]; - - - // - // Call History View - // - UICompositeViewDescription *historyDescription = [UICompositeViewDescription alloc]; - historyDescription->content = @"HistoryViewController"; - historyDescription->tabBar = @"UIMainBar"; - historyDescription->tabBarEnabled = true; - historyDescription->stateBar = nil; - historyDescription->stateBarEnabled = false; - historyDescription->fullscreen = false; - [viewDescriptions setObject:historyDescription forKey:[NSNumber numberWithInt: PhoneView_History]]; - - // - // InCall View - // - UICompositeViewDescription *inCallDescription = [UICompositeViewDescription alloc]; - inCallDescription->content = @"InCallViewController"; - inCallDescription->tabBar = @"UICallBar"; - inCallDescription->tabBarEnabled = true; - inCallDescription->stateBar = @"UIStateBar"; - inCallDescription->stateBarEnabled = true; - inCallDescription->fullscreen = false; - [viewDescriptions setObject:inCallDescription forKey:[NSNumber numberWithInt: PhoneView_InCall]]; - - - // - // Settings View - // - UICompositeViewDescription *settingsDescription = [UICompositeViewDescription alloc]; - settingsDescription->content = @"SettingsViewController"; - settingsDescription->tabBar = @"UIMainBar"; - settingsDescription->tabBarEnabled = true; - settingsDescription->stateBar = nil; - settingsDescription->stateBarEnabled = false; - settingsDescription->fullscreen = false; - [viewDescriptions setObject:settingsDescription forKey:[NSNumber numberWithInt: PhoneView_Settings]]; - - // - // Chat View - // - UICompositeViewDescription *chatDescription = [UICompositeViewDescription alloc]; - chatDescription->content = @"ChatViewController"; - chatDescription->tabBar = @"UIMainBar"; - chatDescription->tabBarEnabled = true; - chatDescription->stateBar = nil; - chatDescription->stateBarEnabled = false; - chatDescription->fullscreen = false; - [viewDescriptions setObject:chatDescription forKey:[NSNumber numberWithInt: PhoneView_Chat]]; - - // - // FirstLogin View - // - UICompositeViewDescription *firstLoginDescription = [UICompositeViewDescription alloc]; - firstLoginDescription->content = @"FirstLoginViewController"; - firstLoginDescription->tabBar = nil; - firstLoginDescription->tabBarEnabled = false; - firstLoginDescription->stateBar = nil; - firstLoginDescription->stateBarEnabled = false; - firstLoginDescription->fullscreen = false; - [viewDescriptions setObject:firstLoginDescription forKey:[NSNumber numberWithInt: PhoneView_FirstLogin]]; - - // - // Wizard View - // - UICompositeViewDescription *wizardDescription = [UICompositeViewDescription alloc]; - wizardDescription->content = @"WizardViewController"; - wizardDescription->tabBar = nil; - wizardDescription->tabBarEnabled = false; - wizardDescription->stateBar = nil; - wizardDescription->stateBarEnabled = false; - wizardDescription->fullscreen = false; - [viewDescriptions setObject:wizardDescription forKey:[NSNumber numberWithInt: PhoneView_Wizard]]; + // Init descriptions + [viewDescriptions setObject:[ChatRoomViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_ChatRoom]]; + [viewDescriptions setObject:[ChatViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_Chat]]; + [viewDescriptions setObject:[DialerViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_Dialer]]; + [viewDescriptions setObject:[ContactsViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_Contacts]]; + [viewDescriptions setObject:[HistoryViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_History]]; + [viewDescriptions setObject:[InCallViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_InCall]]; + [viewDescriptions setObject:[SettingsViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_Settings]]; + [viewDescriptions setObject:[FirstLoginViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_FirstLogin]]; + [viewDescriptions setObject:[WizardViewController compositeViewDescription] forKey:[NSNumber numberWithInt: PhoneView_Wizard]]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; // Set observers - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(changeView:) - name:@"LinphoneMainViewChange" - object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callUpdate:) name:@"LinphoneCallUpdate" @@ -203,17 +132,31 @@ selector:@selector(registrationUpdate:) name:@"LinphoneRegistrationUpdate" object:nil]; - + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryLevelChanged:) name:UIDeviceBatteryLevelDidChangeNotification object:nil]; } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + // Remove observers + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneCallUpdate" + object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:@"LinphoneRegistrationUpdate" + object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIDeviceBatteryLevelDidChangeNotification + object:nil]; +} + - (void)viewDidUnload { [super viewDidUnload]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - + // Avoid IOS 4 bug self->loadCount--; } @@ -271,7 +214,7 @@ case LinphoneCallConnected: case LinphoneCallUpdated: { - [[LinphoneManager instance] changeView:PhoneView_InCall]; + [self changeView:PhoneView_InCall]; break; } case LinphoneCallUpdatedByRemote: @@ -280,7 +223,7 @@ const LinphoneCallParams* remote = linphone_call_get_remote_params(call); if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) { - [[LinphoneManager instance] changeView:PhoneView_InCall]; + [self changeView:PhoneView_InCall]; } break; } @@ -299,15 +242,15 @@ [[[NSArray alloc] initWithObjects: [NSNumber numberWithInt: FALSE], nil] autorelease] , @"setTransferMode:", nil] autorelease]; - [[LinphoneManager instance] changeView:PhoneView_Dialer dict:dict]; + [self changeView:PhoneView_Dialer dict:dict]; } else { - [[LinphoneManager instance] changeView:PhoneView_InCall]; + [self changeView:PhoneView_InCall]; } break; } case LinphoneCallStreamsRunning: { - [[LinphoneManager instance] changeView:PhoneView_InCall]; + [self changeView:PhoneView_InCall]; break; } default: @@ -318,12 +261,27 @@ #pragma mark - -- (CATransition*)getTransition:(PhoneView)old new:(PhoneView)new { ++ (CATransition*)getBackwardTransition { CATransition* trans = [CATransition animation]; [trans setType:kCATransitionPush]; [trans setDuration:0.35]; [trans setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; + [trans setSubtype:kCATransitionFromLeft]; + return trans; +} + ++ (CATransition*)getForwardTransition { + CATransition* trans = [CATransition animation]; + [trans setType:kCATransitionPush]; + [trans setDuration:0.35]; + [trans setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; + [trans setSubtype:kCATransitionFromRight]; + + return trans; +} + ++ (CATransition*)getTransition:(PhoneView)old new:(PhoneView)new { bool left = false; if(old == PhoneView_Chat) { @@ -351,44 +309,80 @@ } if(left) { - [trans setSubtype:kCATransitionFromLeft]; + return [PhoneMainView getBackwardTransition]; } else { - [trans setSubtype:kCATransitionFromRight]; + return [PhoneMainView getForwardTransition]; } - - return trans; } -- (void)changeView: (NSNotification*) notif { - NSNumber *viewId = [notif.userInfo objectForKey: @"view"]; - NSNumber *tabBar = [notif.userInfo objectForKey: @"tabBar"]; - NSNumber *fullscreen = [notif.userInfo objectForKey: @"fullscreen"]; - - // Check view change - if(viewId != nil) { - PhoneView view = [viewId intValue]; - UICompositeViewDescription* description = [viewDescriptions objectForKey:[NSNumber numberWithInt: view]]; - if(description == nil) - return; - if(view != currentPhoneView) { - [mainViewController setViewTransition:[self getTransition:currentPhoneView new:view]]; - [mainViewController changeView:description]; - currentPhoneView = view; - } ++ (PhoneMainView *) instance { + return phoneMainViewInstance; +} + +- (void) showTabBar:(BOOL) show { + [mainViewController setToolBarHidden:!show]; +} + +- (void)fullScreen:(BOOL) enabled { + [mainViewController setFullScreen:enabled]; +} + +- (void)changeView:(PhoneView)view { + [self changeView:view dict:nil push:FALSE]; +} + +- (void)changeView:(PhoneView)view dict:(NSDictionary *)dict { + [self changeView:view dict:dict push:FALSE]; +} + +- (void)changeView:(PhoneView)view push:(BOOL)push { + [self changeView:view dict:nil push:push]; +} + +- (void)changeView:(PhoneView)view dict:(NSDictionary *)dict push:(BOOL)push { + if(push && currentView != -1) { + [viewStack addObject:[NSNumber numberWithInt: currentView]]; + } else { + [viewStack removeAllObjects]; } + [self _changeView:view dict:dict transition:nil]; +} + +- (void)_changeView:(PhoneView)view dict:(NSDictionary *)dict transition:(CATransition*)transition { + UICompositeViewDescription* description = [viewDescriptions objectForKey:[NSNumber numberWithInt: view]]; + if(description == nil) + return; - if(tabBar != nil) { - [mainViewController setToolBarHidden:![tabBar boolValue]]; - } - - if(fullscreen != nil) { - [mainViewController setFullScreen:[fullscreen boolValue]]; - } + if(view != currentView) { + if(transition == nil) + transition = [PhoneMainView getTransition:currentView new:view]; + [mainViewController setViewTransition:transition]; + [mainViewController changeView:description]; + currentView = view; + } // Call abstractCall - NSDictionary *dict = [notif.userInfo objectForKey: @"args"]; if(dict != nil) [AbstractCall call:[mainViewController getCurrentViewController] dict:dict]; + + NSDictionary* mdict = [NSMutableDictionary dictionaryWithObject: [NSNumber numberWithInt:currentView] forKey:@"view"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"LinphoneMainViewChange" object:self userInfo:mdict]; +} + +- (void)popView { + [self popView:nil]; +} + +- (void)popView:(NSDictionary *)dict { + if([viewStack count] > 0) { + PhoneView view = [[viewStack lastObject] intValue]; + [viewStack removeLastObject]; + [self _changeView:view dict:dict transition:[PhoneMainView getBackwardTransition]]; + } +} + +- (PhoneView)currentView { + return currentView; } - (void)displayCallError:(LinphoneCall*) call message:(NSString*) message { @@ -461,7 +455,7 @@ } } else { IncomingCallViewController *controller = [[IncomingCallViewController alloc] init]; - [controller update:call]; + [controller setCall:call]; [self addModalViewController:controller]; } } diff --git a/Classes/SettingsViewController.h b/Classes/SettingsViewController.h index c6b0b4754..7bc3df627 100644 --- a/Classes/SettingsViewController.h +++ b/Classes/SettingsViewController.h @@ -19,9 +19,10 @@ #import +#import "UICompositeViewController.h" #import "IASKAppSettingsViewController.h" -@interface SettingsViewController: UIViewController { +@interface SettingsViewController: UIViewController { IASKAppSettingsViewController *settingsController; UINavigationController *navigationController; } diff --git a/Classes/SettingsViewController.m b/Classes/SettingsViewController.m index bd5f34100..41e117729 100644 --- a/Classes/SettingsViewController.m +++ b/Classes/SettingsViewController.m @@ -32,6 +32,20 @@ } +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { + UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"SettingsViewController"; + description->tabBar = @"UIMainBar"; + description->tabBarEnabled = true; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions - (void)viewDidLoad { diff --git a/Classes/WizardViewController.h b/Classes/WizardViewController.h index d1115d1f4..0326f5b07 100644 --- a/Classes/WizardViewController.h +++ b/Classes/WizardViewController.h @@ -19,7 +19,9 @@ #import -@interface WizardViewController : UIViewController { +#import "UICompositeViewController.h" + +@interface WizardViewController : UIViewController { UIView *contentView; UIView *welcomeView; diff --git a/Classes/WizardViewController.m b/Classes/WizardViewController.m index e3b1c4cb2..226f61ece 100644 --- a/Classes/WizardViewController.m +++ b/Classes/WizardViewController.m @@ -23,6 +23,8 @@ #import "LinphoneManager.h" +#import "PhoneMainView.h" + typedef enum _ViewElement { ViewElement_Username = 100, ViewElement_Password = 101, @@ -74,6 +76,20 @@ typedef enum _ViewElement { } +#pragma mark - UICompositeViewDelegate Functions + ++ (UICompositeViewDescription*) compositeViewDescription { +UICompositeViewDescription *description = [UICompositeViewDescription alloc]; + description->content = @"WizardViewController"; + description->tabBar = nil; + description->tabBarEnabled = false; + description->stateBar = nil; + description->stateBarEnabled = false; + description->fullscreen = false; + return description; +} + + #pragma mark - ViewController Functions - (void)viewDidLoad { @@ -168,7 +184,7 @@ typedef enum _ViewElement { } - (IBAction)onCancelClick:(id)sender { - [[LinphoneManager instance] changeView:PhoneView_Dialer]; + [[PhoneMainView instance] changeView:PhoneView_Dialer]; } - (IBAction)onCreateAccountClick:(id)sender { diff --git a/Resources/chat_back_default.png b/Resources/chat_back_default.png new file mode 100644 index 0000000000000000000000000000000000000000..3c90a7bb6868b1f7bca3bd8ab9118f83e2d33e52 GIT binary patch literal 4647 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 literal 0 HcmV?d00001 diff --git a/Resources/chat_field.png b/Resources/chat_field.png new file mode 100644 index 0000000000000000000000000000000000000000..17a1bee8df88d15de25356a53c840672dddd8162 GIT binary patch literal 4375 zcmbVQc{r5&+kZ4_RJI&tXBvepv)IPW*p0D{3gINn#9+wG7{iPZrKpf(OIgwhMQF3H zmB^M>vWzW}Fr%zl@{V&(=RNOr{jT31?{huZ^S$rybKjqP`F`#{p6AjLI}4#*(z^fv z5VEqw*#iLI0#6PR*v6BLRi2#VDN+n`7ls4XhruM$Nq~tr^&|;m6-e|Y*^`LgVL@#q zeEW(WM4yG>0R)m5Lh)}q60%{cp-EV5M3k;siloVq0}Lo2qXfI(1as3HIOKbmL>*) zfc$+ydC}e4hV9+pdIFreQF|}Y+x-T4wMx(bdG&MDN78=1}6b6x{ zK?zp;g@7Xkd(p`>2AN8MY#|a)QbQO9P+q2gl@LfH5dHzC1pnPAUd!MtA`Om&A>e_5 zTXp?u9n7#N{cjro(K^^Mj7EanlY*%sbT8g{_$dBz=JoEs2ih{^WrI0PC-V-4cnU}L z3JD}p7*;p~DDMr-o9vB2AoUPPBuX2B(nRR$A(19{Gc&ZQ849m!hC-lCkiRhglP?Zu zqK!A##OdkcP)MXX60N1FWsc|VB6ZQ`CMNh_zE+fA29e@L`W2VVi~F~)*?;xLn9)f@ z29@qerJnl5fFpiX1~u4^N`sg==s*ZWFEV9I-#VVZs>PA$dIsku1K%RYzsT}yi^sq%@gM5* zlz)bYMBz;goi`ed^%s44<7#1rGjU|~zwdb{{0t(#{k5spZ`L)^SV?CoS=)tHHyyi{ zr!VfoM{kdWBET`)FVU_KX^24bG zc5#bq` zs2;eKf9Y-efPDa`m&yp6V|(6cy=rj}Bj7dq-0A zJxjQJ+j!k!P6Y10;Q)M{mfUVE8M{qo*Y-jfJ3EWt*SDLi&L~nAy|*uDA)v@yqW6IE z%6aXuuJK*JBa*fc=#6$Bk5}7mL>tmlPME)4+AhvU`zG-9=~-A1%g&3syMaHK_gEjA zctdPc9u?{+zOJBj?vupx&YK&G#HWJk{+{|r!rnZ!l#Xh;w#mH&*k*pZAI@DP&h*EI zEs))p0uy7CZ9JZG4EQ~}6OM_-o<$_&T_4{mUTCb8JN%)XdToF0b#KvceoqXvEM}9I zg)Y3cRXDgjEVtyjSK{EV<~0SRHn(t|#lTvF9X)z;&+iv&3Vasc9a*s)F7Whtae3?) zV@REYpL+gyR(5d5rk%pdQB6uh-emhEzsh@WJ0$ z{m+h>*$Ehr7P)d=Y@9r~A+L}Q68GOWFA;S1meyAvuv!V zN~r!{RSzyn{-LtQYE%uIKn;E9xp;v)FB%;g97dKDc*YtK4HSFm)C_)dT=cZqp@p#* zQT>md%W_hiE+?zX7m0(U70IS>rlXC4{E3qsOSdNi zX>b~tDKNN6md~sf$?+%!JC{4AJ?cVs5yPT$ow*w$bGJ5a44+GC5mIgtqDxhT4Xm!| zUD;^8H9WA{!?kEtuBU|W-@8hvUdc8~y6t!4&N#Ds{?tH)di-ktNGXRoCLcR$h8UU- zZCJv#c4gZ+H%o;yI=^k0x;fpNC+^$qqZZX>x%jZmG^&jMPN~k2dH9Sn6Zz^Q!6mvQ zi0@+IMGUr;uM0M_uFYGt3(pVhNXnn-9bIn2eaBWw_%La`V#A|M!Vkf!ZWBYrpEnl8 z@mD^*9vk_RTGl6H=Z15$;TN(nOe8yK2-Uq0dKYx5_@Sf3QJbKG`UW~yHstut!I`@j z6Wg-Ca(yLYW)lk>^*s|vhE>(`Oy==`E)vZ-X{vBC!?k#6;g6!}8o;sci1O=Zxv)F( zoR_W(G}JzgBP#A?+a54s8ar`B$xysd@UsMKiG8?gm6v{AuPe?N8{LYM#l3mKf5-}& z{9TNEGNteJ$f%!Qk7(y?m=lb#@A>l%<`r&co`|5y+iX_ci19JdYdL_;r%xEq7{)eM zs|_37za#eTW5R0v!R{7)y$de1&>C*JPq=QW+zj{UbNj`T0c>rRyS2a19{2a7dlSHg zZW2)^L~>m|a^t+PH>Y(&P-1TJ3+5zuIVkEAQeKw97I&lgWr?e{TEtZ_8r9VgJb5Wf z)CZe12@S=^Ca@$+&X!I;toBx_UzzM<(+n`)woJO5Y&Q$dCZGw*0o`4fYFzKs{-{XH zow_nTBL7KbiIBZcx_o(er4b_=<*krHX&-fVZ2ZSGe}2&yxW*nkOSWZ(;fULM@nct~FYnz?7l+G9Nq+ zByzjxvK+gNqA))o6LZw`R7=dwbNUB9ybzRz&wg-xdxhf~F!jzf44#oT4f+nIp!EEz z(FGmbM|uL3rJdAMovib(E#`->T9gm9O+FHjetN8>Bk`s6;=Lh1Qu<^`RK9q;IY*A4 z-hSqpgTV*UyI&R0Tg(wN9<4bulz5{mHKn`@OjZ+2Jnkh7&bm znna!KEh)a$Z$9(P?|i`n4apAt?tnbX>HEw&2J1r@qcDE{>yHSSch0OH>&MFHZ;M%z zc?VTl0yP)UX1vWlxx$36W;rs&eRW&Cd7o`*lenww}9cz(_Hf*WfD-71!TajZ_&3zDB z7BSHFD*v=a@(;|-hR3TTP6rh=GLlSRyyyrnNtY6^mBq3vRflC7i|P2p2=TiIg=|D% z)@A9)XCde~+w}+TKYnzw2Qs>5K%)X(NZ)L#A2vPE7mG8K>p-%uL0Q z!dSjYe`ayd)x(EzW_An-U%Q29&aE_#o7OV_)1MdCqLYexRJ5wme_SbTX3^e+sJ$vt zY&X1|oo=^-0L4^Y{8}Tc)|Yp8m_lXSG5-*`ujdDi%*c;x83-jW4>X>1=6X0uX)l~v zffSU8B{+}E*u_f$U7ww1k1@%zJ)HZ85@bVb-tkGc2+HIi@@cY}y29bH;QgQX9V{>< zY+M7n$^m|fQ-&(+ooD8(Yu2h)CGge(Ki;3p44oR{GQYW8-+m!E95nMm+U|1Z4~Bi< zqp#Darul9qjTPlX2WBZFT*BXTlwPqI+em>^J!%l)N@xef+G2O3F6HRBs#W8~m0vzB(+Cik%}ql!*u<)AXHi-AfByWl3*8t^{sg4Ce!& z_`q`P;BG*)yy`Iw1T@P5#)EwSS}tON=qeC!TYkC!Tkcx<>S#yo3OjK^EyoBj)=jg% zBewIQ8*Ds2zS0lW?&Le9nRBUo&-3s;5bQhv`5pmM^Kk4O(j8!L zWR#`v3zjL)Umu)tX?7Ew8h{r~)?Yzyc3%jX@$SIVTX$jrQ@BUP`@ViGdnof*iIK}8 z!=IiTku4joT_q_gPRNWm+JrQ{NM#N%GQdPn!wP*TyWM3YSN*&K^F>1kySvvs&TP!K zPWwQ8K9VxlDBM~xZX&h>jM#aI$sW5IvUZ#M{T0XLj|WfYzKm|njls^0$CovPtv?Wt zat&4H47Gby8iIh|3@g@JB57?y!v=RVGHiGm194j0);m)Qo%*tDn!Ro)P=_yJ0hOG+ zp}kKGtE~Cw&+K0wmnc4QLcCr`krTdFp44OO)@$B8J3Ck95DFYwPbX#FuN@oWF3++i zIQiyukRaD&Y-l#S->dd#PvUbd2@IgW2`5`CPd9*qH01*tIXm<&@0l4N&x~A|E1mO~ z00^uh*_ZmN`5b-N6Ctr|+4`ze;a)%kw4d z065Z-$%Mk0rQ==Zrtn-5)62C1=M}Ee+l7Hr)tVmHEY}FjveKQ3oHNRE)ONQHJP<7t z@8A1z!^n8JcieED5!MNe)QoPVe-jL$7qS7-8xNG3tHQwk)X2JY5&&#=w8;U8f|NB+ z#7F}uI;b=}`iNFFsEJjXO_BmGj*q{3BnaSmABVs10HAtRYPK9ew7!aGVT@aQH7*R; za(J|ZN-=p@o}HiMmmUco7UU7KE&CD3*e_DVi=HI4I`z9z{xm8_h`Un|U?!HYe{koX z!lVg^`p2vNH>9*a0Pu7yp{AJ#2!u$q*b7#rSpLuu(n zdYmXgky?IwFx=x*$*@Qo>T+fWfAN#!_Z+w7p3Fb3pOSOj16f|&e3wGa?qGSyChU=K zYW9t^>6ywazBxb7p4hI;ww$yhY!yr1$-f{ze~kiv$B=QEr2W-I-CR zo!V>N~=z_YCq3~PNrIj1Kvopq}GM1JYQe?F|!EFce8b6su4nK zuY|&7%?>jGpfc-=g)DPOPY}2rhY|(>W5NK01N>`AiK$%P7A>$U)BT~UPbpDQVe40g NmAM_R)YS9b{{YNr&+`BP literal 0 HcmV?d00001 diff --git a/Resources/chat_ok_default.png b/Resources/chat_ok_default.png new file mode 100644 index 0000000000000000000000000000000000000000..0c49ac3d5414176c98d001554a4c31ece99bb328 GIT binary patch literal 4336 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 literal 0 HcmV?d00001 diff --git a/Resources/chat_ok_over.png b/Resources/chat_ok_over.png new file mode 100644 index 0000000000000000000000000000000000000000..4fe6248f82917e3f2aad61b5c687d3170e82ad29 GIT binary patch literal 4006 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 literal 0 HcmV?d00001 diff --git a/Resources/chat_send_default.png b/Resources/chat_send_default.png new file mode 100644 index 0000000000000000000000000000000000000000..1bee48a2f35c00afa3662d87d143bce80cf9948a GIT binary patch literal 5101 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 literal 0 HcmV?d00001 diff --git a/Resources/database.sqlite b/Resources/database.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..d52fcbd6e20bf26c09b10bf3134d4bb6680362f8 GIT binary patch literal 3072 zcmeHGPfNov6i=H@53=Lf^<9LG)suIzmLS!(n>7P_kP)+|7W#*^@dM~r@tgTcOohTM z?6$*{JoqK=zIc5Hir98lAPV(*=6Aw)|c0fSi4u z4(TJY?HfW*^kD3NDnQ>a=<#?ovOZQyJmn}~g=%5@3G+Au?p=ip+7*~&YY1Y_u2}+$ zB#68ugu;oHA)$`zuDxvFIEk1-msL|3+b;%^^%iP6zJ-cQ~lGQ jhyB~mu;sVi)rZa3urmr61@@?b>Hj^7X-XLd{+I&a=qF%l literal 0 HcmV?d00001 diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 930be9325..bd35fda31 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -223,6 +223,15 @@ D32648451588F6FC00930C67 /* UIToggleButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D32648431588F6FB00930C67 /* UIToggleButton.m */; }; D32942A41594C94300556A1C /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D32942A31594C94200556A1C /* SettingsViewController.xib */; }; D32942A51594C94300556A1C /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D32942A31594C94200556A1C /* SettingsViewController.xib */; }; + D32B6E2415A5B2020033019F /* chat_send_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D32B6E2315A5B2020033019F /* chat_send_disabled.png */; }; + D32B6E2515A5B2020033019F /* chat_send_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D32B6E2315A5B2020033019F /* chat_send_disabled.png */; }; + D32B6E2915A5BC440033019F /* ChatRoomTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B6E2815A5BC430033019F /* ChatRoomTableViewController.m */; }; + D32B6E2A15A5BC440033019F /* ChatRoomTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B6E2815A5BC430033019F /* ChatRoomTableViewController.m */; }; + D32B6E2C15A5C0800033019F /* database.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = D32B6E2B15A5C0800033019F /* database.sqlite */; }; + D32B6E2D15A5C0800033019F /* database.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = D32B6E2B15A5C0800033019F /* database.sqlite */; }; + D32B6E2F15A5C0AC0033019F /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D32B6E2E15A5C0AC0033019F /* libsqlite3.dylib */; }; + D32B6E3815A5C2430033019F /* ChatModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B6E3715A5C2430033019F /* ChatModel.m */; }; + D32B6E3915A5C2430033019F /* ChatModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B6E3715A5C2430033019F /* ChatModel.m */; }; D32B9DFC15A2F131000B6DEC /* FastAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */; }; D32B9DFD15A2F131000B6DEC /* FastAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */; }; D3432A62158A4446001C6B0B /* led_connected.png in Resources */ = {isa = PBXBuildFile; fileRef = D3432A5C158A4446001C6B0B /* led_connected.png */; }; @@ -423,6 +432,16 @@ D3A55FBD15877E5E003FD403 /* UIContactCell.m in Sources */ = {isa = PBXBuildFile; fileRef = D3A55FBB15877E5E003FD403 /* UIContactCell.m */; }; D3A55FBF15877E69003FD403 /* UIContactCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D3A55FBE15877E69003FD403 /* UIContactCell.xib */; }; D3A55FC015877E69003FD403 /* UIContactCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D3A55FBE15877E69003FD403 /* UIContactCell.xib */; }; + D3B9A3DF15A58C450096EA4E /* chat_field.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DA15A58C440096EA4E /* chat_field.png */; }; + D3B9A3E015A58C450096EA4E /* chat_field.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DA15A58C440096EA4E /* chat_field.png */; }; + D3B9A3E115A58C450096EA4E /* chat_ok_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DB15A58C440096EA4E /* chat_ok_default.png */; }; + D3B9A3E215A58C450096EA4E /* chat_ok_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DB15A58C440096EA4E /* chat_ok_default.png */; }; + D3B9A3E315A58C450096EA4E /* chat_ok_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DC15A58C440096EA4E /* chat_ok_over.png */; }; + D3B9A3E415A58C450096EA4E /* chat_ok_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DC15A58C440096EA4E /* chat_ok_over.png */; }; + D3B9A3E515A58C450096EA4E /* chat_send_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DD15A58C440096EA4E /* chat_send_default.png */; }; + D3B9A3E615A58C450096EA4E /* chat_send_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DD15A58C440096EA4E /* chat_send_default.png */; }; + D3B9A3E715A58C450096EA4E /* chat_send_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DE15A58C450096EA4E /* chat_send_over.png */; }; + D3B9A3E815A58C450096EA4E /* chat_send_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3B9A3DE15A58C450096EA4E /* chat_send_over.png */; }; D3C2814B15A2D38D0098AA42 /* dialer_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = D3C2814A15A2D38D0098AA42 /* dialer_selected.png */; }; D3C2814C15A2D38D0098AA42 /* dialer_selected.png in Resources */ = {isa = PBXBuildFile; fileRef = D3C2814A15A2D38D0098AA42 /* dialer_selected.png */; }; D3C2815215A2D64A0098AA42 /* numpad_star_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3C2815115A2D64A0098AA42 /* numpad_star_over.png */; }; @@ -525,6 +544,14 @@ D3F34F311599B008005BE94F /* avatar_shadow.png in Resources */ = {isa = PBXBuildFile; fileRef = D3F34F2F1599B008005BE94F /* avatar_shadow.png */; }; D3F34F351599C354005BE94F /* UIModalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F34F341599C354005BE94F /* UIModalViewController.m */; }; D3F34F361599C354005BE94F /* UIModalViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F34F341599C354005BE94F /* UIModalViewController.m */; }; + D3F795D615A582810077328B /* ChatRoomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F795D415A582800077328B /* ChatRoomViewController.m */; }; + D3F795D715A582810077328B /* ChatRoomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F795D415A582800077328B /* ChatRoomViewController.m */; }; + D3F795D815A582810077328B /* ChatRoomViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D3F795D515A582800077328B /* ChatRoomViewController.xib */; }; + D3F795D915A582810077328B /* ChatRoomViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D3F795D515A582800077328B /* ChatRoomViewController.xib */; }; + D3F795DD15A5831C0077328B /* chat_back_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3F795DB15A5831C0077328B /* chat_back_default.png */; }; + D3F795DE15A5831C0077328B /* chat_back_default.png in Resources */ = {isa = PBXBuildFile; fileRef = D3F795DB15A5831C0077328B /* chat_back_default.png */; }; + D3F795DF15A5831C0077328B /* chat_back_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3F795DC15A5831C0077328B /* chat_back_over.png */; }; + D3F795E015A5831C0077328B /* chat_back_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D3F795DC15A5831C0077328B /* chat_back_over.png */; }; D3F83EEC1582021700336684 /* InCallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F83EEA1582021700336684 /* InCallViewController.m */; }; D3F83EED1582021700336684 /* InCallViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D3F83EEA1582021700336684 /* InCallViewController.m */; }; D3F83EEE1582021700336684 /* InCallViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D3F83EEB1582021700336684 /* InCallViewController.xib */; }; @@ -979,6 +1006,13 @@ D32648421588F6FA00930C67 /* UIToggleButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIToggleButton.h; sourceTree = ""; }; D32648431588F6FB00930C67 /* UIToggleButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIToggleButton.m; sourceTree = ""; }; D32942A31594C94200556A1C /* SettingsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsViewController.xib; sourceTree = ""; }; + D32B6E2315A5B2020033019F /* chat_send_disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_send_disabled.png; path = Resources/chat_send_disabled.png; sourceTree = ""; }; + D32B6E2715A5BC430033019F /* ChatRoomTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatRoomTableViewController.h; sourceTree = ""; }; + D32B6E2815A5BC430033019F /* ChatRoomTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatRoomTableViewController.m; sourceTree = ""; }; + D32B6E2B15A5C0800033019F /* database.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; name = database.sqlite; path = Resources/database.sqlite; sourceTree = ""; }; + D32B6E2E15A5C0AC0033019F /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + D32B6E3615A5C2430033019F /* ChatModel.h */ = {isa = PBXFileReference; fileEncoding = 4; name = ChatModel.h; path = Model/ChatModel.h; sourceTree = ""; }; + D32B6E3715A5C2430033019F /* ChatModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ChatModel.m; path = Model/ChatModel.m; sourceTree = ""; }; D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FastAddressBook.h; path = Utils/FastAddressBook.h; sourceTree = ""; }; D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FastAddressBook.m; path = Utils/FastAddressBook.m; sourceTree = ""; }; D3432A5C158A4446001C6B0B /* led_connected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = led_connected.png; path = Resources/led_connected.png; sourceTree = ""; }; @@ -1115,6 +1149,11 @@ D3A55FBA15877E5E003FD403 /* UIContactCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIContactCell.h; sourceTree = ""; }; D3A55FBB15877E5E003FD403 /* UIContactCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIContactCell.m; sourceTree = ""; }; D3A55FBE15877E69003FD403 /* UIContactCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UIContactCell.xib; sourceTree = ""; }; + D3B9A3DA15A58C440096EA4E /* chat_field.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_field.png; path = Resources/chat_field.png; sourceTree = ""; }; + D3B9A3DB15A58C440096EA4E /* chat_ok_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_ok_default.png; path = Resources/chat_ok_default.png; sourceTree = ""; }; + D3B9A3DC15A58C440096EA4E /* chat_ok_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_ok_over.png; path = Resources/chat_ok_over.png; sourceTree = ""; }; + D3B9A3DD15A58C440096EA4E /* chat_send_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_send_default.png; path = Resources/chat_send_default.png; sourceTree = ""; }; + D3B9A3DE15A58C450096EA4E /* chat_send_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_send_over.png; path = Resources/chat_send_over.png; sourceTree = ""; }; D3C2814A15A2D38D0098AA42 /* dialer_selected.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = dialer_selected.png; path = Resources/dialer_selected.png; sourceTree = ""; }; D3C2815115A2D64A0098AA42 /* numpad_star_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = numpad_star_over.png; path = Resources/numpad_star_over.png; sourceTree = ""; }; D3C714B2159DB84400705B8E /* toy-mono.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; name = "toy-mono.wav"; path = "Resources/toy-mono.wav"; sourceTree = ""; }; @@ -1175,6 +1214,11 @@ D3F34F2F1599B008005BE94F /* avatar_shadow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = avatar_shadow.png; path = Resources/avatar_shadow.png; sourceTree = ""; }; D3F34F331599C354005BE94F /* UIModalViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIModalViewController.h; sourceTree = ""; }; D3F34F341599C354005BE94F /* UIModalViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIModalViewController.m; sourceTree = ""; }; + D3F795D315A582800077328B /* ChatRoomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatRoomViewController.h; sourceTree = ""; }; + D3F795D415A582800077328B /* ChatRoomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChatRoomViewController.m; sourceTree = ""; }; + D3F795D515A582800077328B /* ChatRoomViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChatRoomViewController.xib; sourceTree = ""; }; + D3F795DB15A5831C0077328B /* chat_back_default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_back_default.png; path = Resources/chat_back_default.png; sourceTree = ""; }; + D3F795DC15A5831C0077328B /* chat_back_over.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_back_over.png; path = Resources/chat_back_over.png; sourceTree = ""; }; D3F83EE91582021700336684 /* InCallViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InCallViewController.h; sourceTree = ""; }; D3F83EEA1582021700336684 /* InCallViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InCallViewController.m; sourceTree = ""; }; D3F83EEB1582021700336684 /* InCallViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InCallViewController.xib; sourceTree = ""; }; @@ -1233,6 +1277,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D32B6E2F15A5C0AC0033019F /* libsqlite3.dylib in Frameworks */, D37DC7181594AF3400B2A5EB /* MessageUI.framework in Frameworks */, 340751971506459A00B89C47 /* CoreTelephony.framework in Frameworks */, 226CDADF14E2D0B800513B67 /* libbcg729.a in Frameworks */, @@ -1331,8 +1376,14 @@ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( + D32B6E3515A5C2200033019F /* Model */, 340751E4150E4D0200B89C47 /* CallDelegate.h */, 2211DBBB14769C8200DEE054 /* CallDelegate.m */, + D32B6E2715A5BC430033019F /* ChatRoomTableViewController.h */, + D32B6E2815A5BC430033019F /* ChatRoomTableViewController.m */, + D3F795D315A582800077328B /* ChatRoomViewController.h */, + D3F795D415A582800077328B /* ChatRoomViewController.m */, + D3F795D515A582800077328B /* ChatRoomViewController.xib */, D3EA540B1598528B0037DC6B /* ChatTableViewController.h */, D3EA540C1598528B0037DC6B /* ChatTableViewController.m */, D35E7594159460560066B1C1 /* ChatViewController.h */, @@ -1747,6 +1798,7 @@ 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { isa = PBXGroup; children = ( + D32B6E2E15A5C0AC0033019F /* libsqlite3.dylib */, 2258633C11410BAC00C5A737 /* README */, 22276E8013C73D3100210156 /* libavcodec.a */, 22276E8113C73D3100210156 /* libavutil.a */, @@ -1867,11 +1919,19 @@ D36C43CD158F2F370048BA40 /* cell_conference.png */, D3EA5401159852080037DC6B /* chat_add_default.png */, D3EA5402159852080037DC6B /* chat_add_over.png */, + D3F795DB15A5831C0077328B /* chat_back_default.png */, + D3F795DC15A5831C0077328B /* chat_back_over.png */, D38327F11580FE3A00FA0D23 /* chat_default.png */, D3EA53FF159852080037DC6B /* chat_edit_default.png */, D3EA5400159852080037DC6B /* chat_edit_over.png */, + D3B9A3DA15A58C440096EA4E /* chat_field.png */, + D3B9A3DB15A58C440096EA4E /* chat_ok_default.png */, + D3B9A3DC15A58C440096EA4E /* chat_ok_over.png */, D38327FF158100E400FA0D23 /* chat_over.png */, D38327F21580FE3A00FA0D23 /* chat_selected.png */, + D3B9A3DD15A58C440096EA4E /* chat_send_default.png */, + D32B6E2315A5B2020033019F /* chat_send_disabled.png */, + D3B9A3DE15A58C450096EA4E /* chat_send_over.png */, D31AAF61159B5B6E002C6B02 /* conference_default.png */, D31AAF62159B5B6E002C6B02 /* conference_over.png */, D354980E15875608000081D8 /* contacts_add_default.png */, @@ -1883,6 +1943,7 @@ D354980415875534000081D8 /* contacts_linphone_selected.png */, D38327FC158100E400FA0D23 /* contacts_over.png */, D38327EC1580FE3A00FA0D23 /* contacts_selected.png */, + D32B6E2B15A5C0800033019F /* database.sqlite */, D3F83F761582253100336684 /* decline_default.png */, D3F83F771582253100336684 /* decline_over.png */, D3ED3E441585FB8C006C0DE4 /* dialer_address_background.png */, @@ -2029,6 +2090,15 @@ name = Utils; sourceTree = ""; }; + D32B6E3515A5C2200033019F /* Model */ = { + isa = PBXGroup; + children = ( + D32B6E3615A5C2430033019F /* ChatModel.h */, + D32B6E3715A5C2430033019F /* ChatModel.m */, + ); + name = Model; + sourceTree = ""; + }; D37DC6C31594AE5600B2A5EB /* InAppSettingsKit */ = { isa = PBXGroup; children = ( @@ -2399,6 +2469,16 @@ D350F22C15A43D3400149E54 /* setup_welcome_logo.png in Resources */, D35406F715A47E9E007E7E81 /* button_background_default.png in Resources */, D35406F915A47E9E007E7E81 /* button_background_over.png in Resources */, + D3F795D815A582810077328B /* ChatRoomViewController.xib in Resources */, + D3F795DD15A5831C0077328B /* chat_back_default.png in Resources */, + D3F795DF15A5831C0077328B /* chat_back_over.png in Resources */, + D3B9A3DF15A58C450096EA4E /* chat_field.png in Resources */, + D3B9A3E115A58C450096EA4E /* chat_ok_default.png in Resources */, + D3B9A3E315A58C450096EA4E /* chat_ok_over.png in Resources */, + D3B9A3E515A58C450096EA4E /* chat_send_default.png in Resources */, + D3B9A3E715A58C450096EA4E /* chat_send_over.png in Resources */, + D32B6E2415A5B2020033019F /* chat_send_disabled.png in Resources */, + D32B6E2C15A5C0800033019F /* database.sqlite in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2599,6 +2679,16 @@ D350F22D15A43D3400149E54 /* setup_welcome_logo.png in Resources */, D35406F815A47E9E007E7E81 /* button_background_default.png in Resources */, D35406FA15A47E9E007E7E81 /* button_background_over.png in Resources */, + D3F795D915A582810077328B /* ChatRoomViewController.xib in Resources */, + D3F795DE15A5831C0077328B /* chat_back_default.png in Resources */, + D3F795E015A5831C0077328B /* chat_back_over.png in Resources */, + D3B9A3E015A58C450096EA4E /* chat_field.png in Resources */, + D3B9A3E215A58C450096EA4E /* chat_ok_default.png in Resources */, + D3B9A3E415A58C450096EA4E /* chat_ok_over.png in Resources */, + D3B9A3E615A58C450096EA4E /* chat_send_default.png in Resources */, + D3B9A3E815A58C450096EA4E /* chat_send_over.png in Resources */, + D32B6E2515A5B2020033019F /* chat_send_disabled.png in Resources */, + D32B6E2D15A5C0800033019F /* database.sqlite in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2676,6 +2766,9 @@ D32B9DFC15A2F131000B6DEC /* FastAddressBook.m in Sources */, D3196D3E15A32BD8007FEEBA /* UITransferButton.m in Sources */, D350F20E15A43BB100149E54 /* WizardViewController.m in Sources */, + D3F795D615A582810077328B /* ChatRoomViewController.m in Sources */, + D32B6E2915A5BC440033019F /* ChatRoomTableViewController.m in Sources */, + D32B6E3815A5C2430033019F /* ChatModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2750,6 +2843,9 @@ D32B9DFD15A2F131000B6DEC /* FastAddressBook.m in Sources */, D3196D3F15A32BD8007FEEBA /* UITransferButton.m in Sources */, D350F20F15A43BB100149E54 /* WizardViewController.m in Sources */, + D3F795D715A582810077328B /* ChatRoomViewController.m in Sources */, + D32B6E2A15A5BC440033019F /* ChatRoomTableViewController.m in Sources */, + D32B6E3915A5C2430033019F /* ChatModel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };