From 6caf717b59e7e26847a08892b155963dd1601091 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 3 Jul 2014 14:44:42 +0200 Subject: [PATCH 01/11] Incomplete image transfert evolution --- Classes/ChatRoomViewController.h | 2 +- Classes/ChatRoomViewController.m | 45 +++++++++++++++++++++++++-- Classes/ImageSharing.m | 2 +- Classes/LinphoneManager.h | 8 +++++ Classes/LinphoneManager.m | 40 ++++++++++++++++++++++-- Resources/wizard_linphone_create.rc | 2 +- Resources/wizard_linphone_existing.rc | 2 +- 7 files changed, 91 insertions(+), 10 deletions(-) diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index 491accaf4..44f08cc3e 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -29,7 +29,7 @@ #include "linphone/linphonecore.h" -@interface ChatRoomViewController : UIViewController { +@interface ChatRoomViewController : UIViewController { LinphoneChatRoom *chatRoom; ImageSharing *imageSharing; OrderedDictionary *imageQualities; diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index cdfc82e09..a40462b45 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -26,7 +26,12 @@ #import #import "Utils.h" -@implementation ChatRoomViewController +@implementation ChatRoomViewController { + /* Message transfer transient storage */ + /* TODO: use this for data retrieval */ + NSData* image; + size_t offset_sent; +} @synthesize tableController; @synthesize sendButton; @@ -62,6 +67,9 @@ [NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil), [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; self->composingVisible = TRUE; + + self->image = nil; + self->offset_sent = 0; } return self; } @@ -625,8 +633,26 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta - (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]; + NSData* jpegData = UIImageJPEGRepresentation(image, 1.0); + LinphoneContent content = {}; + content.type = "image"; + content.subtype = "jpeg"; + content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); + content.data = (void*)[jpegData bytes]; + content.size = [jpegData length]; + + LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, &content); + linphone_chat_message_set_user_data(message, self); + + if ( url ) { + // internal url is saved in the appdata for display and later save + [LinphoneManager setValueInMessageAppData:[url absoluteString] forKey:@"localimage" inMessage:message]; + } + + linphone_chat_room_send_message2(chatRoom, message, message_status, self); + + [tableController addChatEntry:linphone_chat_message_ref(message)]; + [tableController scrollToBottom:true]; [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; return TRUE; @@ -729,6 +755,19 @@ 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]; +} + +- (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size { + // TODO +} + +- (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size { + // TODO +} #pragma mark - Keyboard Event Functions diff --git a/Classes/ImageSharing.m b/Classes/ImageSharing.m index 6ab27490e..bebc306d0 100644 --- a/Classes/ImageSharing.m +++ b/Classes/ImageSharing.m @@ -92,7 +92,7 @@ - (void)uploadImageTo:(NSURL*)url image:(UIImage*)image { - [LinphoneLogger log:LinphoneLoggerLog format:@"downloading [%@]", [url absoluteString]]; + [LinphoneLogger log:LinphoneLoggerLog format:@"uploading to [%@]", [url absoluteString]]; // setting up the request object now NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h index 6fa0e1fd7..6546807a3 100644 --- a/Classes/LinphoneManager.h +++ b/Classes/LinphoneManager.h @@ -96,6 +96,14 @@ struct NetworkReachabilityContext { }; @end +@protocol LinphoneChatContentTransferDelegate + +-(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 call; SystemSoundID message; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 3a5927891..9f2a092f0 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -859,7 +859,29 @@ static void linphone_iphone_message_received(LinphoneCore *lc, LinphoneChatRoom [(LinphoneManager*)linphone_core_get_user_data(lc) onMessageReceived:lc room:room message:message]; } -#pragma mark - Message composition start +#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 delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Transfer of %s, incoming data (%d bytes)", content->name, 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 delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Transfer of %s, requesting data (%d bytes)", content->name, *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 progress){ + id delegate = (id)linphone_chat_message_get_user_data(message); + [LinphoneLogger log:LinphoneLoggerLog format:@"Progress of transfer %s: %d%%", content->name, progress]; + [delegate onProgressReport:message forContent:content percent:progress]; +} + + + +#pragma mark - Message composition start - (void)onMessageComposeReceived:(LinphoneCore*)core forRoom:(LinphoneChatRoom*)room { [[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneTextComposeEvent @@ -1022,7 +1044,7 @@ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReach } -#pragma mark - +#pragma mark - VTable static LinphoneCoreVTable linphonec_vtable = { .show =NULL, @@ -1041,9 +1063,15 @@ static LinphoneCoreVTable linphonec_vtable = { .transfer_state_changed=linphone_iphone_transfer_state_changed, .is_composing_received = linphone_iphone_is_composing_received, .configuring_status = linphone_iphone_configuring_status_changed, - .global_state_changed = linphone_iphone_global_state_changed + .global_state_changed = linphone_iphone_global_state_changed, + .file_transfer_received = 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); @@ -1111,6 +1139,12 @@ static LinphoneCoreVTable linphonec_vtable = { [self setupNetworkReachabilityCallback]; + NSString *urlString = [self lpConfigStringForKey:@"sharing_server_preference"]; + if( urlString ){ + linphone_core_set_file_transfer_server(theLinphoneCore, [urlString UTF8String]); + } + + NSString* path = [LinphoneManager bundleFile:@"nowebcamCIF.jpg"]; if (path) { const char* imagePath = [path cStringUsingEncoding:[NSString defaultCStringEncoding]]; diff --git a/Resources/wizard_linphone_create.rc b/Resources/wizard_linphone_create.rc index 53c05f61c..0780368e9 100644 --- a/Resources/wizard_linphone_create.rc +++ b/Resources/wizard_linphone_create.rc @@ -18,7 +18,7 @@
1 - https://www.linphone.org:444/upload.php + https://www.linphone.org:444/lft.php 1 stun.linphone.org 1 diff --git a/Resources/wizard_linphone_existing.rc b/Resources/wizard_linphone_existing.rc index 74b948d8a..6bbcf1a49 100644 --- a/Resources/wizard_linphone_existing.rc +++ b/Resources/wizard_linphone_existing.rc @@ -18,7 +18,7 @@
1 - https://www.linphone.org:444/upload.php + https://www.linphone.org:444/lft.php 1 stun.linphone.org 1 From e6045a2c60f90851a98c544373d02ce3b6e8954d Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:31:50 +0200 Subject: [PATCH 02/11] Removed / corrected code spotted by static analysis --- Classes/ChatRoomTableViewController.m | 1 + Classes/ChatRoomViewController.m | 2 +- Classes/HistoryDetailsViewController.m | 12 ------------ Classes/LinphoneManager.m | 1 + Classes/LinphoneUI/UIChatRoomCell.m | 2 ++ .../Controllers/IASKSpecifierValuesViewController.m | 1 + 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Classes/ChatRoomTableViewController.m b/Classes/ChatRoomTableViewController.m index 323c6943a..6533dbfc1 100644 --- a/Classes/ChatRoomTableViewController.m +++ b/Classes/ChatRoomTableViewController.m @@ -47,6 +47,7 @@ // chatRoom = NULL; } - (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; [self reloadData]; } diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index a40462b45..026e1fc87 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -240,10 +240,10 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; - } -(void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; [TUNinePatchCache flushCache]; // will remove any images cache (freeing any cached but unused images) } diff --git a/Classes/HistoryDetailsViewController.m b/Classes/HistoryDetailsViewController.m index dfaf43580..108848ba9 100644 --- a/Classes/HistoryDetailsViewController.m +++ b/Classes/HistoryDetailsViewController.m @@ -385,18 +385,6 @@ static UICompositeViewDescription *compositeDescription = nil; if(lAddress == NULL) return; - NSString *displayName = nil; - if(contact != nil) { - displayName = [FastAddressBook getContactDisplayName:contact]; - } else { - const char* lDisplayName = linphone_address_get_display_name(addr); - const char* lUserName = linphone_address_get_username(addr); - if (lDisplayName) - displayName = [NSString stringWithUTF8String:lDisplayName]; - else if(lUserName) - displayName = [NSString stringWithUTF8String:lUserName]; - } - // Go to ChatRoom view [[PhoneMainView instance] changeCurrentView:[ChatViewController compositeViewDescription]]; ChatRoomViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ChatRoomViewController compositeViewDescription] push:TRUE], ChatRoomViewController); diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 34dc82399..24eeab399 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1890,6 +1890,7 @@ static void audioRouteChangeListenerCallback ( NSData* data = [NSJSONSerialization dataWithJSONObject:appDataDict options:0 error:nil]; NSString* appdataJSON = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; linphone_chat_message_set_appdata(msg, [appdataJSON UTF8String] ); + [appdataJSON release]; } #pragma mark - LPConfig Functions diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index eea11e183..19561be8b 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -140,6 +140,8 @@ static UIFont *CELL_FONT = nil; [messageImageView stopLoading]; [image release]; }); + } else { + [image release]; } }); } failureBlock:^(NSError *error) { diff --git a/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m b/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m index bd0b82ac6..d5d9449b4 100755 --- a/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m +++ b/Classes/Utils/InAppSettingsKit/Controllers/IASKSpecifierValuesViewController.m @@ -105,6 +105,7 @@ } - (void)viewDidUnload { + [super viewDidUnload]; // Release any retained subviews of the main view. // e.g. self.myOutlet = nil; self.tableView = nil; From 33d645dfc5c10259644d40810e46b5112af5d4be Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:43:43 +0200 Subject: [PATCH 03/11] Update linphone and belle-sip --- submodules/belle-sip | 2 +- submodules/linphone | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/submodules/belle-sip b/submodules/belle-sip index 46c40fd48..e25ef8504 160000 --- a/submodules/belle-sip +++ b/submodules/belle-sip @@ -1 +1 @@ -Subproject commit 46c40fd4809dd8d46a6568fa1245150711ec27fd +Subproject commit e25ef850442577adbab07be82112b279ceded9e3 diff --git a/submodules/linphone b/submodules/linphone index 7f4afe295..214521c5a 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 7f4afe2954c1f92df5ca57e2a14e44e152e2b244 +Subproject commit 214521c5a87048b81bb7f6ae278782db5ab4e124 From 974fe07e2b479301942d8dc75148548980ed9e0c Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 13:45:16 +0200 Subject: [PATCH 04/11] Update msopenh264 --- submodules/msopenh264 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/msopenh264 b/submodules/msopenh264 index ae2270dca..bba709ebd 160000 --- a/submodules/msopenh264 +++ b/submodules/msopenh264 @@ -1 +1 @@ -Subproject commit ae2270dcaaabb0cc5980783fc5fb6ac5365ee03f +Subproject commit bba709ebd9fccf0ec2e895275a5bea3c27eece13 From 77dfa1c6b3af146a81445d9e69b82e675f52c955 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:11:46 +0200 Subject: [PATCH 05/11] Added block-based UIAlertview handler. This will ease development --- .../UIAlertView+Blocks/UIAlertView+Blocks.h | 59 ++++ .../UIAlertView+Blocks/UIAlertView+Blocks.m | 264 ++++++++++++++++++ Resources/licenses.html | 23 +- linphone.xcodeproj/project.pbxproj | 17 ++ 4 files changed, 360 insertions(+), 3 deletions(-) create mode 100644 Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h create mode 100644 Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m diff --git a/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h new file mode 100644 index 000000000..d5372d8d2 --- /dev/null +++ b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.h @@ -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 + +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 diff --git a/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m new file mode 100644 index 000000000..2cdfd71ff --- /dev/null +++ b/Classes/Utils/UIAlertView+Blocks/UIAlertView+Blocks.m @@ -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 + +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)self) { + objc_setAssociatedObject(self, UIAlertViewOriginalDelegateKey, self.delegate, OBJC_ASSOCIATION_ASSIGN); + self.delegate = (id)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 diff --git a/Resources/licenses.html b/Resources/licenses.html index a30fe2bed..38e6bca0e 100644 --- a/Resources/licenses.html +++ b/Resources/licenses.html @@ -2,56 +2,73 @@

Third party softwares

+

CAAnimationBlocks

Xissburg
http://xissburg.com

+

ColorConverter

Matteo Alessani
http://www.extendi.it

+

DCRoundSwitch

Patrick Richards
http://domesticcat.com.au
MIT license

+

DTFoundation

Oliver Drobnik
http://www.cocoanetics.com
BSD license

+

HPGrowingTextView

Hans Pinckaers
http://hanspinckaers.com
MIT license

+

InAppSettingsKit

Luc Vandal, Edovia Inc., Ortwin Gentz, FutureTap GmbH
http://www.inappsettingskit.com/
BSD license

+

NinePatch

Tortuga 22, Inc.
http://www.tortuga22.com
Apache license

+ +

Ryan Maxwell

+

UIAlertview+Blocks

+https://github.com/ryanmaxwell/UIAlertView-Blocks
+MIT license +

OrderedDictionary

Matt Gallagher
http://cocoawithlove.com

+

TPMultiLayoutViewController

Michael Tyson
http://atastypixel.com
MIT license

+

UACellBackgroundView

Matt Coneybeare
http://code.coneybeare.net

+

XMLRPC

Eric Czarny
http://divisiblebyzero.com/
MIT license

+

Graphics

+

Kerosine

http://www.kerosine.fr

+

Translations

+

Russian

Maxim Solodovnik
solomax666@gmail.com

-

Utilitary softwares

-

Localization Suite

-

http://www.loc-suite.org

diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj index 9a045321d..edd8efc3a 100755 --- a/linphone.xcodeproj/project.pbxproj +++ b/linphone.xcodeproj/project.pbxproj @@ -1428,6 +1428,8 @@ F0BB8C48193630CA00974404 /* userdb.conf in Resources */ = {isa = PBXBuildFile; fileRef = F0BB8C43193630CA00974404 /* userdb.conf */; }; F0BB8C4C193631D200974404 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 22276E8813C73DC000210156 /* CoreMedia.framework */; }; F0BB8C4D193631DF00974404 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 224567C1107B968500F10948 /* AVFoundation.framework */; }; + F0D00DE2196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */; }; + F0D00DE3196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */; }; F476004B147AAF2800FFF19B /* liblinphone.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2211DB911475562600DEE054 /* liblinphone.a */; }; F84015BF1939FE37006ABAB5 /* test_failed.png in Resources */ = {isa = PBXBuildFile; fileRef = F84015BC1939FE37006ABAB5 /* test_failed.png */; }; F84015C01939FE37006ABAB5 /* test_inprogress.png in Resources */ = {isa = PBXBuildFile; fileRef = F84015BD1939FE37006ABAB5 /* test_inprogress.png */; }; @@ -2377,6 +2379,8 @@ F0BB8C42193630CA00974404 /* tester_hosts */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = tester_hosts; path = submodules/linphone/tester/tester_hosts; sourceTree = SOURCE_ROOT; }; F0BB8C43193630CA00974404 /* userdb.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = userdb.conf; path = submodules/linphone/tester/userdb.conf; sourceTree = SOURCE_ROOT; }; F0BB8C4A193631B300974404 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; + F0D00DE0196EB8F40018F6E7 /* UIAlertView+Blocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+Blocks.h"; sourceTree = ""; }; + F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+Blocks.m"; sourceTree = ""; }; F84015BC1939FE37006ABAB5 /* test_failed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_failed.png; path = Resources/test_failed.png; sourceTree = ""; }; F84015BD1939FE37006ABAB5 /* test_inprogress.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_inprogress.png; path = Resources/test_inprogress.png; sourceTree = ""; }; F84015BE1939FE37006ABAB5 /* test_passed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = test_passed.png; path = Resources/test_passed.png; sourceTree = ""; }; @@ -2880,6 +2884,7 @@ D3807FB615C28940005BE9BC /* DCRoundSwitch */, D37EE15F160377D7003608A6 /* DTFoundation */, D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */, + F0D00DDF196EB8F40018F6E7 /* UIAlertView+Blocks */, D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */, D3ED40141602172200BF332B /* GrowingTextView */, D3807FC715C2894A005BE9BC /* InAppSettingsKit */, @@ -3598,6 +3603,16 @@ name = "Supporting Files"; sourceTree = ""; }; + F0D00DDF196EB8F40018F6E7 /* UIAlertView+Blocks */ = { + isa = PBXGroup; + children = ( + F0D00DE0196EB8F40018F6E7 /* UIAlertView+Blocks.h */, + F0D00DE1196EB8F40018F6E7 /* UIAlertView+Blocks.m */, + ); + name = "UIAlertView+Blocks"; + path = "Utils/UIAlertView+Blocks"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -4916,6 +4931,7 @@ D32409C3158B49A600C8C119 /* UILongTouchButton.m in Sources */, D36C43C6158F2E5A0048BA40 /* UICallCell.m in Sources */, D35E7581159328EB0066B1C1 /* UIAddressTextField.m in Sources */, + F0D00DE2196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */, D35E7597159460580066B1C1 /* ChatViewController.m in Sources */, D35E759F159460B70066B1C1 /* SettingsViewController.m in Sources */, F03CA84318C72F1A0008889D /* UITextViewNoDefine.m in Sources */, @@ -5015,6 +5031,7 @@ D32409C4158B49A600C8C119 /* UILongTouchButton.m in Sources */, D36C43C7158F2E5A0048BA40 /* UICallCell.m in Sources */, D35E7582159328EB0066B1C1 /* UIAddressTextField.m in Sources */, + F0D00DE3196EB8F40018F6E7 /* UIAlertView+Blocks.m in Sources */, D35E7598159460580066B1C1 /* ChatViewController.m in Sources */, D35E75A0159460B70066B1C1 /* SettingsViewController.m in Sources */, F03CA84418C72F1A0008889D /* UITextViewNoDefine.m in Sources */, From 831a7f222f341d5303c6fa7909a1b4769caef269 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:24:15 +0200 Subject: [PATCH 06/11] Add helper functions for Logging --- Classes/Utils/Utils.h | 8 ++++++++ Classes/Utils/Utils.m | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Classes/Utils/Utils.h b/Classes/Utils/Utils.h index 00c7b3eeb..9b2b36a78 100644 --- a/Classes/Utils/Utils.h +++ b/Classes/Utils/Utils.h @@ -62,4 +62,12 @@ typedef enum _LinphoneLoggerSeverity { @end +void Linphone_log(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_dbg(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_warn(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_err(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); +void Linphone_fatal(NSString* format, ...) NS_FORMAT_FUNCTION(1,2); + + + #endif diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m index b6c97ab26..e68b2187c 100644 --- a/Classes/Utils/Utils.m +++ b/Classes/Utils/Utils.m @@ -23,9 +23,8 @@ @implementation LinphoneLogger -+ (void)log:(LinphoneLoggerSeverity) severity format:(NSString *)format,... { - va_list args; - va_start (args, format); + ++ (void)logv:(LinphoneLoggerSeverity)severity format:(NSString*)format args:(va_list)args{ NSString *str = [[NSString alloc] initWithFormat: format arguments:args]; if(severity <= LinphoneLoggerDebug) { ms_debug("%s", [str UTF8String]); @@ -39,6 +38,12 @@ ms_fatal("%s", [str UTF8String]); } [str release]; +} + ++ (void)log:(LinphoneLoggerSeverity) severity format:(NSString *)format,... { + va_list args; + va_start (args, format); + [LinphoneLogger logv:severity format:format args:args]; va_end (args); } @@ -237,3 +242,29 @@ } @end + +#define LOGV(level, argstart) \ + va_list args; \ + va_start(args, argstart); \ + [LinphoneLogger logv:level format:argstart args:args]; \ + va_end(args); + +void Linphone_log(NSString* format, ...){ + LOGV(LinphoneLoggerLog, format); +} + +void Linphone_dbg(NSString* format, ...){ + LOGV(LinphoneLoggerDebug, format); +} + +void Linphone_warn(NSString* format, ...){ + LOGV(LinphoneLoggerWarning, format); +} + +void Linphone_err(NSString* format, ...){ + LOGV(LinphoneLoggerError, format); +} + +void Linphone_fatal(NSString* format, ...){ + LOGV(LinphoneLoggerFatal, format); +} From 7467caa879d375ef723e5e2ab206df3b07740a00 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:27:48 +0200 Subject: [PATCH 07/11] Progress commit on message file transfer: - upload and download works, - download only works for runtime messages. Messages pulled from DB will make belle-sip crash - can't cancel the transfer for the moment (waiting for API to fix that) --- Classes/ChatRoomTableViewController.h | 2 +- Classes/ChatRoomViewController.h | 2 +- Classes/ChatRoomViewController.m | 256 +++++++++++++------------- Classes/LinphoneUI/UIChatRoomCell.m | 4 +- 4 files changed, 136 insertions(+), 128 deletions(-) diff --git a/Classes/ChatRoomTableViewController.h b/Classes/ChatRoomTableViewController.h index 38fc39114..e0b3fcedb 100644 --- a/Classes/ChatRoomTableViewController.h +++ b/Classes/ChatRoomTableViewController.h @@ -23,7 +23,7 @@ @protocol ChatRoomDelegate -- (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; diff --git a/Classes/ChatRoomViewController.h b/Classes/ChatRoomViewController.h index 44f08cc3e..aa6492db4 100644 --- a/Classes/ChatRoomViewController.h +++ b/Classes/ChatRoomViewController.h @@ -29,7 +29,7 @@ #include "linphone/linphonecore.h" -@interface ChatRoomViewController : UIViewController { +@interface ChatRoomViewController : UIViewController { LinphoneChatRoom *chatRoom; ImageSharing *imageSharing; OrderedDictionary *imageQualities; diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index 026e1fc87..b9d1a43f6 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -21,6 +21,7 @@ #import "PhoneMainView.h" #import "DTActionSheet.h" #import "UILinphone.h" +#import "UIAlertView+Blocks.h" #import #import @@ -28,9 +29,10 @@ @implementation ChatRoomViewController { /* Message transfer transient storage */ - /* TODO: use this for data retrieval */ - NSData* image; - size_t offset_sent; + NSData* upload_data; + size_t upload_bytes_sent; + + NSMutableData* download_data; } @synthesize tableController; @@ -68,8 +70,9 @@ [NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil]; self->composingVisible = TRUE; - self->image = nil; - self->offset_sent = 0; + self->upload_data = nil; + self->upload_bytes_sent = 0; + self->download_data = nil; } return self; } @@ -199,8 +202,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]; @@ -269,7 +272,7 @@ static UICompositeViewDescription *compositeDescription = nil; - (void)update { if(chatRoom == NULL) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot update chat room header: null contact"]; + Linphone_warn(@"Cannot update chat room header: null contact"); return; } @@ -314,18 +317,17 @@ static UICompositeViewDescription *compositeDescription = nil; static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) { ChatRoomViewController* thiz = (ChatRoomViewController*)ud; const char*text = linphone_chat_message_get_text(msg); - [LinphoneLogger log:LinphoneLoggerLog - format:@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)]; + Linphone_log(@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state)); [thiz.tableController updateChatEntry:msg]; } - (BOOL)sendMessage:(NSString *)message withExterlBodyUrl:(NSURL*)externalUrl withInternalURL:(NSURL*)internalUrl { if(![LinphoneManager isLcReady]) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: Linphone core not ready"]; + Linphone_warn(@"Cannot send message: Linphone core not ready"); return FALSE; } if(chatRoom == NULL) { - [LinphoneLogger logc:LinphoneLoggerWarning format:"Cannot send message: No chatroom"]; + Linphone_warn(@"Cannot send message: No chatroom"); return FALSE; } @@ -347,35 +349,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) { - [LinphoneLogger log:LinphoneLoggerError format:@"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]; - [errorAlert release]; - return; - } - [LinphoneLogger log:LinphoneLoggerLog format:@"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 { @@ -536,8 +510,19 @@ 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 ){ + + [UIAlertView showWithTitle:NSLocalizedString(@"Cancel transfer?", nil) + message:NSLocalizedString(@"You have a transfer in progress, leaving this view will cancel it. Are you sure?", nil) + cancelButtonTitle:NSLocalizedString(@"Cancel", nil) + otherButtonTitles:@[NSLocalizedString(@"Yes", nil)] + tapBlock:^(UIAlertView *alertView, NSInteger buttonIndex) { + if( buttonIndex == 1 ){ + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; + } + }]; + } } - (IBAction)onEditClick:(id)event { @@ -621,9 +606,18 @@ 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); + Linphone_log(@"Content to download: %s", url); + + if( url == nil ) return FALSE; + + download_data = [[NSMutableData alloc] init]; + + linphone_chat_message_set_user_data(msg, self); + linphone_chat_message_start_file_download(msg); + [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; return TRUE; @@ -632,14 +626,13 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta } - (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url{ - if(imageSharing == nil) { - NSData* jpegData = UIImageJPEGRepresentation(image, 1.0); + if( self->upload_data == nil) { LinphoneContent content = {}; - content.type = "image"; - content.subtype = "jpeg"; - content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); - content.data = (void*)[jpegData bytes]; - content.size = [jpegData length]; + self->upload_data = [UIImageJPEGRepresentation(image, 1.0) retain]; + content.type = "image"; + content.subtype = "jpeg"; + content.name = ms_strdup([[NSString stringWithFormat:@"%i-%f.jpg", [image hash],[NSDate timeIntervalSinceReferenceDate]] UTF8String]); + content.size = [self->upload_data length]; LinphoneChatMessage* message = linphone_chat_room_create_file_transfer_message(chatRoom, &content); linphone_chat_message_set_user_data(message, self); @@ -649,8 +642,14 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [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, self); + if( content.name ){ + ms_free(content.name); + } + [tableController addChatEntry:linphone_chat_message_ref(message)]; [tableController scrollToBottom:true]; [messageView setHidden:TRUE]; @@ -666,10 +665,6 @@ 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]; @@ -677,68 +672,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta 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) { - [LinphoneLogger log:LinphoneLoggerError format:@"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]; - [errorAlert release]; - } else { - [LinphoneLogger log:LinphoneLoggerError format:@"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]; - [errorAlert release]; - } - 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) { - [LinphoneLogger log:LinphoneLoggerError format:@"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]; - [errorAlert release]; - return; - } - [LinphoneLogger log:LinphoneLoggerLog format:@"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 { @@ -758,15 +691,92 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta #pragma mark - LinphoneChatContentTransferDelegate - (void)onProgressReport:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content percent:(int)percent { - [imageTransferProgressBar setProgress:percent]; + [imageTransferProgressBar setProgress:percent/100.0f]; } - (void)onDataRequested:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(char *)buffer withSize:(size_t *)size { - // TODO + if( self->upload_data ){ + size_t to_send = *size; + size_t remaining = [upload_data length] - self->upload_bytes_sent; + + Linphone_log(@"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) { + Linphone_err(@"Exception: %@", exception); + } + + + if( to_send == 0 || upload_bytes_sent == [upload_data length] ){ + Linphone_log(@"Upload finished, cleanup.."); + [upload_data release]; + upload_data = nil; + upload_bytes_sent = 0; + + // update UI + dispatch_async(dispatch_get_main_queue(), ^{ + [messageView setHidden:FALSE]; + [transferView setHidden:TRUE]; + }); + } + + } else { + Linphone_err(@"Error: no upload data in progress!"); + } } - (void)onDataReceived:(LinphoneChatMessage *)msg forContent:(const LinphoneContent *)content buffer:(const char *)buffer withSize:(size_t)size { - // TODO + if( download_data ){ + Linphone_log(@"Receiving data for %s : %zu bytes, already got %d of %zu",content->name, size, [download_data length], content->size); + + if( size != 0 ){ + [download_data appendBytes:buffer length:size]; + } + + if( size == 0 && [download_data length] == content->size ){ + + Linphone_log(@"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 release]; + download_data = nil; + + [[LinphoneManager instance].photoLibrary + writeImageToSavedPhotosAlbum:image.CGImage + orientation:(ALAssetOrientation)[image imageOrientation] + completionBlock:^(NSURL *assetURL, NSError *error){ + if (error) { + Linphone_err(@"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]; + [errorAlert release]; + return; + } + Linphone_log(@"Image saved to [%@]", [assetURL absoluteString]); + [LinphoneManager setValueInMessageAppData:[assetURL absoluteString] forKey:@"localimage" inMessage:msg]; + [tableController updateChatEntry:msg]; + }]; + + }); + } + } } #pragma mark - Keyboard Event Functions @@ -781,7 +791,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [UIView setAnimationCurve:curve]; [UIView setAnimationBeginsFromCurrentState:TRUE]; CGFloat composeIndicatorCompensation = composingVisible ? composeIndicatorView.frame.size.height : 0.0f; - + // Resize chat view { CGRect chatFrame = [[self chatView] frame]; diff --git a/Classes/LinphoneUI/UIChatRoomCell.m b/Classes/LinphoneUI/UIChatRoomCell.m index 19561be8b..18f37676d 100644 --- a/Classes/LinphoneUI/UIChatRoomCell.m +++ b/Classes/LinphoneUI/UIChatRoomCell.m @@ -315,9 +315,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 { From d9c51e485456d3b81ce18565d2b2590345268f7e Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 14:28:02 +0200 Subject: [PATCH 08/11] Use named background task when possible --- Classes/LinphoneManager.m | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index 24eeab399..0df79656e 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -629,11 +629,19 @@ static void linphone_iphone_display_status(struct _LinphoneCore * lc, const char [[UIApplication sharedApplication] presentLocalNotificationNow:data->notification]; if (!incallBgTask){ - incallBgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler: ^{ - [LinphoneLogger log:LinphoneLoggerWarning format:@"Call cannot ring any more, too late"]; - [[UIApplication sharedApplication] endBackgroundTask:incallBgTask]; - incallBgTask=0; - }]; + UIApplication* app = [UIApplication sharedApplication]; + + void (^expirationHandler)() = ^{ + [LinphoneLogger log:LinphoneLoggerWarning format:@"Call cannot ring any more, too late"]; + [[UIApplication sharedApplication] endBackgroundTask:incallBgTask]; + incallBgTask=0; + }; + + if( [app respondsToSelector:@selector(beginBackgroundTaskWithName:expirationHandler:)] ){ + incallBgTask = [app beginBackgroundTaskWithName:@"Linphone in-call bg task" expirationHandler:expirationHandler]; + } else { + incallBgTask = [app beginBackgroundTaskWithExpirationHandler:expirationHandler]; + } [[NSRunLoop currentRunLoop] addTimer:data->timer forMode:NSRunLoopCommonModes]; } From 154f247009c249cfc8a15e1c277586beb7d11f6b Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 10 Jul 2014 17:45:25 +0200 Subject: [PATCH 09/11] Update linphone --- submodules/linphone | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/linphone b/submodules/linphone index 214521c5a..38ea4ee8a 160000 --- a/submodules/linphone +++ b/submodules/linphone @@ -1 +1 @@ -Subproject commit 214521c5a87048b81bb7f6ae278782db5ab4e124 +Subproject commit 38ea4ee8a341f58f26406dfb94b7a021980f4872 From d56dc2a972974895f0868ed832ffb825e94a365f Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Fri, 11 Jul 2014 09:04:02 +0200 Subject: [PATCH 10/11] Fix back button --- Classes/ChatRoomViewController.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index b9d1a43f6..d09b59024 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -522,6 +522,9 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta [[PhoneMainView instance] popCurrentView]; } }]; + } else { + [self.tableController setChatRoom:NULL]; + [[PhoneMainView instance] popCurrentView]; } } From 2d702f020e301b8351d0bcd7e7774971d9153c22 Mon Sep 17 00:00:00 2001 From: Guillaume BIENKOWSKI Date: Thu, 11 Sep 2014 12:12:10 +0200 Subject: [PATCH 11/11] Update prototypes for new API of linphone chat messages --- Classes/ChatRoomViewController.m | 2 +- Classes/LinphoneManager.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/ChatRoomViewController.m b/Classes/ChatRoomViewController.m index d09b59024..a787490c6 100644 --- a/Classes/ChatRoomViewController.m +++ b/Classes/ChatRoomViewController.m @@ -619,7 +619,7 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta download_data = [[NSMutableData alloc] init]; linphone_chat_message_set_user_data(msg, self); - linphone_chat_message_start_file_download(msg); + linphone_chat_message_start_file_download(msg,NULL); [messageView setHidden:TRUE]; [transferView setHidden:FALSE]; diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m index a105fba20..95a0cee4c 100644 --- a/Classes/LinphoneManager.m +++ b/Classes/LinphoneManager.m @@ -1128,7 +1128,7 @@ 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, - .file_transfer_received = linphone_iphone_file_transfer_recv, + .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