mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 11:08:06 +00:00
filetransfer: rework file transfer to use latest API
This commit is contained in:
parent
c501f59859
commit
06375f58af
25 changed files with 808 additions and 862 deletions
|
|
@ -1,31 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6751" systemVersion="14B25" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6736"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ChatRoomViewController">
|
||||
<connections>
|
||||
<outlet property="addressLabel" destination="40" id="43"/>
|
||||
<outlet property="avatarImage" destination="41" id="44"/>
|
||||
<outlet property="cancelTransferButton" destination="75" id="85"/>
|
||||
<outlet property="chatView" destination="49" id="54"/>
|
||||
<outlet property="composeIndicatorView" destination="fx4-ao-53M" id="xk5-nK-lur"/>
|
||||
<outlet property="composeLabel" destination="fpY-Fv-ht2" id="4L6-ik-ZAe"/>
|
||||
<outlet property="editButton" destination="10" id="35"/>
|
||||
<outlet property="headerView" destination="39" id="45"/>
|
||||
<outlet property="imageTransferProgressBar" destination="74" id="79"/>
|
||||
<outlet property="messageBackgroundImage" destination="66" id="90"/>
|
||||
<outlet property="messageField" destination="63" id="64"/>
|
||||
<outlet property="messageView" destination="14" id="89"/>
|
||||
<outlet property="pictureButton" destination="73" id="84"/>
|
||||
<outlet property="sendButton" destination="15" id="27"/>
|
||||
<outlet property="tableController" destination="29" id="32"/>
|
||||
<outlet property="transferBackgroundImage" destination="83" id="88"/>
|
||||
<outlet property="transferView" destination="72" id="86"/>
|
||||
<outlet property="view" destination="6" id="11"/>
|
||||
<outlet property="waitView" destination="91" id="93"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
|
|
@ -90,46 +85,11 @@
|
|||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<view hidden="YES" contentMode="scaleToFill" id="72" userLabel="transferView">
|
||||
<rect key="frame" x="0.0" y="359" width="320" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="chat_progressbar_background.png" id="83" userLabel="transfertBackgroundImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" id="75" userLabel="cancelTransferButton">
|
||||
<rect key="frame" x="262" y="0.0" width="58" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<state key="normal" backgroundImage="chat_cancel_default.png">
|
||||
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<state key="highlighted" backgroundImage="chat_cancel_over.png">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onTransferCancelClick:" destination="-1" eventType="touchUpInside" id="78"/>
|
||||
</connections>
|
||||
</button>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" progress="0.5" id="74" userLabel="transferProgressBar">
|
||||
<rect key="frame" x="20" y="27" width="222" height="2"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Upload or download progression">
|
||||
<accessibilityTraits key="traits" none="YES" notEnabled="YES" updatesFrequently="YES"/>
|
||||
</accessibility>
|
||||
</progressView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="14" userLabel="messageView">
|
||||
<rect key="frame" x="0.0" y="359" width="320" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="chat_message_background.png" id="66" userLabel="messageBackgroundImage">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" id="66" userLabel="messageBackgroundImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="57"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -235,17 +195,6 @@
|
|||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<view hidden="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="91" userLabel="waitView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" contentMode="scaleToFill" animating="YES" style="whiteLarge" id="92" userLabel="activityIndicator">
|
||||
<rect key="frame" x="142" y="211" width="37" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="0.66000000000000003" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<gestureRecognizers/>
|
||||
|
|
@ -264,16 +213,12 @@
|
|||
<image name="avatar_unknown_small.png" width="131" height="131"/>
|
||||
<image name="chat_back_default.png" width="320" height="88"/>
|
||||
<image name="chat_back_over.png" width="320" height="88"/>
|
||||
<image name="chat_cancel_default.png" width="116" height="115"/>
|
||||
<image name="chat_cancel_over.png" width="116" height="115"/>
|
||||
<image name="chat_edit_default.png" width="320" height="88"/>
|
||||
<image name="chat_edit_over.png" width="320" height="88"/>
|
||||
<image name="chat_message_background.png" width="640" height="117"/>
|
||||
<image name="chat_ok_default.png" width="320" height="88"/>
|
||||
<image name="chat_photo_default.png" width="71" height="115"/>
|
||||
<image name="chat_photo_disabled.png" width="71" height="115"/>
|
||||
<image name="chat_photo_over.png" width="71" height="115"/>
|
||||
<image name="chat_progressbar_background.png" width="524" height="115"/>
|
||||
<image name="chat_send_default.png" width="117" height="115"/>
|
||||
<image name="chat_send_disabled.png" width="117" height="115"/>
|
||||
<image name="chat_send_over.png" width="117" height="115"/>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
@protocol ChatRoomDelegate <NSObject>
|
||||
|
||||
- (BOOL)chatRoomStartImageDownload:(LinphoneChatMessage*)msg;
|
||||
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)url;
|
||||
- (void)resendChat:(NSString*)message withExternalUrl:(NSString*)url;
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,16 @@
|
|||
if( !chatRoom ) return;
|
||||
[self clearMessageList];
|
||||
self->messageList = linphone_chat_room_get_history(chatRoom, 0);
|
||||
|
||||
// also append transient upload messages because they are not in history yet!
|
||||
for (FileTransferDelegate *ftd in [[LinphoneManager instance] fileTransferDelegates]) {
|
||||
if (linphone_chat_room_get_peer_address(linphone_chat_message_get_chat_room(ftd.message)) ==
|
||||
linphone_chat_room_get_peer_address(chatRoom) &&
|
||||
linphone_chat_message_is_outgoing(ftd.message)) {
|
||||
LOGI(@"Appending transient upload message %p", ftd.message);
|
||||
self->messageList = ms_list_append(self->messageList, ftd.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reloadData {
|
||||
|
|
@ -76,9 +86,10 @@
|
|||
messageList = ms_list_append(messageList, linphone_chat_message_ref(chat));
|
||||
int pos = ms_list_size(messageList) - 1;
|
||||
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:pos inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
|
||||
[self.tableView endUpdates];
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0];
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (void)updateChatEntry:(LinphoneChatMessage*)chat {
|
||||
|
|
|
|||
|
|
@ -24,14 +24,12 @@
|
|||
#import "ChatRoomTableViewController.h"
|
||||
#import "HPGrowingTextView.h"
|
||||
#import "ImagePickerViewController.h"
|
||||
#import "ImageSharing.h"
|
||||
#import "OrderedDictionary.h"
|
||||
|
||||
#include "linphone/linphonecore.h"
|
||||
|
||||
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatRoomDelegate, LinphoneChatContentTransferDelegate> {
|
||||
@interface ChatRoomViewController : UIViewController<HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatRoomDelegate> {
|
||||
LinphoneChatRoom *chatRoom;
|
||||
ImageSharing *imageSharing;
|
||||
OrderedDictionary *imageQualities;
|
||||
BOOL scrollOnGrowingEnabled;
|
||||
BOOL composingVisible;
|
||||
|
|
@ -54,17 +52,12 @@
|
|||
@property (strong, nonatomic) IBOutlet UIView *composeIndicatorView;
|
||||
|
||||
@property (nonatomic, strong) IBOutlet UIButton* pictureButton;
|
||||
@property (nonatomic, strong) IBOutlet UIButton* cancelTransferButton;
|
||||
@property (nonatomic, strong) IBOutlet UIProgressView* imageTransferProgressBar;
|
||||
@property (nonatomic, strong) IBOutlet UIView* transferView;
|
||||
@property (nonatomic, strong) IBOutlet UIView* waitView;
|
||||
|
||||
- (IBAction)onBackClick:(id)event;
|
||||
- (IBAction)onEditClick:(id)event;
|
||||
- (IBAction)onMessageChange:(id)sender;
|
||||
- (IBAction)onSendClick:(id)event;
|
||||
- (IBAction)onPictureClick:(id)event;
|
||||
- (IBAction)onTransferCancelClick:(id)event;
|
||||
- (IBAction)onListTap:(id)sender;
|
||||
|
||||
- (void)setChatRoom:(LinphoneChatRoom*)room;
|
||||
|
|
|
|||
|
|
@ -21,20 +21,14 @@
|
|||
#import "PhoneMainView.h"
|
||||
#import "DTActionSheet.h"
|
||||
#import "UILinphone.h"
|
||||
//#import "UIAlertView+Blocks.h"
|
||||
#import "DTAlertView.h"
|
||||
|
||||
#import "Utils/FileTransferDelegate.h"
|
||||
#import <NinePatch.h>
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
#import "Utils.h"
|
||||
#import "UIChatRoomCell.h"
|
||||
|
||||
@implementation ChatRoomViewController {
|
||||
/* Message transfer transient storage */
|
||||
NSData* upload_data;
|
||||
size_t upload_bytes_sent;
|
||||
|
||||
NSMutableData* download_data;
|
||||
}
|
||||
@implementation ChatRoomViewController
|
||||
|
||||
@synthesize tableController;
|
||||
@synthesize sendButton;
|
||||
|
|
@ -52,32 +46,23 @@
|
|||
@synthesize listTapGestureRecognizer;
|
||||
@synthesize listSwipeGestureRecognizer;
|
||||
@synthesize pictureButton;
|
||||
@synthesize imageTransferProgressBar;
|
||||
@synthesize cancelTransferButton;
|
||||
@synthesize transferView;
|
||||
@synthesize waitView;
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
||||
- (id)init {
|
||||
self = [super initWithNibName:@"ChatRoomViewController" bundle:[NSBundle mainBundle]];
|
||||
if (self != nil) {
|
||||
self->scrollOnGrowingEnabled = TRUE;
|
||||
self->chatRoom = NULL;
|
||||
self->imageSharing = NULL;
|
||||
self->listTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onListTap:)];
|
||||
self.listSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onListSwipe:)];
|
||||
self->imageQualities = [[OrderedDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithFloat:0.9], NSLocalizedString(@"Maximum", nil),
|
||||
[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;
|
||||
self = [super initWithNibName:@"ChatRoomViewController" bundle:[NSBundle mainBundle]];
|
||||
if (self != nil) {
|
||||
self->scrollOnGrowingEnabled = TRUE;
|
||||
self->chatRoom = NULL;
|
||||
self->listTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onListTap:)];
|
||||
self.listSwipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(onListSwipe:)];
|
||||
self->imageQualities = [[OrderedDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithFloat:0.9], NSLocalizedString(@"Maximum", nil),
|
||||
[NSNumber numberWithFloat:0.5], NSLocalizedString(@"Average", nil),
|
||||
[NSNumber numberWithFloat:0.0], NSLocalizedString(@"Minimum", nil), nil];
|
||||
self->composingVisible = TRUE;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
|
|
@ -168,6 +153,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
selector:@selector(textComposeEvent:)
|
||||
name:kLinphoneTextComposeEvent
|
||||
object:nil];
|
||||
|
||||
if([tableController isEditing])
|
||||
[tableController setEditing:FALSE animated:FALSE];
|
||||
[editButton setOff];
|
||||
|
|
@ -179,39 +165,16 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
BOOL fileSharingEnabled = [[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"] != NULL
|
||||
&& [[[LinphoneManager instance] lpConfigStringForKey:@"sharing_server_preference"] length]>0;
|
||||
[pictureButton setEnabled:fileSharingEnabled];
|
||||
[waitView setHidden:TRUE];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
if(upload_data || download_data ) {
|
||||
// TODO: when the API permits it, we should cancel the transfer.
|
||||
}
|
||||
|
||||
[messageField resignFirstResponder];
|
||||
|
||||
[self setComposingVisible:FALSE withDelay:0]; // will hide the "user is composing.." message
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:UIApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:UIKeyboardWillShowNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:UIKeyboardWillHideNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:kLinphoneTextReceived
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:UITextViewTextDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:kLinphoneTextComposeEvent
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
|
||||
|
|
@ -298,9 +261,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
}
|
||||
|
||||
static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState state,void* ud) {
|
||||
ChatRoomViewController* thiz = (__bridge ChatRoomViewController*)ud;
|
||||
const char*text = linphone_chat_message_get_text(msg);
|
||||
const char *text = (linphone_chat_message_get_file_transfer_information(msg) != NULL) ? "photo transfer" : linphone_chat_message_get_text(msg);
|
||||
LOGI(@"Delivery status for [%s] is [%s]",text,linphone_chat_message_state_to_string(state));
|
||||
ChatRoomViewController* thiz = (__bridge ChatRoomViewController*)ud;
|
||||
[thiz.tableController updateChatEntry:msg];
|
||||
}
|
||||
|
||||
|
|
@ -332,8 +295,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
|
|||
}
|
||||
|
||||
- (void)chooseImageQuality:(UIImage*)image url:(NSURL*)url {
|
||||
[waitView setHidden:FALSE];
|
||||
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Choose the image size", nil)];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
//UIImage *image = [original_image normalizedImage];
|
||||
|
|
@ -349,7 +310,6 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
|
|||
}
|
||||
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[waitView setHidden:TRUE];
|
||||
[sheet showInView:[PhoneMainView instance].view];
|
||||
});
|
||||
});
|
||||
|
|
@ -482,20 +442,8 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
|
|||
#pragma mark - Action Functions
|
||||
|
||||
- (IBAction)onBackClick:(id)event {
|
||||
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];
|
||||
}
|
||||
[self.tableController setChatRoom:NULL];
|
||||
[[PhoneMainView instance] popCurrentView];
|
||||
}
|
||||
|
||||
- (IBAction)onEditClick:(id)event {
|
||||
|
|
@ -573,76 +521,21 @@ static void message_status(LinphoneChatMessage* msg,LinphoneChatMessageState sta
|
|||
[sheet showInView:[PhoneMainView instance].view];
|
||||
}
|
||||
|
||||
- (IBAction)onTransferCancelClick:(id)event {
|
||||
if(imageSharing) {
|
||||
[imageSharing cancel];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark ChatRoomDelegate
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (BOOL)chatRoomStartImageUpload:(UIImage*)image url:(NSURL*)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;
|
||||
}
|
||||
return FALSE;
|
||||
FileTransferDelegate * fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
[[[LinphoneManager instance] fileTransferDelegates] addObject:fileTransfer];
|
||||
[fileTransfer upload:image withURL:url forChatRoom:chatRoom];
|
||||
[tableController addChatEntry:linphone_chat_message_ref(fileTransfer.message)];
|
||||
[tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url {
|
||||
[self sendMessage:message withExterlBodyUrl:[NSURL URLWithString:url] withInternalURL:nil];
|
||||
}
|
||||
|
||||
#pragma mark ImageSharingDelegate
|
||||
|
||||
- (void)imageSharingAborted:(ImageSharing*)aimageSharing {
|
||||
[messageView setHidden:FALSE];
|
||||
[transferView setHidden:TRUE];
|
||||
imageSharing = nil;
|
||||
}
|
||||
|
||||
#pragma mark ImagePickerDelegate
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage*)image info:(NSDictionary *)info {
|
||||
|
|
@ -659,94 +552,6 @@ 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
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notif {
|
||||
|
|
|
|||
|
|
@ -64,43 +64,44 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
|
|||
LinphoneChatMessage* last_elem_message = linphone_chat_room_get_user_data(elem);
|
||||
|
||||
if( last_new_message && last_elem_message ){
|
||||
time_t new = linphone_chat_message_get_time(last_new_message);
|
||||
time_t old = linphone_chat_message_get_time(last_elem_message);
|
||||
if ( new < old ) return 1;
|
||||
else if ( new > old) return -1;
|
||||
}
|
||||
return 0;
|
||||
time_t new = linphone_chat_message_get_time(last_new_message);
|
||||
time_t old = linphone_chat_message_get_time(last_elem_message);
|
||||
if (new < old)
|
||||
return 1;
|
||||
else if (new > old)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (MSList*)sortChatRooms {
|
||||
MSList* sorted = nil;
|
||||
MSList* unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]);
|
||||
MSList* iter = unsorted;
|
||||
MSList *sorted = nil;
|
||||
MSList *unsorted = linphone_core_get_chat_rooms([LinphoneManager getLc]);
|
||||
MSList *iter = unsorted;
|
||||
|
||||
while (iter) {
|
||||
// store last message in user data
|
||||
MSList* history = linphone_chat_room_get_history(iter->data, 1);
|
||||
LinphoneChatMessage* last_msg = history? history->data : NULL;
|
||||
if( last_msg ){
|
||||
linphone_chat_room_set_user_data(iter->data, linphone_chat_message_ref(last_msg));
|
||||
}
|
||||
ms_list_free_with_data(history, (void (*)(void *))linphone_chat_message_unref);
|
||||
while (iter) {
|
||||
// store last message in user data
|
||||
LinphoneChatRoom *chat_room = iter->data;
|
||||
MSList *history = linphone_chat_room_get_history(iter->data, 1);
|
||||
assert(ms_list_size(history) <= 1);
|
||||
LinphoneChatMessage *last_msg = history ? history->data : NULL;
|
||||
if (last_msg) {
|
||||
linphone_chat_message_ref(last_msg);
|
||||
linphone_chat_room_set_user_data(chat_room, last_msg);
|
||||
}
|
||||
sorted = ms_list_insert_sorted(sorted, chat_room, (MSCompareFunc)sorted_history_comparison);
|
||||
|
||||
sorted = ms_list_insert_sorted(sorted,
|
||||
iter->data,
|
||||
(MSCompareFunc)sorted_history_comparison);
|
||||
|
||||
iter = iter->next;
|
||||
}
|
||||
return sorted;
|
||||
iter = iter->next;
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
static void chatTable_free_chatrooms(void *data){
|
||||
LinphoneChatMessage* lastMsg = linphone_chat_room_get_user_data(data);
|
||||
if( lastMsg ){
|
||||
linphone_chat_message_unref(lastMsg);
|
||||
linphone_chat_room_set_user_data(data, NULL);
|
||||
}
|
||||
LinphoneChatMessage *lastMsg = linphone_chat_room_get_user_data(data);
|
||||
if (lastMsg) {
|
||||
linphone_chat_message_unref(lastMsg);
|
||||
linphone_chat_room_set_user_data(data, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadData {
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/* ImageSharing.h
|
||||
*
|
||||
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ImageSharing;
|
||||
|
||||
@protocol ImageSharingDelegate <NSObject>
|
||||
|
||||
- (void)imageSharingProgress:(ImageSharing*)imageSharing progress:(float)progress;
|
||||
- (void)imageSharingAborted:(ImageSharing*)imageSharing;
|
||||
- (void)imageSharingError:(ImageSharing*)imageSharing error:(NSError *)error;
|
||||
- (void)imageSharingUploadDone:(ImageSharing*)imageSharing url:(NSURL*)url;
|
||||
- (void)imageSharingDownloadDone:(ImageSharing*)imageSharing image:(UIImage *)image;
|
||||
|
||||
@end
|
||||
|
||||
@interface ImageSharing : NSObject<NSURLConnectionDataDelegate> {
|
||||
@private
|
||||
NSInteger totalBytesExpectedToRead;
|
||||
id<ImageSharingDelegate> delegate;
|
||||
NSInteger statusCode;
|
||||
}
|
||||
|
||||
+ (id)newImageSharingUpload:(NSURL*)url image:(UIImage*)image delegate:(id<ImageSharingDelegate>)delegate userInfo:(id)userInfo;
|
||||
+ (id)newImageSharingDownload:(NSURL*)url delegate:(id<ImageSharingDelegate>)delegate userInfo:(id)userInfo;
|
||||
|
||||
- (void)cancel;
|
||||
|
||||
@property (nonatomic, strong) id userInfo;
|
||||
|
||||
@property (nonatomic, readonly) BOOL upload;
|
||||
@property (nonatomic, readonly) NSMutableData* data;
|
||||
@property (nonatomic, readonly) NSURLConnection* connection;
|
||||
|
||||
@end
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
/* ImageSharing.m
|
||||
*
|
||||
* Copyright (C) 2012 Belledonne Comunications, Grenoble, France
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import "ImageSharing.h"
|
||||
#import "Utils.h"
|
||||
#import "LinphoneManager.h"
|
||||
|
||||
@implementation ImageSharing
|
||||
|
||||
@synthesize connection;
|
||||
@synthesize data;
|
||||
@synthesize upload;
|
||||
@synthesize userInfo;
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
||||
+ (id)newImageSharingUpload:(NSURL*)url image:(UIImage*)image delegate:(id<ImageSharingDelegate>)delegate userInfo:(id)auserInfo{
|
||||
ImageSharing *imgs = [[ImageSharing alloc] init];
|
||||
if(imgs != nil) {
|
||||
imgs.userInfo = auserInfo;
|
||||
imgs->upload = TRUE;
|
||||
imgs->delegate = delegate;
|
||||
imgs->data = [[NSMutableData alloc] init];
|
||||
if(delegate) {
|
||||
[delegate imageSharingProgress:imgs progress:0];
|
||||
}
|
||||
[imgs uploadImageTo:url image:image];
|
||||
}
|
||||
return imgs;
|
||||
}
|
||||
|
||||
+ (id)newImageSharingDownload:(NSURL*)url delegate:(id<ImageSharingDelegate>)delegate userInfo:(id)auserInfo{
|
||||
ImageSharing *imgs = [[ImageSharing alloc] init];
|
||||
if(imgs != nil) {
|
||||
imgs.userInfo = auserInfo;
|
||||
imgs->upload = FALSE;
|
||||
imgs->delegate = delegate;
|
||||
imgs->data = [[NSMutableData alloc] init];
|
||||
if(delegate) {
|
||||
[delegate imageSharingProgress:imgs progress:0];
|
||||
}
|
||||
[imgs downloadImageFrom:url];
|
||||
}
|
||||
return imgs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)cancel {
|
||||
[connection cancel];
|
||||
LOGI(@"File transfer interrupted by user");
|
||||
if(delegate) {
|
||||
[delegate imageSharingAborted:self];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)downloadImageFrom:(NSURL*)url {
|
||||
LOGI(@"downloading [%@]", [url absoluteString]);
|
||||
|
||||
NSURLRequest* request = [NSURLRequest requestWithURL:url
|
||||
cachePolicy:NSURLRequestUseProtocolCachePolicy
|
||||
timeoutInterval:60.0];
|
||||
|
||||
connection = [[NSURLConnection alloc] initWithRequest:request delegate: self];
|
||||
}
|
||||
|
||||
|
||||
- (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];
|
||||
[request setHTTPMethod:@"POST"];
|
||||
|
||||
/*
|
||||
add some header info now
|
||||
we always need a boundary when we post a file
|
||||
also we need to set the content type
|
||||
|
||||
You might want to generate a random boundary.. this is just the same
|
||||
as my output from wireshark on a valid html post
|
||||
*/
|
||||
NSString *boundary = @"---------------------------14737809831466499882746641449";
|
||||
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
|
||||
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];
|
||||
|
||||
/*
|
||||
now lets create the body of the post
|
||||
*/
|
||||
NSMutableData *body = [NSMutableData data];
|
||||
NSString *imageName = [NSString stringWithFormat:@"%lu-%f.jpg", (unsigned long)[image hash],[NSDate timeIntervalSinceReferenceDate]];
|
||||
[body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n",imageName] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[body appendData:[@"Content-Type: application/octet-stream\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[body appendData:[NSData dataWithData:UIImageJPEGRepresentation(image, 1.0)]];
|
||||
[body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[request setHTTPBody:body];
|
||||
|
||||
connection = [[NSURLConnection alloc] initWithRequest:(NSURLRequest *)request delegate:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSURLConnectionDelegate
|
||||
|
||||
- (void)connection:(NSURLConnection *)aconnection didFailWithError:(NSError *)error {
|
||||
if(delegate) {
|
||||
[delegate imageSharingError:self error:error];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
|
||||
if(upload && delegate) {
|
||||
[delegate imageSharingProgress:self progress:(float)totalBytesWritten/(float)totalBytesExpectedToWrite];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)adata {
|
||||
[data appendData:adata];
|
||||
if(!upload && delegate) {
|
||||
[delegate imageSharingProgress:self progress:(float)data.length/(float)totalBytesExpectedToRead];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *) response;
|
||||
statusCode = httpResponse.statusCode;
|
||||
LOGI(@"File transfer status code [%i]", statusCode);
|
||||
|
||||
if (statusCode == 200 && !upload) {
|
||||
totalBytesExpectedToRead = (int)[response expectedContentLength];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
if(statusCode >= 400) {
|
||||
NSError *error = [NSError errorWithDomain:@"ImageSharing" code:statusCode userInfo:nil];
|
||||
if(delegate) {
|
||||
[delegate imageSharingError:self error:error];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (upload) {
|
||||
NSString* imageRemoteUrl = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
LOGI(@"File can be downloaded from [%@]", imageRemoteUrl);
|
||||
if(delegate) {
|
||||
[delegate imageSharingUploadDone:self url:[NSURL URLWithString:imageRemoteUrl]];
|
||||
}
|
||||
} else {
|
||||
UIImage* image = [UIImage imageWithData:data];
|
||||
LOGI(@"File downloaded");
|
||||
if(delegate) {
|
||||
[delegate imageSharingDownloadDone:self image:image];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -693,7 +693,7 @@ extern void linphone_iphone_log_handler(int lev, const char *fmt, va_list args);
|
|||
|
||||
NSString* sharing_server = [self stringForKey:@"sharing_server_preference"];
|
||||
[[LinphoneManager instance] lpConfigSetString:sharing_server forKey:@"sharing_server_preference"];
|
||||
|
||||
linphone_core_set_file_transfer_server(lc, [sharing_server UTF8String]);
|
||||
|
||||
//Tunnel
|
||||
if (linphone_core_tunnel_available()){
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ extern NSString *const kLinphoneBluetoothAvailabilityUpdate;
|
|||
extern NSString *const kLinphoneConfiguringStateUpdate;
|
||||
extern NSString *const kLinphoneGlobalStateUpdate;
|
||||
extern NSString *const kLinphoneNotifyReceived;
|
||||
extern NSString *const kLinphoneFileTransferSendUpdate;
|
||||
extern NSString *const kLinphoneFileTransferRecvUpdate;
|
||||
|
||||
typedef enum _NetworkType {
|
||||
network_none = 0,
|
||||
|
|
@ -98,14 +100,6 @@ 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;
|
||||
|
|
@ -211,5 +205,6 @@ typedef struct _LinphoneManagerSounds {
|
|||
@property (readonly) BOOL wasRemoteProvisioned;
|
||||
@property (readonly) LpConfig *configDb;
|
||||
@property (readonly) InAppProductsManager *iapManager;
|
||||
@end
|
||||
@property(strong, nonatomic) NSMutableArray *fileTransferDelegates;
|
||||
|
||||
@end
|
||||
|
|
@ -68,7 +68,8 @@ NSString *const kLinphoneBluetoothAvailabilityUpdate = @"LinphoneBluetoothAvaila
|
|||
NSString *const kLinphoneConfiguringStateUpdate = @"LinphoneConfiguringStateUpdate";
|
||||
NSString *const kLinphoneGlobalStateUpdate = @"LinphoneGlobalStateUpdate";
|
||||
NSString *const kLinphoneNotifyReceived = @"LinphoneNotifyReceived";
|
||||
|
||||
NSString *const kLinphoneFileTransferSendUpdate = @"LinphoneFileTransferSendUpdate";
|
||||
NSString *const kLinphoneFileTransferRecvUpdate = @"LinphoneFileTransferRecvUpdate";
|
||||
|
||||
const int kLinphoneAudioVbrCodecDefaultBitrate=36; /*you can override this from linphonerc or linphonerc-factory*/
|
||||
|
||||
|
|
@ -273,6 +274,7 @@ struct codec_name_pref_table codec_pref_table[]={
|
|||
bluetoothEnabled = FALSE;
|
||||
tunnelMode = FALSE;
|
||||
|
||||
_fileTransferDelegates = [[NSMutableArray alloc] init];
|
||||
|
||||
pushCallIDs = [[NSMutableArray alloc] init ];
|
||||
photoLibrary = [[ALAssetsLibrary alloc] init];
|
||||
|
|
@ -915,29 +917,6 @@ 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 {
|
||||
|
|
@ -1228,11 +1207,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,
|
||||
.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
|
||||
|
||||
.notify_received = linphone_iphone_notify_received
|
||||
};
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4514" systemVersion="13B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIChatRoomCell">
|
||||
|
|
@ -9,9 +10,11 @@
|
|||
<outlet property="backgroundImage" destination="3" id="11"/>
|
||||
<outlet property="backgroundView" destination="7" id="10"/>
|
||||
<outlet property="bubbleView" destination="16" id="30"/>
|
||||
<outlet property="cancelButton" destination="fGh-KI-efm" id="R65-2g-q7P"/>
|
||||
<outlet property="dateLabel" destination="22" id="24"/>
|
||||
<outlet property="deleteButton" destination="18" id="19"/>
|
||||
<outlet property="downloadButton" destination="33" id="34"/>
|
||||
<outlet property="fileTransferProgress" destination="Pd7-2N-Jg3" id="sct-Jr-HnV"/>
|
||||
<outlet property="innerView" destination="2" id="25"/>
|
||||
<outlet property="messageImageView" destination="28" id="31"/>
|
||||
<outlet property="messageText" destination="43" id="44"/>
|
||||
|
|
@ -54,6 +57,7 @@
|
|||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="33" userLabel="downloadButton">
|
||||
<rect key="frame" x="81" y="33" width="132" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Download"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<state key="normal" title="Download image">
|
||||
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -66,11 +70,31 @@
|
|||
<action selector="onDownloadClick:" destination="-1" eventType="touchUpInside" id="39"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="fGh-KI-efm" userLabel="cancelButton">
|
||||
<rect key="frame" x="81" y="34" width="132" height="37"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel transfer"/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||
<state key="normal" title="Cancel transfer">
|
||||
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<state key="highlighted">
|
||||
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
<connections>
|
||||
<action selector="onCancelDownloadClick:" destination="-1" eventType="touchUpInside" id="Ag3-jA-20G"/>
|
||||
</connections>
|
||||
</button>
|
||||
<progressView hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" id="Pd7-2N-Jg3" userLabel="fileTransferProgress">
|
||||
<rect key="frame" x="15" y="94" width="264" height="2"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
</progressView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<label opaque="NO" clipsSubviews="YES" contentMode="left" text="09/09/2009 at 09:09" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="8" adjustsFontSizeToFit="NO" id="22" userLabel="timestampLabel">
|
||||
<rect key="frame" x="0.0" y="104" width="280" height="10"/>
|
||||
<rect key="frame" x="4" y="104" width="274" height="10"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="9"/>
|
||||
|
|
@ -103,16 +127,23 @@
|
|||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<rect key="contentStretch" x="0.0" y="0.0" width="0.59999999999999964" height="1"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="7" userLabel="backgroundView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" id="9" userLabel="selectedBackgroundView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
|
|
@ -121,4 +152,9 @@
|
|||
<image name="list_delete_default.png" width="45" height="45"/>
|
||||
<image name="list_delete_over.png" width="45" height="45"/>
|
||||
</resources>
|
||||
</document>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
<simulatedScreenMetrics key="destination" type="retina4"/>
|
||||
</simulatedMetricsContainer>
|
||||
</document>
|
||||
|
|
|
|||
|
|
@ -106,11 +106,12 @@
|
|||
|
||||
if( last_message ){
|
||||
|
||||
const char* text = linphone_chat_message_get_text(last_message);
|
||||
const char* url = linphone_chat_message_get_external_body_url(last_message);
|
||||
// Message
|
||||
if(url) {
|
||||
[chatContentLabel setText:@""];
|
||||
const char* text = linphone_chat_message_get_text(last_message);
|
||||
const char* url = linphone_chat_message_get_external_body_url(last_message);
|
||||
const LinphoneContent *last_content = linphone_chat_message_get_file_transfer_information(last_message);
|
||||
// Message
|
||||
if(url||last_content) {
|
||||
[chatContentLabel setText:@"🗻"];
|
||||
} else if (text) {
|
||||
NSString *message = [NSString stringWithUTF8String:text];
|
||||
// shorten long messages
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#import "UITransparentTVCell.h"
|
||||
#import "UITextViewNoDefine.h"
|
||||
#include "linphone/linphonecore.h"
|
||||
|
||||
#import "FileTransferDelegate.h"
|
||||
|
||||
@interface UIChatRoomCell : UITransparentTVCell {
|
||||
LinphoneChatMessage* chat;
|
||||
|
|
@ -41,6 +41,8 @@
|
|||
@property (nonatomic, strong) IBOutlet UIButton* downloadButton;
|
||||
@property (nonatomic, strong) IBOutlet UITapGestureRecognizer* imageTapGestureRecognizer;
|
||||
@property (nonatomic, strong) IBOutlet UITapGestureRecognizer* resendTapGestureRecognizer;
|
||||
@property (weak, nonatomic) IBOutlet UIProgressView *fileTransferProgress;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *cancelButton;
|
||||
|
||||
- (id)initWithIdentifier:(NSString*)identifier;
|
||||
+ (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width;
|
||||
|
|
@ -50,7 +52,10 @@
|
|||
- (IBAction)onDeleteClick:(id)event;
|
||||
- (IBAction)onDownloadClick:(id)event;
|
||||
- (IBAction)onImageClick:(id)event;
|
||||
- (IBAction)onCancelDownloadClick:(id)sender;
|
||||
|
||||
- (void)setChatMessage:(LinphoneChatMessage*)message;
|
||||
|
||||
- (void)connectToFileDelegate:(FileTransferDelegate*)ftd;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@
|
|||
#import <NinePatch.h>
|
||||
#include "linphone/linphonecore.h"
|
||||
|
||||
@implementation UIChatRoomCell
|
||||
@implementation UIChatRoomCell {
|
||||
FileTransferDelegate* ftd;
|
||||
}
|
||||
|
||||
@synthesize innerView;
|
||||
@synthesize bubbleView;
|
||||
|
|
@ -56,304 +58,395 @@ static UIFont *CELL_FONT = nil;
|
|||
#pragma mark - Lifecycle Functions
|
||||
|
||||
- (id)initWithIdentifier:(NSString*)identifier {
|
||||
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
|
||||
[[NSBundle mainBundle] loadNibNamed:@"UIChatRoomCell"
|
||||
owner:self
|
||||
options:nil];
|
||||
imageTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageClick:)];
|
||||
[messageImageView addGestureRecognizer:imageTapGestureRecognizer];
|
||||
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
|
||||
[[NSBundle mainBundle] loadNibNamed:@"UIChatRoomCell"
|
||||
owner:self
|
||||
options:nil];
|
||||
imageTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onImageClick:)];
|
||||
[messageImageView addGestureRecognizer:imageTapGestureRecognizer];
|
||||
|
||||
resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)];
|
||||
[dateLabel addGestureRecognizer:resendTapGestureRecognizer];
|
||||
resendTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onResendClick:)];
|
||||
[dateLabel addGestureRecognizer:resendTapGestureRecognizer];
|
||||
|
||||
[self addSubview:innerView];
|
||||
[deleteButton setAlpha:0.0f];
|
||||
[self addSubview:innerView];
|
||||
[deleteButton setAlpha:0.0f];
|
||||
|
||||
// shift message box, otherwise it will collide with the bubble
|
||||
CGRect messageCoords = [messageText frame];
|
||||
messageCoords.origin.x += 2;
|
||||
messageCoords.origin.y += 2;
|
||||
messageCoords.size.width -= 5;
|
||||
[messageText setFrame:messageCoords];
|
||||
messageText.allowSelectAll = TRUE;
|
||||
}
|
||||
return self;
|
||||
// shift message box, otherwise it will collide with the bubble
|
||||
CGRect messageCoords = [messageText frame];
|
||||
messageCoords.origin.x += 2;
|
||||
messageCoords.origin.y += 2;
|
||||
messageCoords.size.width -= 5;
|
||||
[messageText setFrame:messageCoords];
|
||||
messageText.allowSelectAll = TRUE;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self disconnectFromFileDelegate];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)setChatMessage:(LinphoneChatMessage *)message {
|
||||
self->chat = message;
|
||||
[self update];
|
||||
if (message != self->chat) {
|
||||
self->chat = message;
|
||||
messageImageView.image = nil;
|
||||
[self disconnectFromFileDelegate];
|
||||
for (FileTransferDelegate *aftd in [[LinphoneManager instance] fileTransferDelegates]) {
|
||||
if (message &&
|
||||
linphone_chat_message_get_storage_id(aftd.message) == linphone_chat_message_get_storage_id(message)) {
|
||||
LOGI(@"Chat message [%p] with file transfer delegate [%p], connecting to it!", message,
|
||||
linphone_chat_message_get_user_data(message));
|
||||
[self connectToFileDelegate:aftd];
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self update];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+ (NSString*)decodeTextMessage:(const char*)text {
|
||||
NSString* decoded = [NSString stringWithUTF8String:text];
|
||||
if( decoded == nil ){
|
||||
// couldn't decode the string as UTF8, do a lossy conversion
|
||||
decoded = [NSString stringWithCString:text encoding:NSASCIIStringEncoding];
|
||||
if( decoded == nil ){
|
||||
decoded = @"(invalid string)";
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
NSString* decoded = [NSString stringWithUTF8String:text];
|
||||
if( decoded == nil ){
|
||||
// couldn't decode the string as UTF8, do a lossy conversion
|
||||
decoded = [NSString stringWithCString:text encoding:NSASCIIStringEncoding];
|
||||
if( decoded == nil ){
|
||||
decoded = @"(invalid string)";
|
||||
}
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
|
||||
- (void)update {
|
||||
if(chat == nil) {
|
||||
LOGW(@"Cannot update chat room cell: null chat");
|
||||
return;
|
||||
}
|
||||
const char* url = linphone_chat_message_get_external_body_url(chat);
|
||||
const char* text = linphone_chat_message_get_text(chat);
|
||||
BOOL is_external = url && (strstr(url, "http") == url);
|
||||
NSString* localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
if(chat == nil) {
|
||||
LOGW(@"Cannot update chat room cell: null chat");
|
||||
return;
|
||||
}
|
||||
const char* url = linphone_chat_message_get_external_body_url(chat);
|
||||
const char* text = linphone_chat_message_get_text(chat);
|
||||
BOOL is_external =
|
||||
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(chat);
|
||||
NSString* localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:chat];
|
||||
|
||||
// this is an image (either to download or already downloaded)
|
||||
if (is_external || localImage) {
|
||||
if(localImage) {
|
||||
if (messageImageView.image == nil) {
|
||||
NSURL *imageUrl = [NSURL URLWithString:localImage];
|
||||
messageText.hidden = YES;
|
||||
[messageImageView startLoading];
|
||||
__block LinphoneChatMessage *achat = chat;
|
||||
[[LinphoneManager instance]
|
||||
.photoLibrary assetForURL:imageUrl
|
||||
resultBlock:^(ALAsset *asset) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
|
||||
^(void) {
|
||||
if (achat == self->chat) { // Avoid glitch and scrolling
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[messageImageView setImage:image];
|
||||
[messageImageView setFullImageUrl:asset];
|
||||
[messageImageView stopLoading];
|
||||
messageImageView.hidden = NO;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read image");
|
||||
}];
|
||||
}
|
||||
if (ftd.message != nil) {
|
||||
_cancelButton.hidden = NO;
|
||||
_fileTransferProgress.hidden = NO;
|
||||
downloadButton.hidden = YES;
|
||||
} else {
|
||||
_cancelButton.hidden = _fileTransferProgress.hidden = downloadButton.hidden = YES;
|
||||
}
|
||||
} else {
|
||||
messageText.hidden = YES;
|
||||
messageImageView.hidden = _cancelButton.hidden = _fileTransferProgress.hidden = (ftd.message == nil);
|
||||
downloadButton.hidden = !_cancelButton.hidden;
|
||||
}
|
||||
// simple text message
|
||||
} else {
|
||||
[messageText setHidden:FALSE];
|
||||
if ( text ){
|
||||
NSString* nstext = [UIChatRoomCell decodeTextMessage:text];
|
||||
|
||||
if(is_external && !localImage ) {
|
||||
[messageText setHidden:TRUE];
|
||||
[messageImageView setImage:nil];
|
||||
[messageImageView setHidden:TRUE];
|
||||
[downloadButton setHidden:FALSE];
|
||||
/* We need to use an attributed string here so that data detector don't mess
|
||||
* with the text style. See http://stackoverflow.com/a/20669356 */
|
||||
|
||||
} else if(localImage) {
|
||||
NSAttributedString* attr_text = [[NSAttributedString alloc]
|
||||
initWithString:nstext
|
||||
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0],
|
||||
NSForegroundColorAttributeName:[UIColor darkGrayColor]}];
|
||||
messageText.attributedText = attr_text;
|
||||
|
||||
NSURL* imageUrl = [NSURL URLWithString:localImage];
|
||||
} else {
|
||||
messageText.text = @"";
|
||||
}
|
||||
messageImageView.hidden = YES;
|
||||
_cancelButton.hidden = _fileTransferProgress.hidden = downloadButton.hidden = YES;
|
||||
}
|
||||
|
||||
[messageText setHidden:TRUE];
|
||||
[messageImageView setImage:nil];
|
||||
[messageImageView startLoading];
|
||||
__block LinphoneChatMessage *achat = chat;
|
||||
[[LinphoneManager instance].photoLibrary assetForURL:imageUrl resultBlock:^(ALAsset *asset) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) {
|
||||
if(achat == self->chat) { //Avoid glitch and scrolling
|
||||
UIImage* image = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[messageImageView setImage:image];
|
||||
[messageImageView setFullImageUrl:asset];
|
||||
[messageImageView stopLoading];
|
||||
});
|
||||
}
|
||||
});
|
||||
} failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read image");
|
||||
}];
|
||||
// Date
|
||||
time_t chattime = linphone_chat_message_get_time(chat);
|
||||
NSDate *message_date = (chattime == 0) ? [[NSDate alloc] init] : [NSDate dateWithTimeIntervalSince1970:chattime];
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
|
||||
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
|
||||
NSLocale *locale = [NSLocale currentLocale];
|
||||
[dateFormatter setLocale:locale];
|
||||
[dateLabel setText:[dateFormatter stringFromDate:message_date]];
|
||||
|
||||
[messageImageView setHidden:FALSE];
|
||||
[downloadButton setHidden:TRUE];
|
||||
} else {
|
||||
// simple text message
|
||||
[messageText setHidden:FALSE];
|
||||
if ( text ){
|
||||
NSString* nstext = [UIChatRoomCell decodeTextMessage:text];
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(chat);
|
||||
BOOL outgoing = linphone_chat_message_is_outgoing(chat);
|
||||
|
||||
/* We need to use an attributed string here so that data detector don't mess
|
||||
* with the text style. See http://stackoverflow.com/a/20669356 */
|
||||
|
||||
NSAttributedString* attr_text = [[NSAttributedString alloc]
|
||||
initWithString:nstext
|
||||
attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:17.0],
|
||||
NSForegroundColorAttributeName:[UIColor darkGrayColor]}];
|
||||
messageText.attributedText = attr_text;
|
||||
|
||||
} else {
|
||||
messageText.text = @"";
|
||||
}
|
||||
|
||||
[messageImageView setImage:nil];
|
||||
[messageImageView setHidden:TRUE];
|
||||
|
||||
[downloadButton setHidden:TRUE];
|
||||
}
|
||||
|
||||
// Date
|
||||
NSDate* message_date = [NSDate dateWithTimeIntervalSince1970:linphone_chat_message_get_time(chat)];
|
||||
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
|
||||
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
|
||||
NSLocale *locale = [NSLocale currentLocale];
|
||||
[dateFormatter setLocale:locale];
|
||||
[dateLabel setText:[dateFormatter stringFromDate:message_date]];
|
||||
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(chat);
|
||||
BOOL outgoing = linphone_chat_message_is_outgoing(chat);
|
||||
|
||||
if( !outgoing ){
|
||||
statusImage.hidden = TRUE; // not useful for incoming chats..
|
||||
} else if (state== LinphoneChatMessageStateInProgress) {
|
||||
if( !outgoing ){
|
||||
statusImage.hidden = TRUE; // not useful for incoming chats..
|
||||
} else if (state== LinphoneChatMessageStateInProgress) {
|
||||
[statusImage setImage:[UIImage imageNamed:@"chat_message_inprogress.png"]];
|
||||
[statusImage setAccessibilityValue:@"in progress"];
|
||||
[statusImage setAccessibilityValue:@"in progress"];
|
||||
statusImage.hidden = FALSE;
|
||||
} else if (state == LinphoneChatMessageStateDelivered) {
|
||||
} else if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateFileTransferDone) {
|
||||
[statusImage setImage:[UIImage imageNamed:@"chat_message_delivered.png"]];
|
||||
[statusImage setAccessibilityValue:@"delivered"];
|
||||
[statusImage setAccessibilityValue:@"delivered"];
|
||||
statusImage.hidden = FALSE;
|
||||
} else {
|
||||
[statusImage setImage:[UIImage imageNamed:@"chat_message_not_delivered.png"]];
|
||||
[statusImage setAccessibilityValue:@"not delivered"];
|
||||
[statusImage setAccessibilityValue:@"not delivered"];
|
||||
statusImage.hidden = FALSE;
|
||||
|
||||
NSAttributedString* resend_text = [[NSAttributedString alloc]
|
||||
initWithString:NSLocalizedString(@"Resend", @"Resend")
|
||||
attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}];
|
||||
[dateLabel setAttributedText:resend_text];
|
||||
NSAttributedString* resend_text = [[NSAttributedString alloc]
|
||||
initWithString:NSLocalizedString(@"Resend", @"Resend")
|
||||
attributes:@{NSForegroundColorAttributeName: [UIColor redColor]}];
|
||||
[dateLabel setAttributedText:resend_text];
|
||||
}
|
||||
|
||||
if( outgoing){
|
||||
[messageText setAccessibilityLabel:@"Outgoing message"];
|
||||
} else {
|
||||
[messageText setAccessibilityLabel:@"Incoming message"];
|
||||
}
|
||||
|
||||
if( outgoing){
|
||||
[messageText setAccessibilityLabel:@"Outgoing message"];
|
||||
} else {
|
||||
[messageText setAccessibilityLabel:@"Incoming message"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEditing:(BOOL)editing {
|
||||
[self setEditing:editing animated:FALSE];
|
||||
[self setEditing:editing animated:FALSE];
|
||||
}
|
||||
|
||||
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
|
||||
if(animated) {
|
||||
[UIView beginAnimations:nil context:nil];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
}
|
||||
if(editing) {
|
||||
[deleteButton setAlpha:1.0f];
|
||||
} else {
|
||||
[deleteButton setAlpha:0.0f];
|
||||
}
|
||||
if(animated) {
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
if(animated) {
|
||||
[UIView beginAnimations:nil context:nil];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
}
|
||||
if(editing) {
|
||||
[deleteButton setAlpha:1.0f];
|
||||
} else {
|
||||
[deleteButton setAlpha:0.0f];
|
||||
}
|
||||
if(animated) {
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
}
|
||||
|
||||
+ (CGSize)viewSize:(LinphoneChatMessage*)chat width:(int)width {
|
||||
CGSize messageSize;
|
||||
const char* url = linphone_chat_message_get_external_body_url(chat);
|
||||
const char* text = linphone_chat_message_get_text(chat);
|
||||
NSString* messageText = text ? [UIChatRoomCell decodeTextMessage:text] : @"";
|
||||
if(url == nil) {
|
||||
if(CELL_FONT == nil) {
|
||||
CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE];
|
||||
}
|
||||
CGSize messageSize;
|
||||
const char* url = linphone_chat_message_get_external_body_url(chat);
|
||||
const char* text = linphone_chat_message_get_text(chat);
|
||||
NSString* messageText = text ? [UIChatRoomCell decodeTextMessage:text] : @"";
|
||||
if (url == nil && linphone_chat_message_get_file_transfer_information(chat) == NULL) {
|
||||
if(CELL_FONT == nil) {
|
||||
CELL_FONT = [UIFont systemFontOfSize:CELL_FONT_SIZE];
|
||||
}
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
|
||||
|
||||
if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7){
|
||||
messageSize = [messageText
|
||||
boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX)
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading)
|
||||
attributes:@{NSFontAttributeName: CELL_FONT}
|
||||
context:nil].size;
|
||||
} else
|
||||
if( [[[UIDevice currentDevice] systemVersion] doubleValue] >= 7){
|
||||
messageSize = [messageText
|
||||
boundingRectWithSize:CGSizeMake(width - CELL_MESSAGE_X_MARGIN, CGFLOAT_MAX)
|
||||
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesFontLeading)
|
||||
attributes:@{NSFontAttributeName: CELL_FONT}
|
||||
context:nil].size;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
messageSize = [messageText sizeWithFont: CELL_FONT
|
||||
constrainedToSize: CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f)
|
||||
lineBreakMode: NSLineBreakByTruncatingTail];
|
||||
}
|
||||
} else {
|
||||
messageSize = CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT);
|
||||
}
|
||||
messageSize.height += CELL_MESSAGE_Y_MARGIN;
|
||||
if(messageSize.height < CELL_MIN_HEIGHT)
|
||||
messageSize.height = CELL_MIN_HEIGHT;
|
||||
messageSize.width += CELL_MESSAGE_X_MARGIN;
|
||||
if(messageSize.width < CELL_MIN_WIDTH)
|
||||
messageSize.width = CELL_MIN_WIDTH;
|
||||
return messageSize;
|
||||
{
|
||||
messageSize = [messageText sizeWithFont: CELL_FONT
|
||||
constrainedToSize: CGSizeMake(width - CELL_MESSAGE_X_MARGIN, 10000.0f)
|
||||
lineBreakMode: NSLineBreakByTruncatingTail];
|
||||
}
|
||||
} else {
|
||||
messageSize = CGSizeMake(CELL_IMAGE_WIDTH, CELL_IMAGE_HEIGHT);
|
||||
}
|
||||
messageSize.height += CELL_MESSAGE_Y_MARGIN;
|
||||
if(messageSize.height < CELL_MIN_HEIGHT)
|
||||
messageSize.height = CELL_MIN_HEIGHT;
|
||||
messageSize.width += CELL_MESSAGE_X_MARGIN;
|
||||
if(messageSize.width < CELL_MIN_WIDTH)
|
||||
messageSize.width = CELL_MIN_WIDTH;
|
||||
return messageSize;
|
||||
}
|
||||
|
||||
+ (CGFloat)height:(LinphoneChatMessage*)chatMessage width:(int)width {
|
||||
return [UIChatRoomCell viewSize:chatMessage width:width].height;
|
||||
return [UIChatRoomCell viewSize:chatMessage width:width].height;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - View Functions
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
if(chat != nil) {
|
||||
// Resize inner
|
||||
CGRect innerFrame;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(chat);
|
||||
innerFrame.size = [UIChatRoomCell viewSize:chat width:[self frame].size.width];
|
||||
if(!is_outgoing) { // Inverted
|
||||
innerFrame.origin.x = 0.0f;
|
||||
innerFrame.origin.y = 0.0f;
|
||||
} else {
|
||||
innerFrame.origin.x = [self frame].size.width - innerFrame.size.width;
|
||||
innerFrame.origin.y = 0.0f;
|
||||
}
|
||||
[innerView setFrame:innerFrame];
|
||||
[super layoutSubviews];
|
||||
if(chat != nil) {
|
||||
// Resize inner
|
||||
CGRect innerFrame;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(chat);
|
||||
innerFrame.size = [UIChatRoomCell viewSize:chat width:[self frame].size.width];
|
||||
if(!is_outgoing) { // Inverted
|
||||
innerFrame.origin.x = 0.0f;
|
||||
innerFrame.origin.y = 0.0f;
|
||||
} else {
|
||||
innerFrame.origin.x = [self frame].size.width - innerFrame.size.width;
|
||||
innerFrame.origin.y = 0.0f;
|
||||
}
|
||||
[innerView setFrame:innerFrame];
|
||||
|
||||
CGRect messageFrame = [bubbleView frame];
|
||||
messageFrame.origin.y = ([innerView frame].size.height - messageFrame.size.height)/2;
|
||||
if(!is_outgoing) { // Inverted
|
||||
UIImage* image = [UIImage imageNamed:@"chat_bubble_incoming"];
|
||||
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(26, 32, 34, 56)];
|
||||
[backgroundImage setImage:image];
|
||||
messageFrame.origin.y += 5;
|
||||
} else {
|
||||
UIImage* image = [UIImage imageNamed:@"chat_bubble_outgoing"];
|
||||
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(14, 15, 25, 40)];
|
||||
[backgroundImage setImage:image];
|
||||
messageFrame.origin.y -= 5;
|
||||
}
|
||||
[bubbleView setFrame:messageFrame];
|
||||
}
|
||||
CGRect messageFrame = [bubbleView frame];
|
||||
messageFrame.origin.y = ([innerView frame].size.height - messageFrame.size.height)/2;
|
||||
if(!is_outgoing) { // Inverted
|
||||
UIImage* image = [UIImage imageNamed:@"chat_bubble_incoming"];
|
||||
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(26, 32, 34, 56)];
|
||||
[backgroundImage setImage:image];
|
||||
messageFrame.origin.y += 5;
|
||||
} else {
|
||||
UIImage* image = [UIImage imageNamed:@"chat_bubble_outgoing"];
|
||||
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(14, 15, 25, 40)];
|
||||
[backgroundImage setImage:image];
|
||||
messageFrame.origin.y -= 5;
|
||||
}
|
||||
[bubbleView setFrame:messageFrame];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action Functions
|
||||
|
||||
- (IBAction)onDeleteClick:(id)event {
|
||||
if(chat != NULL) {
|
||||
UIView *view = [self superview];
|
||||
// Find TableViewCell
|
||||
while(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview];
|
||||
if(view != nil) {
|
||||
UITableView *tableView = (UITableView*) view;
|
||||
NSIndexPath *indexPath = [tableView indexPathForCell:self];
|
||||
[[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
if(chat != NULL) {
|
||||
if (ftd.message != nil) {
|
||||
[ftd cancel];
|
||||
}
|
||||
UIView *view = [self superview];
|
||||
// Find TableViewCell
|
||||
while(view != nil && ![view isKindOfClass:[UITableView class]]) view = [view superview];
|
||||
if(view != nil) {
|
||||
UITableView *tableView = (UITableView*) view;
|
||||
NSIndexPath *indexPath = [tableView indexPathForCell:self];
|
||||
[[tableView dataSource] tableView:tableView commitEditingStyle:UITableViewCellEditingStyleDelete forRowAtIndexPath:indexPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onDownloadClick:(id)event {
|
||||
[chatRoomDelegate chatRoomStartImageDownload:chat];
|
||||
if (ftd.message == nil) {
|
||||
ftd = [[FileTransferDelegate alloc] init];
|
||||
[[[LinphoneManager instance] fileTransferDelegates] addObject:ftd];
|
||||
[self connectToFileDelegate:ftd];
|
||||
[ftd download:chat];
|
||||
_cancelButton.hidden = NO;
|
||||
downloadButton.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)onCancelDownloadClick:(id)sender {
|
||||
[ftd cancel];
|
||||
[self disconnectFromFileDelegate];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)onImageClick:(id)event {
|
||||
if(![messageImageView isLoading]) {
|
||||
ImageViewController *controller = DYNAMIC_CAST([[PhoneMainView instance] changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], ImageViewController);
|
||||
if(controller != nil) {
|
||||
CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage];
|
||||
UIImage* fullScreen = [UIImage imageWithCGImage:fullScreenRef];
|
||||
[controller setImage:fullScreen];
|
||||
}
|
||||
}
|
||||
// if(![messageImageView isLoading]) {
|
||||
// ImageViewController *controller = DYNAMIC_CAST([[PhoneMainView instance]
|
||||
// changeCurrentView:[ImageViewController compositeViewDescription] push:TRUE], ImageViewController);
|
||||
// if(controller != nil) {
|
||||
// CGImageRef fullScreenRef = [[messageImageView.fullImageUrl defaultRepresentation] fullScreenImage];
|
||||
// UIImage* fullScreen = [UIImage imageWithCGImage:fullScreenRef];
|
||||
// [controller setImage:fullScreen];
|
||||
// }
|
||||
// }
|
||||
|
||||
[LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:chat];
|
||||
}
|
||||
|
||||
- (IBAction)onResendClick:(id)event {
|
||||
if( chat == nil ) return;
|
||||
if( chat == nil ) return;
|
||||
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat);
|
||||
if (state == LinphoneChatMessageStateNotDelivered) {
|
||||
const char* text = linphone_chat_message_get_text(self->chat);
|
||||
const char* url = linphone_chat_message_get_external_body_url(self->chat);
|
||||
NSString* message = text ? [NSString stringWithUTF8String:text] : nil;
|
||||
NSString* exturl = url ? [NSString stringWithUTF8String:url] : nil;
|
||||
LinphoneChatMessageState state = linphone_chat_message_get_state(self->chat);
|
||||
if (state == LinphoneChatMessageStateNotDelivered) {
|
||||
const char* text = linphone_chat_message_get_text(self->chat);
|
||||
const char* url = linphone_chat_message_get_external_body_url(self->chat);
|
||||
NSString* message = text ? [NSString stringWithUTF8String:text] : nil;
|
||||
NSString* exturl = url ? [NSString stringWithUTF8String:url] : nil;
|
||||
|
||||
[self onDeleteClick:nil];
|
||||
[self onDeleteClick:nil];
|
||||
|
||||
double delayInSeconds = 0.4;
|
||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
|
||||
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
|
||||
[chatRoomDelegate resendChat:message withExternalUrl:exturl];
|
||||
});
|
||||
}
|
||||
double delayInSeconds = 0.4;
|
||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
|
||||
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
|
||||
[chatRoomDelegate resendChat:message withExternalUrl:exturl];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - LinphoneFileTransfer Notifications Handling
|
||||
|
||||
- (void)connectToFileDelegate:(FileTransferDelegate*)aftd {
|
||||
ftd = aftd;
|
||||
_fileTransferProgress.progress = 0;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onFileTransferSendUpdate:)
|
||||
name:kLinphoneFileTransferSendUpdate
|
||||
object:ftd];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(onFileTransferRecvUpdate:)
|
||||
name:kLinphoneFileTransferRecvUpdate
|
||||
object:ftd];
|
||||
}
|
||||
|
||||
- (void)disconnectFromFileDelegate {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
ftd = nil;
|
||||
}
|
||||
|
||||
- (void)onFileTransferSendUpdate:(NSNotification*)notif {
|
||||
LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue];
|
||||
|
||||
if (state == LinphoneChatMessageStateInProgress) {
|
||||
float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue];
|
||||
// When uploading a file, the message file is first uploaded to the server,
|
||||
// so we are in progress state. Then state goes to filetransfertdone. Then,
|
||||
// the exact same message is sent to the other chat participant and we come
|
||||
// back to in progress again. This second time is NOT an upload, so we must
|
||||
// not update progress!
|
||||
_fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress);
|
||||
_fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f);
|
||||
} else {
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
- (void)onFileTransferRecvUpdate:(NSNotification*)notif {
|
||||
LinphoneChatMessageState state = [[[notif userInfo] objectForKey:@"state"] intValue];
|
||||
if (state == LinphoneChatMessageStateInProgress) {
|
||||
float progress = [[[notif userInfo] objectForKey:@"progress"] floatValue];
|
||||
_fileTransferProgress.progress = MAX(_fileTransferProgress.progress, progress);
|
||||
_fileTransferProgress.hidden = _cancelButton.hidden = (_fileTransferProgress.progress == 1.f);
|
||||
} else {
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
20
Classes/Utils/FileTransferDelegate.h
Normal file
20
Classes/Utils/FileTransferDelegate.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// FileTransferDelegate.h
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 10/06/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "LinphoneManager.h"
|
||||
|
||||
@interface FileTransferDelegate : NSObject
|
||||
|
||||
- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom;
|
||||
- (void)cancel;
|
||||
- (BOOL)download:(LinphoneChatMessage *)message;
|
||||
|
||||
@property() LinphoneChatMessage *message;
|
||||
@end
|
||||
207
Classes/Utils/FileTransferDelegate.m
Normal file
207
Classes/Utils/FileTransferDelegate.m
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
//
|
||||
// FileTransferDelegate.m
|
||||
// linphone
|
||||
//
|
||||
// Created by Gautier Pelloux-Prayer on 10/06/15.
|
||||
//
|
||||
//
|
||||
|
||||
#import "FileTransferDelegate.h"
|
||||
@interface FileTransferDelegate ()
|
||||
@property(strong) NSMutableData *data;
|
||||
@end
|
||||
|
||||
@implementation FileTransferDelegate
|
||||
|
||||
- (void)dealloc {
|
||||
if (_message != nil) {
|
||||
[self cancel];
|
||||
}
|
||||
}
|
||||
|
||||
static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, const LinphoneContent *content,
|
||||
const LinphoneBuffer *buffer) {
|
||||
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message);
|
||||
size_t size = linphone_buffer_get_size(buffer);
|
||||
|
||||
if (!thiz.data) {
|
||||
thiz.data = [[NSMutableData alloc] initWithCapacity:linphone_content_get_size(content)];
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
LOGI(@"Transfer of %s (%d bytes): download finished", linphone_content_get_name(content), size);
|
||||
assert([thiz.data length] == linphone_content_get_size(content));
|
||||
|
||||
// we're finished, save the image and update the message
|
||||
UIImage *image = [UIImage imageWithData:thiz.data];
|
||||
|
||||
|
||||
[[[LinphoneManager instance] fileTransferDelegates] removeObject:thiz];
|
||||
|
||||
[[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];
|
||||
} else {
|
||||
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
|
||||
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString]
|
||||
forKey:@"localimage"
|
||||
inMessage:message];
|
||||
}
|
||||
thiz.message = NULL;
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:kLinphoneFileTransferRecvUpdate
|
||||
object:thiz
|
||||
userInfo:@{
|
||||
@"state" : @(linphone_chat_message_get_state(message)),
|
||||
@"image" : image,
|
||||
@"progress" :
|
||||
@([thiz.data length] * 1.f / linphone_content_get_size(content)),
|
||||
}];
|
||||
|
||||
CFRelease((__bridge CFTypeRef)thiz);
|
||||
}];
|
||||
} else {
|
||||
LOGI(@"Transfer of %s (%d bytes): already %ld sent, adding %ld", linphone_content_get_name(content),
|
||||
linphone_content_get_size(content), [thiz.data length], size);
|
||||
[thiz.data appendBytes:linphone_buffer_get_string_content(buffer) length:size];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:kLinphoneFileTransferRecvUpdate
|
||||
object:thiz
|
||||
userInfo:@{
|
||||
@"state" : @(linphone_chat_message_get_state(message)),
|
||||
@"progress" : @([thiz.data length] * 1.f / linphone_content_get_size(content)),
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *message, const LinphoneContent *content,
|
||||
size_t offset, size_t size) {
|
||||
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(message);
|
||||
size_t total = thiz.data.length;
|
||||
if (thiz.data) {
|
||||
size_t remaining = total - offset;
|
||||
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:@{
|
||||
@"state" : @(linphone_chat_message_get_state(message)),
|
||||
@"progress" : @(offset * 1.f / total),
|
||||
}];
|
||||
LOGI(@"Transfer of %s (%d bytes): already sent %ld, remaining %ld", linphone_content_get_name(content), total,
|
||||
offset, remaining);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kLinphoneFileTransferSendUpdate
|
||||
object:thiz
|
||||
userInfo:dict];
|
||||
@try {
|
||||
return linphone_buffer_new_from_data([thiz.data subdataWithRange:NSMakeRange(offset, size)].bytes, size);
|
||||
} @catch (NSException *exception) {
|
||||
LOGE(@"Exception: %@", exception);
|
||||
}
|
||||
} else {
|
||||
LOGE(@"Transfer of %s (%d bytes): %d Error - no upload data in progress!", linphone_content_get_name(content),
|
||||
total, offset);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void message_status(LinphoneChatMessage *msg, LinphoneChatMessageState state) {
|
||||
FileTransferDelegate *thiz = (__bridge FileTransferDelegate *)linphone_chat_message_get_user_data(msg);
|
||||
|
||||
NSString *notification =
|
||||
linphone_chat_message_is_outgoing(msg) ? kLinphoneFileTransferSendUpdate : kLinphoneFileTransferRecvUpdate;
|
||||
|
||||
const char *text = (linphone_chat_message_get_file_transfer_information(msg) != NULL)
|
||||
? "photo transfer"
|
||||
: linphone_chat_message_get_text(msg);
|
||||
LOGI(@"Delivery status for [%s] is [%s]", text, linphone_chat_message_state_to_string(state));
|
||||
|
||||
NSDictionary *dict = @{ @"state" : @(state), @"progress" : @0.f };
|
||||
if (state == LinphoneChatMessageStateFileTransferDone || state == LinphoneChatMessageStateFileTransferError) {
|
||||
thiz.message = NULL;
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:notification object:thiz userInfo:dict];
|
||||
if (linphone_chat_message_is_outgoing(msg)) {
|
||||
[thiz stopAndDestroy];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom {
|
||||
LinphoneContent *content = linphone_core_create_content(linphone_chat_room_get_lc(chatRoom));
|
||||
_data = [NSMutableData dataWithData: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, [_data length]);
|
||||
|
||||
CFTypeRef myself = (__bridge CFTypeRef)self;
|
||||
_message = linphone_chat_room_create_file_transfer_message(chatRoom, content);
|
||||
linphone_chat_message_ref(_message);
|
||||
linphone_chat_message_set_user_data(_message, (void *)CFRetain(myself));
|
||||
linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message),
|
||||
linphone_iphone_file_transfer_send);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status);
|
||||
|
||||
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_chat_message(chatRoom, _message);
|
||||
}
|
||||
|
||||
- (BOOL)download:(LinphoneChatMessage *)message {
|
||||
_message = message;
|
||||
// we need to keep a ref on the message to continue downloading even if user quit a chatroom which destroy all chat
|
||||
// messages
|
||||
linphone_chat_message_ref(_message);
|
||||
const char *url = linphone_chat_message_get_external_body_url(_message);
|
||||
LOGI(@"Content to download: %s", url);
|
||||
|
||||
if (url == nil)
|
||||
return FALSE;
|
||||
|
||||
linphone_chat_message_set_user_data(_message, (void *)CFBridgingRetain(self));
|
||||
|
||||
linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message),
|
||||
linphone_iphone_file_transfer_recv);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), message_status);
|
||||
|
||||
linphone_chat_message_download_file(_message);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)stopAndDestroy {
|
||||
[[[LinphoneManager instance] fileTransferDelegates] removeObject:self];
|
||||
if (_message != NULL) {
|
||||
linphone_chat_message_set_user_data(_message, NULL);
|
||||
|
||||
linphone_chat_message_cbs_set_file_transfer_progress_indication(linphone_chat_message_get_callbacks(_message),
|
||||
NULL);
|
||||
linphone_chat_message_cbs_set_file_transfer_recv(linphone_chat_message_get_callbacks(_message), NULL);
|
||||
linphone_chat_message_cbs_set_msg_state_changed(linphone_chat_message_get_callbacks(_message), NULL);
|
||||
linphone_chat_message_cancel_file_transfer(_message);
|
||||
linphone_chat_message_unref(_message);
|
||||
}
|
||||
_message = nil;
|
||||
_data = nil;
|
||||
}
|
||||
|
||||
- (void)cancel {
|
||||
[self stopAndDestroy];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -29,7 +29,10 @@
|
|||
OrtpLogLevel ortp_severity;
|
||||
int filesize = 20;
|
||||
if (severity <= LinphoneLoggerDebug) {
|
||||
ortp_severity = ORTP_DEBUG;
|
||||
// lol: ortp_debug(XXX) can be disabled at compile time, but ortp_log(ORTP_DEBUG, xxx) will always be valid even
|
||||
// not in debug build...
|
||||
ortp_debug("%*s:%3d - %s", filesize, file+MAX((int)strlen(file)-filesize,0), line, [str UTF8String]);
|
||||
return;
|
||||
} else if(severity <= LinphoneLoggerLog) {
|
||||
ortp_severity = ORTP_MESSAGE;
|
||||
} else if(severity <= LinphoneLoggerWarning) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import "ChatTester.h"
|
||||
#include "LinphoneManager.h"
|
||||
#import "UIChatRoomCell.h"
|
||||
|
||||
@implementation ChatTester
|
||||
|
||||
|
|
@ -17,12 +18,36 @@
|
|||
- (void)beforeAll {
|
||||
[super beforeAll];
|
||||
[self switchToValidAccountIfNeeded];
|
||||
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Chat")];
|
||||
}
|
||||
|
||||
- (void)beforeEach {
|
||||
[super beforeEach];
|
||||
if ([tester tryFindingTappableViewWithAccessibilityLabel:LOCALIZED(@"Back") error:nil]) {
|
||||
[self goBackFromChat];
|
||||
}
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Chat")];
|
||||
[self removeAllRooms];
|
||||
}
|
||||
|
||||
- (void)afterAll {
|
||||
// at the end of tests, go back to chat rooms to display main bar
|
||||
if ([tester tryFindingTappableViewWithAccessibilityLabel:LOCALIZED(@"Back") error:nil]) {
|
||||
[self goBackFromChat];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - tools
|
||||
|
||||
- (void)removeAllRooms {
|
||||
[tester tapViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton];
|
||||
while (
|
||||
[tester tryFindingTappableViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton error:nil]) {
|
||||
[tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton];
|
||||
}
|
||||
[tester tapViewWithAccessibilityLabel:@"Edit"
|
||||
traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen
|
||||
}
|
||||
|
||||
- (void)goBackFromChat {
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Back")];
|
||||
}
|
||||
|
|
@ -114,29 +139,91 @@
|
|||
for( int i =0; i< uuids.count; i++){
|
||||
[tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton];
|
||||
}
|
||||
|
||||
// then we try to delete all the rest of chatrooms
|
||||
while ( [tester tryFindingTappableViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton error:nil] )
|
||||
{
|
||||
[tester tapViewWithAccessibilityLabel:@"Delete" traits:UIAccessibilityTraitButton];
|
||||
NSLog(@"Deleting an extra chat");
|
||||
}
|
||||
|
||||
[tester tapViewWithAccessibilityLabel:@"Edit" traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen
|
||||
|
||||
// check that the tableview is empty
|
||||
UITableView* tv = nil;
|
||||
NSError* err = nil;
|
||||
if( [tester tryFindingAccessibilityElement:nil view:&tv withIdentifier:@"ChatRoom list" tappable:false error:&err] ){
|
||||
XCTAssert(tv != nil);
|
||||
XCTAssert([tv numberOfRowsInSection:0] == 0); // no more chat rooms
|
||||
} else {
|
||||
NSLog(@"Error: %@",err);
|
||||
}
|
||||
|
||||
// test that there's no more chatrooms in the core
|
||||
XCTAssert(linphone_core_get_chat_rooms([LinphoneManager getLc]) == nil);
|
||||
|
||||
[tester tapViewWithAccessibilityLabel:@"Edit"
|
||||
traits:UIAccessibilityTraitButton]; // same as the first but it is "OK" on screen
|
||||
|
||||
// check that the tableview is empty
|
||||
UITableView *tv = [self findTableView:@"ChatRoom list"];
|
||||
XCTAssert([tv numberOfRowsInSection:0] == 0);
|
||||
|
||||
// test that there's no more chatrooms in the core
|
||||
XCTAssert(linphone_core_get_chat_rooms([LinphoneManager getLc]) == nil);
|
||||
}
|
||||
|
||||
- (UITableView *)findTableView:(NSString *)table {
|
||||
UITableView *tv = nil;
|
||||
NSError *err = nil;
|
||||
if ([tester tryFindingAccessibilityElement:nil view:&tv withIdentifier:table tappable:false error:&err]) {
|
||||
XCTAssertNotNil(tv);
|
||||
} else {
|
||||
XCTFail(@"Error: %@", err);
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
|
||||
- (void)uploadImage {
|
||||
NSString *user = @"testios";
|
||||
|
||||
[self startChatWith:user];
|
||||
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Send picture")];
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Photo library")];
|
||||
// if popup "Linphone would access your photo" pops up, click OK.
|
||||
if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusNotDetermined) {
|
||||
[tester acknowledgeSystemAlert];
|
||||
}
|
||||
|
||||
[tester choosePhotoInAlbum:@"Camera Roll" atRow:1 column:1];
|
||||
|
||||
// TODO: do not harcode size!
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Minimum (108.9 KB)")];
|
||||
|
||||
UITableView *tv = [self findTableView:@"Chat list"];
|
||||
XCTAssertEqual([tv numberOfRowsInSection:0], 1);
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 1);
|
||||
}
|
||||
|
||||
- (void)testUploadImage {
|
||||
NSString *user = @"testios";
|
||||
|
||||
[self uploadImage];
|
||||
[self goBackFromChat];
|
||||
|
||||
// if we go back to the same chatroom, the message should be still there
|
||||
[self startChatWith:user];
|
||||
UITableView *tv = [self findTableView:@"Chat list"];
|
||||
XCTAssertEqual([tv numberOfRowsInSection:0], 1);
|
||||
|
||||
[tester waitForViewWithAccessibilityLabel:LOCALIZED(@"Download")];
|
||||
|
||||
XCTAssertEqual([tv numberOfRowsInSection:0], 2);
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0);
|
||||
}
|
||||
|
||||
- (void)testCancelUploadImage {
|
||||
[self uploadImage];
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Cancel transfer")];
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0);
|
||||
}
|
||||
|
||||
- (void)downloadImage {
|
||||
[self uploadImage];
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Download")];
|
||||
[tester waitForTimeInterval:.5f]; // just wait a few secs to start download
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 1);
|
||||
}
|
||||
|
||||
- (void)testDownloadImage {
|
||||
[self downloadImage];
|
||||
[tester waitForAbsenceOfViewWithAccessibilityLabel:@"Cancel transfer"];
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0);
|
||||
}
|
||||
|
||||
- (void)testCancelDownloadImage {
|
||||
[self downloadImage];
|
||||
[tester tapViewWithAccessibilityLabel:LOCALIZED(@"Cancel transfer")];
|
||||
XCTAssertEqual([[[LinphoneManager instance] fileTransferDelegates] count], 0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ username_length=4
|
|||
expires=1314000
|
||||
push_notification=1
|
||||
transport=tls
|
||||
sharing_server=https://www.linphone.org:444/upload.php
|
||||
sharing_server=https://www.linphone.org:444/lft.php
|
||||
ice=1
|
||||
stun=stun.linphone.org
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ username_length=4
|
|||
expires=1314000
|
||||
push_notification=1
|
||||
transport=tls
|
||||
sharing_server=https://www.linphone.org:444/upload.php
|
||||
sharing_server=https://www.linphone.org:444/lft.php
|
||||
ice=1
|
||||
stun=stun.linphone.org
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@
|
|||
636316D41A1DEC650009B839 /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D61A1DEC650009B839 /* SettingsViewController.xib */; };
|
||||
636316D91A1DECC90009B839 /* PhoneMainView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 636316D71A1DECC90009B839 /* PhoneMainView.xib */; };
|
||||
636316DE1A1DEF2F0009B839 /* UIButtonShrinkable.m in Sources */ = {isa = PBXBuildFile; fileRef = 636316DD1A1DEF2F0009B839 /* UIButtonShrinkable.m */; };
|
||||
637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 637157A01B283FE200C91677 /* FileTransferDelegate.m */; };
|
||||
639CEAFD1A1DF4D9004DE38F /* UIStateBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEAFF1A1DF4D9004DE38F /* UIStateBar.xib */; };
|
||||
639CEB001A1DF4E4004DE38F /* UIHistoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB021A1DF4E4004DE38F /* UIHistoryCell.xib */; };
|
||||
639CEB031A1DF4EB004DE38F /* UICompositeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 639CEB051A1DF4EB004DE38F /* UICompositeViewController.xib */; };
|
||||
|
|
@ -306,7 +307,6 @@
|
|||
D36C43F7158F61EA0048BA40 /* call_state_play_over.png in Resources */ = {isa = PBXBuildFile; fileRef = D36C43F0158F61EA0048BA40 /* call_state_play_over.png */; };
|
||||
D36FB2D51589EF7C0036F6F2 /* UIPauseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */; };
|
||||
D37295DB158B3C9600D2C0C7 /* video_off_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D37295DA158B3C9600D2C0C7 /* video_off_disabled.png */; };
|
||||
D374D3FD16071762003D25FF /* ImageSharing.m in Sources */ = {isa = PBXBuildFile; fileRef = D374D3FC16071762003D25FF /* ImageSharing.m */; };
|
||||
D377BBFA15A19DA6002B696B /* video_on_disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = D377BBF915A19DA6002B696B /* video_on_disabled.png */; };
|
||||
D378906515AC373B00BD776C /* ContactDetailsLabelViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D378906315AC373B00BD776C /* ContactDetailsLabelViewController.m */; };
|
||||
D378AB2A15DCDB4A0098505D /* ImagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D378AB2915DCDB490098505D /* ImagePickerViewController.m */; };
|
||||
|
|
@ -892,7 +892,6 @@
|
|||
|
||||
/* 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>"; };
|
||||
|
|
@ -1039,6 +1038,8 @@
|
|||
636316DB1A1DEDD80009B839 /* ru */ = {isa = PBXFileReference; fileEncoding = 2483028224; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HistoryDetailsViewController.strings; sourceTree = "<group>"; };
|
||||
636316DC1A1DEECB0009B839 /* UIButtonShrinkable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIButtonShrinkable.h; sourceTree = "<group>"; };
|
||||
636316DD1A1DEF2F0009B839 /* UIButtonShrinkable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIButtonShrinkable.m; sourceTree = "<group>"; };
|
||||
6371579F1B283FE200C91677 /* FileTransferDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FileTransferDelegate.h; path = Utils/FileTransferDelegate.h; sourceTree = "<group>"; };
|
||||
637157A01B283FE200C91677 /* FileTransferDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = FileTransferDelegate.m; path = Utils/FileTransferDelegate.m; sourceTree = "<group>"; };
|
||||
639CEAFE1A1DF4D9004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIStateBar.xib; sourceTree = "<group>"; };
|
||||
639CEB011A1DF4E4004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UIHistoryCell.xib; sourceTree = "<group>"; };
|
||||
639CEB041A1DF4EB004DE38F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UICompositeViewController.xib; sourceTree = "<group>"; };
|
||||
|
|
@ -1258,8 +1259,6 @@
|
|||
D36FB2D31589EF7C0036F6F2 /* UIPauseButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIPauseButton.h; sourceTree = "<group>"; };
|
||||
D36FB2D41589EF7C0036F6F2 /* UIPauseButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIPauseButton.m; sourceTree = "<group>"; };
|
||||
D37295DA158B3C9600D2C0C7 /* video_off_disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = video_off_disabled.png; path = Resources/video_off_disabled.png; sourceTree = "<group>"; };
|
||||
D374D3FB16071762003D25FF /* ImageSharing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageSharing.h; sourceTree = "<group>"; };
|
||||
D374D3FC16071762003D25FF /* ImageSharing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageSharing.m; sourceTree = "<group>"; };
|
||||
D377BBF915A19DA6002B696B /* video_on_disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = video_on_disabled.png; path = Resources/video_on_disabled.png; sourceTree = "<group>"; };
|
||||
D378906215AC373B00BD776C /* ContactDetailsLabelViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsLabelViewController.h; sourceTree = "<group>"; };
|
||||
D378906315AC373B00BD776C /* ContactDetailsLabelViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactDetailsLabelViewController.m; sourceTree = "<group>"; };
|
||||
|
|
@ -2041,8 +2040,6 @@
|
|||
D38187D415FE346B00C3EDCA /* HistoryViewController.xib */,
|
||||
D378AB2815DCDB480098505D /* ImagePickerViewController.h */,
|
||||
D378AB2915DCDB490098505D /* ImagePickerViewController.m */,
|
||||
D374D3FB16071762003D25FF /* ImageSharing.h */,
|
||||
D374D3FC16071762003D25FF /* ImageSharing.m */,
|
||||
22405EFD1601C19000B92522 /* ImageViewController.h */,
|
||||
22405EFE1601C19100B92522 /* ImageViewController.m */,
|
||||
D37EE11016035793003608A6 /* ImageViewController.xib */,
|
||||
|
|
@ -2319,7 +2316,6 @@
|
|||
D30BF33216A427BC00AF0026 /* libtunnel.a */,
|
||||
7066FC0B13E830E400EFC6DC /* libvpx.a */,
|
||||
22AA8AFB13D7125500B30535 /* libx264.a */,
|
||||
15017E6F1773578400784ACB /* libxml2.a */,
|
||||
F0B89C2118DC89E30050B60E /* MediaPlayer.framework */,
|
||||
D37DC7171594AF3400B2A5EB /* MessageUI.framework */,
|
||||
226EF06B15FA256B005865C7 /* MobileCoreServices.framework */,
|
||||
|
|
@ -2345,6 +2341,8 @@
|
|||
D37EE15F160377D7003608A6 /* DTFoundation */,
|
||||
D32B9DFA15A2F131000B6DEC /* FastAddressBook.h */,
|
||||
D32B9DFB15A2F131000B6DEC /* FastAddressBook.m */,
|
||||
6371579F1B283FE200C91677 /* FileTransferDelegate.h */,
|
||||
637157A01B283FE200C91677 /* FileTransferDelegate.m */,
|
||||
D3ED40141602172200BF332B /* GrowingTextView */,
|
||||
D3807FC715C2894A005BE9BC /* InAppSettingsKit */,
|
||||
D3B90E1115C2CB5700F64F8C /* NinePatch.xcodeproj */,
|
||||
|
|
@ -4059,13 +4057,13 @@
|
|||
D380800515C28A7A005BE9BC /* UILinphone.m in Sources */,
|
||||
D380801315C299D0005BE9BC /* ColorSpaceUtilites.m in Sources */,
|
||||
6359DE7F1ADEB54200EA15C0 /* InAppProductsViewController.m in Sources */,
|
||||
637157A11B283FE200C91677 /* FileTransferDelegate.m in Sources */,
|
||||
D378AB2A15DCDB4A0098505D /* ImagePickerViewController.m in Sources */,
|
||||
6359DE841ADEB64100EA15C0 /* InAppProductsCell.m in Sources */,
|
||||
22405F001601C19200B92522 /* ImageViewController.m in Sources */,
|
||||
D3ED40191602172200BF332B /* HPGrowingTextView.m in Sources */,
|
||||
D3ED401B1602172200BF332B /* HPTextViewInternal.m in Sources */,
|
||||
D37EE162160377D7003608A6 /* DTActionSheet.m in Sources */,
|
||||
D374D3FD16071762003D25FF /* ImageSharing.m in Sources */,
|
||||
D35E91F4160CA10B0023116B /* UILinphoneTextField.m in Sources */,
|
||||
D35E91F8160CA4FF0023116B /* UILinphoneButton.m in Sources */,
|
||||
D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */,
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 611762072933bf7bcbac9848bfead5a367a22ded
|
||||
Subproject commit 778fbca580812d759979c8431b01899feafa93cd
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit ad1d7c12c9b459660b34d63408b144bf5890f3b6
|
||||
Subproject commit 869938486e66225ded9d46d534a24df30a84d953
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 172e97a83aa2a868fd3dbbd6e7d57ad7d55f3054
|
||||
Subproject commit 40c29ef7736feb11af1e34f587788e49fa18b5c8
|
||||
Loading…
Add table
Reference in a new issue