Merge remote-tracking branch 'origin/dev_sendmsg'

This commit is contained in:
Gautier Pelloux-Prayer 2015-06-09 17:20:43 +02:00
commit 6637fc2127
15 changed files with 702 additions and 283 deletions

View file

@ -23,7 +23,7 @@
@protocol ChatRoomDelegate <NSObject>
- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo;
- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg;
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url;
- (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url;

View file

@ -29,7 +29,7 @@
#include "linphone/linphonecore.h"
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ImageSharingDelegate, ChatRoomDelegate> {
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatRoomDelegate, LinphoneChatContentTransferDelegate> {
LinphoneChatRoom *chatRoom;
ImageSharing *imageSharing;
OrderedDictionary *imageQualities;

View file

@ -21,12 +21,20 @@
#import "PhoneMainView.h"
#import "DTActionSheet.h"
#import "UILinphone.h"
//#import "UIAlertView+Blocks.h"
#import "DTAlertView.h"
#import <NinePatch.h>
#import <MobileCoreServices/UTCoreTypes.h>
#import "Utils.h"
@implementation ChatRoomViewController
@implementation ChatRoomViewController {
/* Message transfer transient storage */
NSData* upload_data;
size_t upload_bytes_sent;
NSMutableData* download_data;
}
@synthesize tableController;
@synthesize sendButton;
@ -64,6 +72,10 @@
[NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil),
[NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil];
self->composingVisible = TRUE;
self->upload_data = nil;
self->upload_bytes_sent = 0;
self->download_data = nil;
}
return self;
}
@ -173,8 +185,8 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(imageSharing) {
[imageSharing cancel];
if(upload_data || download_data ) {
// TODO: when the API permits it, we should cancel the transfer.
}
[messageField resignFirstResponder];
@ -211,7 +223,6 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
-(void)didReceiveMemoryWarning {
@ -317,34 +328,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
}
- (void)saveAndSend:(UIImage*)image url:(NSURL*)url {
if(url == nil) {
[waitView setHidden:FALSE];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[LinphoneManager instance].photoLibrary
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
[waitView setHidden:TRUE];
if (error) {
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
return;
}
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
[self chatRoomStartImageUpload:image url:assetURL];
});
}];
});
} else {
[self chatRoomStartImageUpload:image url:url];
}
[self chatRoomStartImageUpload:image url:url];
}
- (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url {
@ -498,8 +482,20 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark - Action Functions
- (IBAction)onBackClick:(id)event {
[self.tableController setChatRoom:NULL];
[[PhoneMainView instance] popCurrentView];
if( upload_data != nil || download_data != nil ){
DTAlertView *alertView = [[DTAlertView alloc] initWithTitle:NSLocalizedString(@"Cancel transfer?", nil)
message:NSLocalizedString(@"You have a transfer in progress, leaving this view will cancel it. Are you sure?", nil)];
[alertView addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil)
block:nil];
[alertView addButtonWithTitle:NSLocalizedString(@"Yes", nil)
block:^{
[self.tableController setChatRoom:NULL];
[[PhoneMainView instance] popCurrentView];
}];
} else {
[self.tableController setChatRoom:NULL];
[[PhoneMainView instance] popCurrentView];
}
}
- (IBAction)onEditClick:(id)event {
@ -586,20 +582,48 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark ChatRoomDelegate
- (BOOL)chatRoomStartImageDownload:(NSURL*)url userInfo:(id)userInfo {
if(imageSharing == nil) {
imageSharing = [ImageSharing newImageSharingDownload:url delegate:self userInfo:userInfo];
- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg {
if(self->download_data == nil) {
const char* url = linphone_chat_message_get_external_body_url(msg);
LOGI(@"Content to download: %s", url);
if( url == nil ) return FALSE;
download_data = [[NSMutableData alloc] init];
linphone_chat_message_set_user_data(msg, (void*)CFBridgingRetain(self));
linphone_chat_message_start_file_download(msg,NULL,NULL);
[messageView setHidden:TRUE];
[transferView setHidden:FALSE];
return TRUE;
}
return FALSE;
[transferView setHidden:FALSE];
return TRUE;
}
return FALSE;
}
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{
if(imageSharing == nil) {
NSString *urlString = [[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"];
imageSharing = [ImageSharing newImageSharingUpload:[NSURL URLWithString:urlString] image:image delegate:self userInfo:url];
if( self->upload_data == nil) {
LinphoneContent* content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom));
self->upload_data = UIImageJPEGRepresentation(image, 1.0);
linphone_content_set_type(content, "image");
linphone_content_set_subtype(content, "jpeg");
linphone_content_set_name(content, [[NSString stringWithFormat:@"%li-%f.jpg", (long)[image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]);
linphone_content_set_size(content, [self->upload_data length]);
LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, content);
linphone_chat_message_set_user_data(message, (void*)CFBridgingRetain(self));
if ( url ) {
// internal url is saved in the appdata for display and later save
[LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message];
}
// TODO: in the user data, we should maybe put a standalone delegate alloced and retained, instead of self.
// This will make sure that when receiving a memory alert or go to another view, we still send the message
linphone_chat_room_send_message2(chatRoom, message, message_status, (void*)CFBridgingRetain(self));
[tableController addChatEntry:linphone_chat_message_ref(message)];
[tableController scrollToBottom:true];
[messageView setHidden:TRUE];
[transferView setHidden:FALSE];
return TRUE;
@ -613,75 +637,12 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
#pragma mark ImageSharingDelegate
- (void)imageSharingProgress:(ImageSharing*)aimageSharing progress:(float)progress {
[imageTransferProgressBar setProgress:progress];
}
- (void)imageSharingAborted:(ImageSharing*)aimageSharing {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
imageSharing = nil;
}
- (void)imageSharingError:(ImageSharing*)aimageSharing error:(NSError *)error {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
NSString *url = [aimageSharing.connection.currentRequest.URL absoluteString];
if (aimageSharing.upload) {
LOGE(@"Cannot upload file to server [%@] because [%@]", url, [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot transfer file to remote contact", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
} else {
LOGE(@"Cannot download file from [%@] because [%@]", url, [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot transfer file from remote contact", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Continue", nil)
otherButtonTitles:nil, nil];
[errorAlert show];
}
imageSharing = nil;
}
- (void)imageSharingUploadDone:(ImageSharing*)aimageSharing url:(NSURL*)url{
[self sendMessage:nil withExterlBodyUrl:url withInternalURL:[aimageSharing userInfo] ];
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
imageSharing = nil;
}
- (void)imageSharingDownloadDone:(ImageSharing*)aimageSharing image:(UIImage *)image {
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
__block LinphoneChatMessage *chat = (LinphoneChatMessage *)[(NSValue*)[imageSharing userInfo] pointerValue];
[[LinphoneManager instance].photoLibrary writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
return;
}
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:chat];
[tableController updateChatEntry:chat];
}];
imageSharing = nil;
}
#pragma mark ImagePickerDelegate
- (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info {
@ -698,6 +659,93 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
[self chooseImageQuality:image url:url];
}
#pragma mark - LinphoneChatContentTransferDelegate
- (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent {
[imageTransferProgressBar setProgress:percent/100.0f];
}
- (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size {
if( self->upload_data ){
size_t to_send = *size;
size_t remaining = [upload_data length] - self->upload_bytes_sent;
LOGI(@"Asking %ld bytes, sent %ld of %d, %ld remaining", to_send, self->upload_bytes_sent, [upload_data length], remaining);
if( remaining < to_send ) to_send = remaining;
@try {
[upload_data getBytes:(void*)buffer range:NSMakeRange(upload_bytes_sent, to_send)];
upload_bytes_sent += to_send;
*size = to_send;
}
@catch (NSException *exception) {
LOGE(@"Exception: %@", exception);
}
if( to_send == 0 || upload_bytes_sent == [upload_data length] ){
LOGI(@"Upload finished, cleanup..");
upload_data = nil;
upload_bytes_sent = 0;
// update UI
dispatch_async(dispatch_get_main_queue(), ^{
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
});
}
} else {
LOGE(@"Error: no upload data in progress!");
}
}
- (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size {
if( download_data ){
LOGI(@"Receiving data for %s : %zu bytes, already got %d of %zu", linphone_content_get_name(content), size, [download_data length], linphone_content_get_size(content));
if( size != 0 ){
[download_data appendBytes:buffer length:size];
}
if( size == 0 && [download_data length] == linphone_content_get_size(content)){
LOGI(@"Transfer is finished, save image and update chat");
dispatch_async(dispatch_get_main_queue(), ^{
//we're finished, save the image and update the message
[messageView setHidden:FALSE];
[transferView setHidden:TRUE];
UIImage* image = [UIImage imageWithData:download_data];
download_data = nil;
[[LinphoneManager instance].photoLibrary
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
UIAlertView* errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transfer error", nil)
message:NSLocalizedString(@"Cannot write image to photo library", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Ok",nil)
otherButtonTitles:nil ,nil];
[errorAlert show];
return;
}
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:msg];
[tableController updateChatEntry:msg];
}];
});
}
}
}
#pragma mark - Keyboard Event Functions

View file

@ -369,7 +369,6 @@ static UICompositeViewDescription *compositeDescription = nil;
char* lAddress = linphone_address_as_string_uri_only(addr);
if(lAddress == NULL)
return;
// Go to ChatRoom view
[[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]];
ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController);

View file

@ -86,7 +86,6 @@
- (void)uploadImageTo:(NSURL*)url image:(UIImage*)image {
LOGI(@"downloading [%@]", [url absoluteString]);
// setting up the request object now
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];

View file

@ -98,6 +98,14 @@ struct NetworkReachabilityContext {
};
@end
@protocol LinphoneChatContentTransferDelegate <NSObject>
-(void)onProgressReport:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content percent:(int)percent;
-(void)onDataRequested:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(char*)buffer withSize:(size_t*)size;
-(void)onDataReceived:(LinphoneChatMessage*)msg forContent:(const LinphoneContent*)content buffer:(const char*)buffer withSize:(size_t)size;
@end
typedef struct _LinphoneManagerSounds {
SystemSoundID vibrate;
} LinphoneManagerSounds;

View file

@ -145,10 +145,10 @@ struct codec_name_pref_table codec_pref_table[]={
{ "mp4v-es", 90000, "mp4v-es_preference"},
{ "h264", 90000, "h264_preference"},
{ "vp8", 90000, "vp8_preference"},
{ "mpeg4-generic", 16000, "aaceld_16k_preference"},
{ "mpeg4-generic", 22050, "aaceld_22k_preference"},
{ "mpeg4-generic", 32000, "aaceld_32k_preference"},
{ "mpeg4-generic", 44100, "aaceld_44k_preference"},
{ "mpeg4-generic", 16000, "aaceld_16k_preference"},
{ "mpeg4-generic", 22050, "aaceld_22k_preference"},
{ "mpeg4-generic", 32000, "aaceld_32k_preference"},
{ "mpeg4-generic", 44100, "aaceld_44k_preference"},
{ "mpeg4-generic", 48000, "aaceld_48k_preference"},
{ "opus", 48000, "opus_preference"},
{ NULL,0,Nil }
@ -194,9 +194,9 @@ struct codec_name_pref_table codec_pref_table[]={
}
+ (BOOL)isRunningTests {
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
NSString *injectBundle = environment[@"XCInjectBundle"];
return [[injectBundle pathExtension] isEqualToString:@"xctest"];
NSDictionary *environment = [[NSProcessInfo processInfo] environment];
NSString *injectBundle = environment[@"XCInjectBundle"];
return [[injectBundle pathExtension] isEqualToString:@"xctest"];
}
+ (BOOL)isNotIphone3G
@ -244,12 +244,12 @@ struct codec_name_pref_table codec_pref_table[]={
#endif
+ (BOOL)langageDirectionIsRTL {
static NSLocaleLanguageDirection dir = NSLocaleLanguageDirectionLeftToRight;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dir = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
});
return dir == NSLocaleLanguageDirectionRightToLeft;
static NSLocaleLanguageDirection dir = NSLocaleLanguageDirectionLeftToRight;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dir = [NSLocale characterDirectionForLanguage:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]];
});
return dir == NSLocaleLanguageDirectionRightToLeft;
}
#pragma mark - Lifecycle Functions
@ -262,12 +262,12 @@ struct codec_name_pref_table codec_pref_table[]={
LOGE(@"cannot register route change handler [%ld]",lStatus);
}
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil];
NSString *path = [[NSBundle mainBundle] pathForResource:@"msg" ofType:@"wav"];
self.messagePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:path] error:nil];
sounds.vibrate = kSystemSoundID_Vibrate;
sounds.vibrate = kSystemSoundID_Vibrate;
logs = [[NSMutableArray alloc] init];
logs = [[NSMutableArray alloc] init];
database = NULL;
speakerEnabled = FALSE;
bluetoothEnabled = FALSE;
@ -543,9 +543,9 @@ static void linphone_iphone_log(struct _LinphoneCore * lc, const char * message)
- (void)displayStatus:(NSString*) message {
// Post event
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneDisplayStatusUpdate
object:self
userInfo:@{@"message":message}];
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneDisplayStatusUpdate
object:self
userInfo:@{@"message":message}];
}
@ -639,14 +639,14 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char
data->notification = [[UILocalNotification alloc] init];
if (data->notification) {
// iOS8 doesn't need the timer trick for the local notification.
if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){
data->notification.soundName = @"ring.caf";
data->notification.category = @"incoming_call";
} else {
data->notification.soundName = @"shortring.caf";
data->timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(localNotifContinue:) userInfo:data->notification repeats:TRUE];
}
// iOS8 doesn't need the timer trick for the local notification.
if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){
data->notification.soundName = @"ring.caf";
data->notification.category = @"incoming_call";
} else {
data->notification.soundName = @"shortring.caf";
data->timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:@selector(localNotifContinue:) userInfo:data->notification repeats:TRUE];
}
data->notification.repeatInterval = 0;
@ -664,9 +664,9 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char
incallBgTask=0;
}];
if( data->timer ){
[[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes];
}
if( data->timer ){
[[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes];
}
}
}
@ -740,9 +740,9 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char
[self setupGSMInteraction];
}
// Post event
NSDictionary* dict = @{@"call": [NSValue valueWithPointer:call],
@"state": [NSNumber numberWithInt:state],
@"message":[NSString stringWithUTF8String:message]};
NSDictionary* dict = @{@"call": [NSValue valueWithPointer:call],
@"state": [NSNumber numberWithInt:state],
@"message":[NSString stringWithUTF8String:message]};
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneCallUpdate object:self userInfo:dict];
}
@ -845,12 +845,12 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo
silentPushCompletion(UIBackgroundFetchResultNewData);
silentPushCompletion = nil;
}
const LinphoneAddress* remoteAddress = linphone_chat_message_get_from_address(msg);
char* c_address = linphone_address_as_string_uri_only(remoteAddress);
NSString* address = [NSString stringWithUTF8String:c_address];
NSString* remote_uri = [NSString stringWithUTF8String:c_address];
const char* call_id = linphone_chat_message_get_custom_header(msg, "Call-ID");
NSString* callID = [NSString stringWithUTF8String:call_id];
const LinphoneAddress* remoteAddress = linphone_chat_message_get_from_address(msg);
char* c_address = linphone_address_as_string_uri_only(remoteAddress);
NSString* address = [NSString stringWithUTF8String:c_address];
NSString* remote_uri = [NSString stringWithUTF8String:c_address];
const char* call_id = linphone_chat_message_get_custom_header(msg, "Call-ID");
NSString* callID = [NSString stringWithUTF8String:call_id];
ms_free(c_address);
@ -874,9 +874,9 @@ static void linphone_iphone_registration_state(LinphoneCore *lc, LinphoneProxyCo
UILocalNotification* notif = [[UILocalNotification alloc] init];
if (notif) {
notif.repeatInterval = 0;
if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){
notif.category = @"incoming_msg";
}
if( [[UIDevice currentDevice].systemVersion floatValue] >= 8){
notif.category = @"incoming_msg";
}
notif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"IM_MSG",nil), address];
notif.alertAction = NSLocalizedString(@"Show", nil);
notif.soundName = @"msg.caf";
@ -915,6 +915,29 @@ static void linphone_iphone_notify_received(LinphoneCore *lc, LinphoneEvent *lev
[(__bridge LinphoneManager*)linphone_core_get_user_data(lc) onNotifyReceived:lc event:lev notifyEvent:notified_event content:body];
}
#pragma mark - FileTransfer functions
static void linphone_iphone_file_transfer_recv(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, const char* buff, size_t size) {
id <LinphoneChatContentTransferDelegate> delegate = (__bridge id<LinphoneChatContentTransferDelegate>)linphone_chat_message_get_user_data(message);
LOGI(@"Transfer of %s, incoming data (%d bytes)", linphone_content_get_name(content), size);
[delegate onDataReceived:message forContent:content buffer:buff withSize:size];
}
static void linphone_iphone_file_transfer_send(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, char* buff, size_t* size){
id <LinphoneChatContentTransferDelegate> delegate = (__bridge id<LinphoneChatContentTransferDelegate>)linphone_chat_message_get_user_data(message);
LOGI(@"Transfer of %s, requesting data (%d bytes)", linphone_content_get_name(content), *size);
[delegate onDataRequested:message forContent:content buffer:buff withSize:size];
}
static void linphone_iphone_file_transfer_progress(LinphoneCore *lc, LinphoneChatMessage *message, const LinphoneContent* content, size_t offset, size_t total){
id <LinphoneChatContentTransferDelegate> delegate = (__bridge id<LinphoneChatContentTransferDelegate>)linphone_chat_message_get_user_data(message);
float progress = offset*100.f/total;
LOGI(@"Progress of transfer %s: %d%%", linphone_content_get_name(content), progress);
[delegate onProgressReport:message forContent:content percent:progress];
}
#pragma mark - Message composition start
- (void)onMessageComposeReceived:(LinphoneCore*)core forRoom:(LinphoneChatRoom*)room {
@ -936,58 +959,58 @@ static void linphone_iphone_is_composing_received(LinphoneCore *lc, LinphoneChat
}
+ (void)kickOffNetworkConnection {
static BOOL in_progress = FALSE;
if( in_progress ){
LOGW(@"Connection kickoff already in progress");
return;
}
in_progress = TRUE;
static BOOL in_progress = FALSE;
if( in_progress ){
LOGW(@"Connection kickoff already in progress");
return;
}
in_progress = TRUE;
/* start a new thread to avoid blocking the main ui in case of peer host failure */
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static int sleep_us = 10000;
static int timeout_s = 5;
BOOL timeout_reached = FALSE;
int loop = 0;
static int sleep_us = 10000;
static int timeout_s = 5;
BOOL timeout_reached = FALSE;
int loop = 0;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.0.200"/*"linphone.org"*/, 15000, nil, &writeStream);
BOOL res = CFWriteStreamOpen (writeStream);
const char* buff="hello";
time_t start = time(NULL);
time_t loop_time;
time_t start = time(NULL);
time_t loop_time;
if( res == FALSE ){
LOGI(@"Could not open write stream, backing off");
CFRelease(writeStream);
in_progress = FALSE;
return;
}
if( res == FALSE ){
LOGI(@"Could not open write stream, backing off");
CFRelease(writeStream);
in_progress = FALSE;
return;
}
// check stream status and handle timeout
CFStreamStatus status = CFWriteStreamGetStatus(writeStream);
while (status != kCFStreamStatusOpen && status != kCFStreamStatusError ) {
usleep(sleep_us);
status = CFWriteStreamGetStatus(writeStream);
loop_time = time(NULL);
if( loop_time - start >= timeout_s){
timeout_reached = TRUE;
break;
}
loop++;
}
// check stream status and handle timeout
CFStreamStatus status = CFWriteStreamGetStatus(writeStream);
while (status != kCFStreamStatusOpen && status != kCFStreamStatusError ) {
usleep(sleep_us);
status = CFWriteStreamGetStatus(writeStream);
loop_time = time(NULL);
if( loop_time - start >= timeout_s){
timeout_reached = TRUE;
break;
}
loop++;
}
if (status == kCFStreamStatusOpen ) {
CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff));
} else if( !timeout_reached ){
CFErrorRef error = CFWriteStreamCopyError(writeStream);
LOGD(@"CFStreamError: %@", error);
CFRelease(error);
} else if( timeout_reached ){
LOGI(@"CFStream timeout reached");
}
if (status == kCFStreamStatusOpen ) {
CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff));
} else if( !timeout_reached ){
CFErrorRef error = CFWriteStreamCopyError(writeStream);
LOGD(@"CFStreamError: %@", error);
CFRelease(error);
} else if( timeout_reached ){
LOGI(@"CFStream timeout reached");
}
CFWriteStreamClose (writeStream);
CFRelease(writeStream);
in_progress = FALSE;
in_progress = FALSE;
});
}
@ -1185,7 +1208,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach
}
}
#pragma mark -
#pragma mark - VTable
static LinphoneCoreVTable linphonec_vtable = {
.show =NULL,
@ -1205,9 +1228,15 @@ static LinphoneCoreVTable linphonec_vtable = {
.is_composing_received = linphone_iphone_is_composing_received,
.configuring_status = linphone_iphone_configuring_status_changed,
.global_state_changed = linphone_iphone_global_state_changed,
.notify_received = linphone_iphone_notify_received
.notify_received = linphone_iphone_notify_received,
.file_transfer_recv = linphone_iphone_file_transfer_recv,
.file_transfer_send = linphone_iphone_file_transfer_send,
.file_transfer_progress_indication = linphone_iphone_file_transfer_progress
};
#pragma mark -
//scheduling loop
- (void)iterate {
linphone_core_iterate(theLinphoneCore);
@ -1300,6 +1329,11 @@ static LinphoneCoreVTable linphonec_vtable = {
linphone_core_set_static_picture(theLinphoneCore, imagePath);
}
NSString *urlString = [self lpConfigStringForKey:@"sharing_server_preference"];
if( urlString ){
linphone_core_set_file_transfer_server(theLinphoneCore, [urlString UTF8String]);
}
/*DETECT cameras*/
frontCamId= backCamId=nil;
char** camlist = (char**)linphone_core_get_video_devices(theLinphoneCore);
@ -1394,24 +1428,24 @@ static BOOL libStarted = FALSE;
connectivity=none;
ms_init(); // Need to initialize mediastreamer2 before loading the plugins
ms_init(); // Need to initialize mediastreamer2 before loading the plugins
libmsilbc_init();
libmsilbc_init();
#if defined (HAVE_SILK)
libmssilk_init();
libmssilk_init();
#endif
#ifdef HAVE_AMR
libmsamr_init(); //load amr plugin if present from the liblinphone sdk
libmsamr_init(); //load amr plugin if present from the liblinphone sdk
#endif
#ifdef HAVE_X264
libmsx264_init(); //load x264 plugin if present from the liblinphone sdk
libmsx264_init(); //load x264 plugin if present from the liblinphone sdk
#endif
#ifdef HAVE_OPENH264
libmsopenh264_init(); //load openh264 plugin if present from the liblinphone sdk
libmsopenh264_init(); //load openh264 plugin if present from the liblinphone sdk
#endif
#if HAVE_G729
libmsbcg729_init(); // load g729 plugin
libmsbcg729_init(); // load g729 plugin
#endif
linphone_core_set_log_collection_path([[LinphoneManager cacheDirectory] UTF8String]);
@ -1490,39 +1524,39 @@ static int comp_call_id(const LinphoneCall* call , const char *callid) {
}
- (void)cancelLocalNotifTimerForCallId:(NSString*)callid {
//first, make sure this callid is not already involved in a call
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]);
if (call != NULL) {
LinphoneCallAppData* data = (__bridge LinphoneCallAppData *)(linphone_call_get_user_data((LinphoneCall*)call->data));
if ( data->timer )
[data->timer invalidate];
data->timer = nil;
return;
}
//first, make sure this callid is not already involved in a call
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]);
if (call != NULL) {
LinphoneCallAppData* data = (__bridge LinphoneCallAppData *)(linphone_call_get_user_data((LinphoneCall*)call->data));
if ( data->timer )
[data->timer invalidate];
data->timer = nil;
return;
}
}
- (void)acceptCallForCallId:(NSString*)callid {
//first, make sure this callid is not already involved in a call
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]);
if (call != NULL) {
[self acceptCall:(LinphoneCall*)call->data];
return;
};
//first, make sure this callid is not already involved in a call
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
MSList* call = ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String]);
if (call != NULL) {
[self acceptCall:(LinphoneCall*)call->data];
return;
};
}
- (void)addPushCallId:(NSString*) callid {
//first, make sure this callid is not already involved in a call
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
if (ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String])) {
LOGW(@"Call id [%@] already handled",callid);
return;
};
if ([pushCallIDs count] > 10 /*max number of pending notif*/)
[pushCallIDs removeObjectAtIndex:0];
MSList* calls = (MSList*)linphone_core_get_calls(theLinphoneCore);
if (ms_list_find_custom(calls, (MSCompareFunc)comp_call_id, [callid UTF8String])) {
LOGW(@"Call id [%@] already handled",callid);
return;
};
if ([pushCallIDs count] > 10 /*max number of pending notif*/)
[pushCallIDs removeObjectAtIndex:0];
[pushCallIDs addObject:callid];
[pushCallIDs addObject:callid];
}
- (BOOL)popPushCallID:(NSString*) callId {
@ -1542,11 +1576,11 @@ static int comp_call_id(const LinphoneCall* call , const char *callid) {
}
- (void)playMessageSound {
BOOL success = [self.messagePlayer play];
if( !success ){
LOGE(@"Could not play the message sound");
}
AudioServicesPlaySystemSound([LinphoneManager instance].sounds.vibrate);
BOOL success = [self.messagePlayer play];
if( !success ){
LOGE(@"Could not play the message sound");
}
AudioServicesPlaySystemSound([LinphoneManager instance].sounds.vibrate);
}
static int comp_call_state_paused (const LinphoneCall* call, const void* param) {
@ -1559,7 +1593,7 @@ static int comp_call_state_paused (const LinphoneCall* call, const void* param)
[[UIApplication sharedApplication] endBackgroundTask:pausedCallBgTask];
}];
LOGI(@"Long running task started, remaining [%g s] because at least one call is paused"
,[[UIApplication sharedApplication] backgroundTimeRemaining]);
,[[UIApplication sharedApplication] backgroundTimeRemaining]);
}
- (BOOL)enterBackgroundMode {
LinphoneProxyConfig* proxyCfg;
@ -1864,18 +1898,18 @@ static void audioRouteChangeListenerCallback (
}
LinphoneCall* call=NULL;
BOOL addressIsASCII = [address canBeConvertedToEncoding:[NSString defaultCStringEncoding]];
BOOL addressIsASCII = [address canBeConvertedToEncoding:[NSString defaultCStringEncoding]];
if ([address length] == 0) return; //just return
if( !addressIsASCII ){
UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address",nil)
message:NSLocalizedString(@"The address should only contain ASCII data",nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Continue",nil)
otherButtonTitles:nil];
[error show];
if( !addressIsASCII ){
UIAlertView* error = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Invalid SIP address",nil)
message:NSLocalizedString(@"The address should only contain ASCII data",nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"Continue",nil)
otherButtonTitles:nil];
[error show];
}
}
LinphoneAddress* linphoneAddress = linphone_core_interpret_url(theLinphoneCore, [address cStringUsingEncoding:[NSString defaultCStringEncoding]]);
if (linphoneAddress) {
@ -1901,7 +1935,7 @@ static void audioRouteChangeListenerCallback (
otherButtonTitles:nil];
[error show];
}
}
if (call) {
@ -1929,16 +1963,16 @@ static void audioRouteChangeListenerCallback (
pushNotificationToken = nil;
}
if(apushNotificationToken != nil) {
pushNotificationToken = apushNotificationToken;
}
LinphoneProxyConfig *cfg=nil;
linphone_core_get_default_proxy(theLinphoneCore, &cfg);
if (cfg ) {
linphone_proxy_config_edit(cfg);
[self configurePushTokenForProxyConfig: cfg];
linphone_proxy_config_done(cfg);
}
if(apushNotificationToken != nil) {
pushNotificationToken = apushNotificationToken;
}
LinphoneProxyConfig *cfg=nil;
linphone_core_get_default_proxy(theLinphoneCore, &cfg);
if (cfg ) {
linphone_proxy_config_edit(cfg);
[self configurePushTokenForProxyConfig: cfg];
linphone_proxy_config_done(cfg);
}
}
- (void)configurePushTokenForProxyConfig:(LinphoneProxyConfig*)proxyCfg{
@ -1956,10 +1990,10 @@ static void audioRouteChangeListenerCallback (
#else
#define APPMODE_SUFFIX @"prod"
#endif
NSString *params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString];
NSString *params = [NSString stringWithFormat:@"app-id=%@.%@;pn-type=apple;pn-tok=%@;pn-msg-str=IM_MSG;pn-call-str=IC_MSG;pn-call-snd=ring.caf;pn-msg-snd=msg.caf", [[NSBundle mainBundle] bundleIdentifier],APPMODE_SUFFIX,tokenString];
linphone_proxy_config_set_contact_uri_parameters(proxyCfg, [params UTF8String]);
linphone_proxy_config_set_contact_parameters(proxyCfg, NULL);
linphone_proxy_config_set_contact_uri_parameters(proxyCfg, [params UTF8String]);
linphone_proxy_config_set_contact_parameters(proxyCfg, NULL);
} else {
// no push token:
linphone_proxy_config_set_contact_uri_parameters(proxyCfg, NULL);
@ -1990,22 +2024,22 @@ static void audioRouteChangeListenerCallback (
if (! [[NSFileManager defaultManager] fileExistsAtPath:cachePath isDirectory:&isDir] && isDir == NO) {
[[NSFileManager defaultManager] createDirectoryAtPath:cachePath withIntermediateDirectories:NO attributes:nil error:&error];
}
return cachePath;
return cachePath;
}
+ (int)unreadMessageCount {
int count = 0;
MSList* rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]);
MSList* item = rooms;
while (item) {
LinphoneChatRoom* room = (LinphoneChatRoom*)item->data;
if( room ){
count += linphone_chat_room_get_unread_messages_count(room);
}
item = item->next;
}
int count = 0;
MSList* rooms = linphone_core_get_chat_rooms([LinphoneManager getLc]);
MSList* item = rooms;
while (item) {
LinphoneChatRoom* room = (LinphoneChatRoom*)item->data;
if( room ){
count += linphone_chat_room_get_unread_messages_count(room);
}
item = item->next;
}
return count;
return count;
}
+ (BOOL)copyFile:(NSString*)src destination:(NSString*)dst override:(BOOL)override {
@ -2038,16 +2072,16 @@ static void audioRouteChangeListenerCallback (
- (void)configureVbrCodecs{
PayloadType *pt;
int bitrate=lp_config_get_int(configDb,"audio","codec_bitrate_limit",kLinphoneAudioVbrCodecDefaultBitrate);/*default value is in linphonerc or linphonerc-factory*/
const MSList *audio_codecs = linphone_core_get_audio_codecs(theLinphoneCore);
const MSList* codec = audio_codecs;
while (codec) {
pt = codec->data;
if( linphone_core_payload_type_is_vbr(theLinphoneCore, pt) ) {
linphone_core_set_payload_type_bitrate(theLinphoneCore, pt, bitrate);
}
const MSList *audio_codecs = linphone_core_get_audio_codecs(theLinphoneCore);
const MSList* codec = audio_codecs;
while (codec) {
pt = codec->data;
if( linphone_core_payload_type_is_vbr(theLinphoneCore, pt) ) {
linphone_core_set_payload_type_bitrate(theLinphoneCore, pt, bitrate);
}
codec = codec->next;
}
codec = codec->next;
}
}
-(void)setLogsEnabled:(BOOL)enabled {

View file

@ -322,9 +322,7 @@ static UIFont *CELL_FONT = nil;
}
- (IBAction)onDownloadClick:(id)event {
NSURL* url = [NSURL URLWithString:[NSString stringWithUTF8String:linphone_chat_message_get_external_body_url(chat)]];
[chatRoomDelegate chatRoomStartImageDownload:url userInfo:[NSValue valueWithPointer:chat]];
[chatRoomDelegate chatRoomStartImageDownload:chat];
}
- (IBAction)onImageClick:(id)event {

View file

@ -105,6 +105,7 @@
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.tableView = nil;

View file

@ -0,0 +1,59 @@
//
// UIAlertView+Blocks.h
// UIAlertViewBlocks
//
// Created by Ryan Maxwell on 29/08/13.
//
// The MIT License (MIT)
//
// Copyright (c) 2013 Ryan Maxwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#import <UIKit/UIKit.h>
typedef void (^UIAlertViewBlock) (UIAlertView *alertView);
typedef void (^UIAlertViewCompletionBlock) (UIAlertView *alertView, NSInteger buttonIndex);
@interface UIAlertView (Blocks)
+ (instancetype)showWithTitle:(NSString *)title
message:(NSString *)message
style:(UIAlertViewStyle)style
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
tapBlock:(UIAlertViewCompletionBlock)tapBlock;
+ (instancetype)showWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
tapBlock:(UIAlertViewCompletionBlock)tapBlock;
@property (copy, nonatomic) UIAlertViewCompletionBlock tapBlock;
@property (copy, nonatomic) UIAlertViewCompletionBlock willDismissBlock;
@property (copy, nonatomic) UIAlertViewCompletionBlock didDismissBlock;
@property (copy, nonatomic) UIAlertViewBlock willPresentBlock;
@property (copy, nonatomic) UIAlertViewBlock didPresentBlock;
@property (copy, nonatomic) UIAlertViewBlock cancelBlock;
@property (copy, nonatomic) BOOL(^shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView);
@end

View file

@ -0,0 +1,264 @@
//
// UIAlertView+Blocks.m
// UIAlertViewBlocks
//
// Created by Ryan Maxwell on 29/08/13.
//
// The MIT License (MIT)
//
// Copyright (c) 2013 Ryan Maxwell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#import "UIAlertView+Blocks.h"
#import <objc/runtime.h>
static const void *UIAlertViewOriginalDelegateKey = &UIAlertViewOriginalDelegateKey;
static const void *UIAlertViewTapBlockKey = &UIAlertViewTapBlockKey;
static const void *UIAlertViewWillPresentBlockKey = &UIAlertViewWillPresentBlockKey;
static const void *UIAlertViewDidPresentBlockKey = &UIAlertViewDidPresentBlockKey;
static const void *UIAlertViewWillDismissBlockKey = &UIAlertViewWillDismissBlockKey;
static const void *UIAlertViewDidDismissBlockKey = &UIAlertViewDidDismissBlockKey;
static const void *UIAlertViewCancelBlockKey = &UIAlertViewCancelBlockKey;
static const void *UIAlertViewShouldEnableFirstOtherButtonBlockKey = &UIAlertViewShouldEnableFirstOtherButtonBlockKey;
@implementation UIAlertView (Blocks)
+ (instancetype)showWithTitle:(NSString *)title
message:(NSString *)message
style:(UIAlertViewStyle)style
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
tapBlock:(UIAlertViewCompletionBlock)tapBlock {
NSString *firstObject = otherButtonTitles.count ? otherButtonTitles[0] : nil;
UIAlertView *alertView = [[self alloc] initWithTitle:title
message:message
delegate:nil
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:firstObject, nil];
alertView.alertViewStyle = style;
if (otherButtonTitles.count > 1) {
for (NSString *buttonTitle in [otherButtonTitles subarrayWithRange:NSMakeRange(1, otherButtonTitles.count - 1)]) {
[alertView addButtonWithTitle:buttonTitle];
}
}
if (tapBlock) {
alertView.tapBlock = tapBlock;
}
[alertView show];
#if !__has_feature(objc_arc)
return [alertView autorelease];
#else
return alertView;
#endif
}
+ (instancetype)showWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
tapBlock:(UIAlertViewCompletionBlock)tapBlock {
return [self showWithTitle:title
message:message
style:UIAlertViewStyleDefault
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles
tapBlock:tapBlock];
}
#pragma mark -
- (void)_checkAlertViewDelegate {
if (self.delegate != (id<UIAlertViewDelegate>)self) {
objc_setAssociatedObject(self, UIAlertViewOriginalDelegateKey, self.delegate, OBJC_ASSOCIATION_ASSIGN);
self.delegate = (id<UIAlertViewDelegate>)self;
}
}
- (UIAlertViewCompletionBlock)tapBlock {
return objc_getAssociatedObject(self, UIAlertViewTapBlockKey);
}
- (void)setTapBlock:(UIAlertViewCompletionBlock)tapBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewTapBlockKey, tapBlock, OBJC_ASSOCIATION_COPY);
}
- (UIAlertViewCompletionBlock)willDismissBlock {
return objc_getAssociatedObject(self, UIAlertViewWillDismissBlockKey);
}
- (void)setWillDismissBlock:(UIAlertViewCompletionBlock)willDismissBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewWillDismissBlockKey, willDismissBlock, OBJC_ASSOCIATION_COPY);
}
- (UIAlertViewCompletionBlock)didDismissBlock {
return objc_getAssociatedObject(self, UIAlertViewDidDismissBlockKey);
}
- (void)setDidDismissBlock:(UIAlertViewCompletionBlock)didDismissBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewDidDismissBlockKey, didDismissBlock, OBJC_ASSOCIATION_COPY);
}
- (UIAlertViewBlock)willPresentBlock {
return objc_getAssociatedObject(self, UIAlertViewWillPresentBlockKey);
}
- (void)setWillPresentBlock:(UIAlertViewBlock)willPresentBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewWillPresentBlockKey, willPresentBlock, OBJC_ASSOCIATION_COPY);
}
- (UIAlertViewBlock)didPresentBlock {
return objc_getAssociatedObject(self, UIAlertViewDidPresentBlockKey);
}
- (void)setDidPresentBlock:(UIAlertViewBlock)didPresentBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewDidPresentBlockKey, didPresentBlock, OBJC_ASSOCIATION_COPY);
}
- (UIAlertViewBlock)cancelBlock {
return objc_getAssociatedObject(self, UIAlertViewCancelBlockKey);
}
- (void)setCancelBlock:(UIAlertViewBlock)cancelBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewCancelBlockKey, cancelBlock, OBJC_ASSOCIATION_COPY);
}
- (void)setShouldEnableFirstOtherButtonBlock:(BOOL(^)(UIAlertView *alertView))shouldEnableFirstOtherButtonBlock {
[self _checkAlertViewDelegate];
objc_setAssociatedObject(self, UIAlertViewShouldEnableFirstOtherButtonBlockKey, shouldEnableFirstOtherButtonBlock, OBJC_ASSOCIATION_COPY);
}
- (BOOL(^)(UIAlertView *alertView))shouldEnableFirstOtherButtonBlock {
return objc_getAssociatedObject(self, UIAlertViewShouldEnableFirstOtherButtonBlockKey);
}
#pragma mark - UIAlertViewDelegate
- (void)willPresentAlertView:(UIAlertView *)alertView {
UIAlertViewBlock block = alertView.willPresentBlock;
if (block) {
block(alertView);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(willPresentAlertView:)]) {
[originalDelegate willPresentAlertView:alertView];
}
}
- (void)didPresentAlertView:(UIAlertView *)alertView {
UIAlertViewBlock block = alertView.didPresentBlock;
if (block) {
block(alertView);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(didPresentAlertView:)]) {
[originalDelegate didPresentAlertView:alertView];
}
}
- (void)alertViewCancel:(UIAlertView *)alertView {
UIAlertViewBlock block = alertView.cancelBlock;
if (block) {
block(alertView);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertViewCancel:)]) {
[originalDelegate alertViewCancel:alertView];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
UIAlertViewCompletionBlock completion = alertView.tapBlock;
if (completion) {
completion(alertView, buttonIndex);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)]) {
[originalDelegate alertView:alertView clickedButtonAtIndex:buttonIndex];
}
}
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
UIAlertViewCompletionBlock completion = alertView.willDismissBlock;
if (completion) {
completion(alertView, buttonIndex);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)]) {
[originalDelegate alertView:alertView willDismissWithButtonIndex:buttonIndex];
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
UIAlertViewCompletionBlock completion = alertView.didDismissBlock;
if (completion) {
completion(alertView, buttonIndex);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)]) {
[originalDelegate alertView:alertView didDismissWithButtonIndex:buttonIndex];
}
}
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView {
BOOL(^shouldEnableFirstOtherButtonBlock)(UIAlertView *alertView) = alertView.shouldEnableFirstOtherButtonBlock;
if (shouldEnableFirstOtherButtonBlock) {
return shouldEnableFirstOtherButtonBlock(alertView);
}
id originalDelegate = objc_getAssociatedObject(self, UIAlertViewOriginalDelegateKey);
if (originalDelegate && [originalDelegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)]) {
return [originalDelegate alertViewShouldEnableFirstOtherButton:alertView];
}
return YES;
}
@end

View file

@ -37,6 +37,11 @@
<a href="http://www.tortuga22.com">http://www.tortuga22.com</a><br />
<em>Apache license</em></p>
<h3>Ryan Maxwell</h3>
<p>UIAlertview+Blocks</p>
<a href="https://github.com/ryanmaxwell/UIAlertView-Blocks">https://github.com/ryanmaxwell/UIAlertView-Blocks</a><br />
<em>MIT license</em>
<h3>OrderedDictionary</h3>
<p>Matt Gallagher<br />
<a href="http://cocoawithlove.com">http://cocoawithlove.com</a></p>

View file

@ -22,7 +22,7 @@
<section name="app">
<entry name="pushnotification_preference" overwrite="true">1</entry>
<entry name="sharing_server_preference" overwrite="true">https://www.linphone.org:444/upload.php</entry>
<entry name="sharing_server_preference" overwrite="true">https://www.linphone.org:444/lft.php</entry>
<entry name="ice_preference" overwrite="true">1</entry>
<entry name="stun_preference" overwrite="true">stun.linphone.org</entry>
<entry name="random_port_preference" overwrite="true">1</entry>

View file

@ -22,7 +22,7 @@
<section name="app">
<entry name="pushnotification_preference" overwrite="true">1</entry>
<entry name="sharing_server_preference" overwrite="true">https://www.linphone.org:444/upload.php</entry>
<entry name="sharing_server_preference" overwrite="true">https://www.linphone.org:444/lft.php</entry>
<entry name="ice_preference" overwrite="true">1</entry>
<entry name="stun_preference" overwrite="true">stun.linphone.org</entry>
<entry name="random_port_preference" overwrite="true">1</entry>

View file

@ -892,6 +892,7 @@
/* Begin PBXFileReference section */
045B5CB218D72E9A0088350C /* libbzrtp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbzrtp.a; path = "liblinphone-sdk/apple-darwin/lib/libbzrtp.a"; sourceTree = "<group>"; };
15017E6F1773578400784ACB /* libxml2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libxml2.a; path = "liblinphone-sdk/apple-darwin/lib/libxml2.a"; sourceTree = "<group>"; };
152F22331B15E83B008C0621 /* libilbcrfc3951.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbcrfc3951.a; path = "liblinphone-sdk/apple-darwin/lib/libilbcrfc3951.a"; sourceTree = "<group>"; };
152F22351B15E889008C0621 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
1560821E18EEF26100765332 /* libmsopenh264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsopenh264.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsopenh264.a"; sourceTree = "<group>"; };
@ -951,6 +952,7 @@
22276E8213C73D3100210156 /* libswscale.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libswscale.a; path = "liblinphone-sdk/apple-darwin/lib/libswscale.a"; sourceTree = "<group>"; };
22276E8613C73D8A00210156 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
22276E8813C73DC000210156 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
223148E31178A08200637D6A /* libilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libilbc.a; path = "liblinphone-sdk/apple-darwin/lib/libilbc.a"; sourceTree = "<group>"; };
223148E51178A09900637D6A /* libmsilbc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmsilbc.a; path = "liblinphone-sdk/apple-darwin/lib/mediastreamer/plugins/libmsilbc.a"; sourceTree = "<group>"; };
2234C8E715EE2F7F00E18E83 /* chat_message_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_delivered.png; path = Resources/chat_message_delivered.png; sourceTree = "<group>"; };
2234C8E815EE2F7F00E18E83 /* chat_message_not_delivered.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = chat_message_not_delivered.png; path = Resources/chat_message_not_delivered.png; sourceTree = "<group>"; };
@ -2287,6 +2289,7 @@
F03A9B9718C0DB6F00C4D7FE /* libc++.dylib */,
F0BB8C111936240300974404 /* libcunit.a */,
220FAD2910765B400068D98F /* libgsm.a */,
223148E31178A08200637D6A /* libilbc.a */,
2211DB911475562600DEE054 /* liblinphone.a */,
F0BB8C0F193623F200974404 /* liblinphonetester.a */,
22405EE916006F0700B92522 /* libmediastreamer_base.a */,
@ -2316,6 +2319,7 @@
D30BF33216A427BC00AF0026 /* libtunnel.a */,
7066FC0B13E830E400EFC6DC /* libvpx.a */,
22AA8AFB13D7125500B30535 /* libx264.a */,
15017E6F1773578400784ACB /* libxml2.a */,
F0B89C2118DC89E30050B60E /* MediaPlayer.framework */,
D37DC7171594AF3400B2A5EB /* MessageUI.framework */,
226EF06B15FA256B005865C7 /* MobileCoreServices.framework */,