forked from mirrors/linphone-iphone
PhotoKit integration done. Need small bug fix.
This commit is contained in:
parent
0ec09ef8d5
commit
6023bbff6c
15 changed files with 359 additions and 308 deletions
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
@protocol ChatConversationDelegate <NSObject>
|
||||
|
||||
- (BOOL)startImageUpload:(UIImage *)image url:(NSURL *)url withQuality:(float)quality;
|
||||
- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality;
|
||||
- (BOOL)startFileUpload:(NSData *)data withUrl:(NSURL *)url;
|
||||
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url;
|
||||
- (void)tableViewIsScrolling;
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
@property(nonatomic) LinphoneChatRoom *chatRoom;
|
||||
@property(nonatomic, strong) id<ChatConversationDelegate> chatRoomDelegate;
|
||||
@property NSMutableDictionary<NSString *, UIImage *> *imagesInChatroom;
|
||||
|
||||
- (void)addEventEntry:(LinphoneEventLog *)event;
|
||||
- (void)scrollToBottom:(BOOL)animated;
|
||||
|
|
|
|||
|
|
@ -39,29 +39,36 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.tableView.accessibilityIdentifier = @"ChatRoom list";
|
||||
_imagesInChatroom = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)clearEventList {
|
||||
[eventList removeAllObjects];
|
||||
for (NSValue *value in eventList) {
|
||||
LinphoneEventLog *event = value.pointerValue;
|
||||
linphone_event_log_unref(event);
|
||||
}
|
||||
[eventList removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)updateData {
|
||||
[self clearEventList];
|
||||
if (!_chatRoom)
|
||||
return;
|
||||
[self clearEventList];
|
||||
|
||||
LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(_chatRoom);
|
||||
bctbx_list_t *chatRoomEvents = (capabilities & LinphoneChatRoomCapabilitiesOneToOne)
|
||||
? linphone_chat_room_get_history_message_events(_chatRoom, 0)
|
||||
: linphone_chat_room_get_history_events(_chatRoom, 0);
|
||||
|
||||
bctbx_list_t *head = chatRoomEvents;
|
||||
eventList = [[NSMutableArray alloc] initWithCapacity:bctbx_list_size(chatRoomEvents)];
|
||||
while (chatRoomEvents) {
|
||||
LinphoneEventLog *event = (LinphoneEventLog *)chatRoomEvents->data;
|
||||
[eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
chatRoomEvents = chatRoomEvents->next;
|
||||
}
|
||||
bctbx_list_free_with_data(head, (bctbx_list_free_func)linphone_event_log_unref);
|
||||
|
||||
for (FileTransferDelegate *ftd in [LinphoneManager.instance fileTransferDelegates]) {
|
||||
const LinphoneAddress *ftd_peer =
|
||||
|
|
@ -83,7 +90,6 @@
|
|||
- (void)addEventEntry:(LinphoneEventLog *)event {
|
||||
[eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
int pos = (int)eventList.count - 1;
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0];
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
|
@ -102,12 +108,12 @@
|
|||
}
|
||||
|
||||
- (void)scrollToBottom:(BOOL)animated {
|
||||
[self.tableView reloadData];
|
||||
//[self.tableView reloadData];
|
||||
size_t count = eventList.count;
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0]];
|
||||
//[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0]];
|
||||
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(count - 1) inSection:0]
|
||||
atScrollPosition:UITableViewScrollPositionBottom
|
||||
animated:YES];
|
||||
|
|
@ -231,7 +237,6 @@ static const CGFloat MESSAGE_SPACING_PERCENTAGE = 5.f;
|
|||
if (nextEvent) {
|
||||
LinphoneChatMessage *nextChat = linphone_event_log_get_chat_message(nextEvent);
|
||||
if (!linphone_address_equal(linphone_chat_message_get_from_address(nextChat), linphone_chat_message_get_from_address(chat))) {
|
||||
LOGD(@"BITE");
|
||||
height += tableView.frame.size.height * MESSAGE_SPACING_PERCENTAGE / 100;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
//share photo
|
||||
NSData *data = dict[@"nsData"];
|
||||
UIImage *image = [[UIImage alloc] initWithData:data];
|
||||
[self chooseImageQuality:image url:nil];
|
||||
[self chooseImageQuality:image assetId:nil];
|
||||
[defaults removeObjectForKey:@"img"];
|
||||
} else if (dictWeb) {
|
||||
//share url, if local file, then upload file
|
||||
|
|
@ -310,38 +310,12 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
- (void)saveAndSend:(UIImage *)image url:(NSURL *)url withQuality:(float)quality{
|
||||
- (void)saveAndSend:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality{
|
||||
// photo from Camera, must be saved first
|
||||
if (url == nil) {
|
||||
__block NSURL *assetURL = nil;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
if (success) {
|
||||
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
|
||||
[self startImageUpload:image url:assetURL withQuality:quality];
|
||||
} else {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write image to photo library",
|
||||
nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[self presentViewController:errView animated:YES completion:nil];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[self startImageUpload:image url:url withQuality:quality];
|
||||
}
|
||||
[self startImageUpload:image assetId:phAssetId withQuality:quality];
|
||||
}
|
||||
|
||||
- (void)chooseImageQuality:(UIImage *)image url:(NSURL *)url {
|
||||
- (void)chooseImageQuality:(UIImage *)image assetId:(NSString *)phAssetId {
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Choose the image size", nil)];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
for (NSString *key in [imageQualities allKeys]) {
|
||||
|
|
@ -351,7 +325,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
NSString *text = [NSString stringWithFormat:@"%@ (%@)", key, [size toHumanReadableSize]];
|
||||
[sheet addButtonWithTitle:text
|
||||
block:^() {
|
||||
[self saveAndSend:image url:url withQuality:[quality floatValue]];
|
||||
[self saveAndSend:image assetId:phAssetId withQuality:[quality floatValue]];
|
||||
}];
|
||||
}
|
||||
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
|
||||
|
|
@ -603,9 +577,9 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark ChatRoomDelegate
|
||||
|
||||
- (BOOL)startImageUpload:(UIImage *)image url:(NSURL *)url withQuality:(float)quality {
|
||||
- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality {
|
||||
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
|
||||
[fileTransfer upload:image withURL:url forChatRoom:_chatRoom withQuality:quality];
|
||||
[fileTransfer upload:image withassetId:phAssetId forChatRoom:_chatRoom withQuality:quality];
|
||||
[_tableController scrollToBottom:true];
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -623,7 +597,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
#pragma mark ImagePickerDelegate
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info {
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSString *)phAssetId {
|
||||
// When getting image from the camera, it may be 90° rotated due to orientation
|
||||
// (image.imageOrientation = UIImageOrientationRight). Just rotate it to be face up.
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
|
|
@ -637,9 +611,7 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
if (IPAD) {
|
||||
[VIEW(ImagePickerView).popoverController dismissPopoverAnimated:TRUE];
|
||||
}
|
||||
|
||||
NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL];
|
||||
[self chooseImageQuality:image url:url];
|
||||
[self chooseImageQuality:image assetId:phAssetId];
|
||||
}
|
||||
|
||||
- (void)tableViewIsScrolling {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
@protocol ImagePickerDelegate <NSObject>
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info;
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSString *)phAssetId;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
|||
|
|
@ -161,27 +161,38 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
|
||||
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
|
||||
[self dismiss];
|
||||
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
|
||||
if (image == nil) {
|
||||
image = [info objectForKey:UIImagePickerControllerOriginalImage];
|
||||
}
|
||||
if (image != nil) {
|
||||
if (![info objectForKey:UIImagePickerControllerReferenceURL]) {
|
||||
//Saving image. Supports picture only, no video
|
||||
//Maybe add a completion target to send the saved image to, like self, and we would call it manually if the image was not taken.
|
||||
UIImageWriteToSavedPhotosAlbum(image, self, @selector(savedImage:didFinishSavingWithError:contextInfo:), (__bridge void *)info);
|
||||
} else {
|
||||
[self savedImage:image didFinishSavingWithError:nil contextInfo:(__bridge void *)info];
|
||||
PHAsset *phasset = [info objectForKey:UIImagePickerControllerPHAsset];
|
||||
UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage] ? [info objectForKey:UIImagePickerControllerEditedImage] : [info objectForKey:UIImagePickerControllerOriginalImage];
|
||||
if (!phasset) {
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
if (success) {
|
||||
LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]);
|
||||
[self passImageToDelegate:image PHAssetId:[placeHolder localIdentifier]];
|
||||
} else {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
}
|
||||
}
|
||||
];
|
||||
return;
|
||||
}
|
||||
[self passImageToDelegate:image PHAssetId:[phasset localIdentifier]];
|
||||
}
|
||||
|
||||
- (void)savedImage:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
|
||||
- (void) passImageToDelegate:(UIImage *)image PHAssetId:(NSString *)assetId {
|
||||
if (imagePickerDelegate != nil) {
|
||||
[imagePickerDelegate imagePickerDelegateImage:image info:(NSString *)assetId];
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (imagePickerDelegate != nil) {
|
||||
[imagePickerDelegate imagePickerDelegateImage:image info:(__bridge NSDictionary *)contextInfo];
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
|
||||
[self dismiss];
|
||||
}
|
||||
|
|
@ -234,35 +245,62 @@ static UICompositeViewDescription *compositeDescription = nil;
|
|||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
}
|
||||
};
|
||||
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)];
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil)
|
||||
block:^() {
|
||||
if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] == AVAuthorizationStatusAuthorized ){
|
||||
if([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusDenied ){
|
||||
block(UIImagePickerControllerSourceTypeCamera);
|
||||
}else{
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
}
|
||||
}else {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
}
|
||||
}];
|
||||
}
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil)
|
||||
block:^() {
|
||||
if([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusDenied ){
|
||||
block(UIImagePickerControllerSourceTypePhotoLibrary);
|
||||
}else{
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
}
|
||||
}];
|
||||
}
|
||||
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
|
||||
|
||||
[sheet showInView:PhoneMainView.instance.view];
|
||||
|
||||
[PHPhotoLibrary authorizationStatus];
|
||||
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
|
||||
|
||||
if (status == PHAuthorizationStatusNotDetermined) {
|
||||
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
|
||||
if(status != PHAuthorizationStatusAuthorized) {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
return;
|
||||
}
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)];
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil)
|
||||
block:^() {
|
||||
if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized ) {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
return;
|
||||
}
|
||||
block(UIImagePickerControllerSourceTypeCamera);
|
||||
}];
|
||||
}
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil)
|
||||
block:^() {
|
||||
block(UIImagePickerControllerSourceTypePhotoLibrary);
|
||||
}];
|
||||
}
|
||||
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
|
||||
|
||||
[sheet showInView:PhoneMainView.instance.view];
|
||||
}];
|
||||
} else if (status == PHAuthorizationStatusAuthorized) {
|
||||
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Select the source", nil)];
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Camera", nil)
|
||||
block:^() {
|
||||
if([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized ) {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Camera's permission", nil) message:NSLocalizedString(@"Camera not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
return;
|
||||
}
|
||||
block(UIImagePickerControllerSourceTypeCamera);
|
||||
}];
|
||||
}
|
||||
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
|
||||
[sheet addButtonWithTitle:NSLocalizedString(@"Photo library", nil)
|
||||
block:^() {
|
||||
block(UIImagePickerControllerSourceTypePhotoLibrary);
|
||||
}];
|
||||
}
|
||||
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
|
||||
|
||||
[sheet showInView:PhoneMainView.instance.view];
|
||||
} else {
|
||||
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Photo's permission", nil) message:NSLocalizedString(@"Photo not authorized", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Continue", nil] show];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SCNetworkReachability.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AssetsLibrary/ALAssetsLibrary.h>
|
||||
#import <Photos/Photos.h>
|
||||
#import <CoreTelephony/CTCallCenter.h>
|
||||
|
||||
|
|
@ -209,6 +208,8 @@ typedef struct _LinphoneManagerSounds {
|
|||
|
||||
- (void)checkNewVersion;
|
||||
|
||||
- (void)loadAvatar;
|
||||
|
||||
@property ProviderDelegate *providerDelegate;
|
||||
|
||||
@property (readonly) BOOL isTesting;
|
||||
|
|
@ -226,7 +227,6 @@ typedef struct _LinphoneManagerSounds {
|
|||
@property (nonatomic, assign) BOOL speakerEnabled;
|
||||
@property (nonatomic, assign) BOOL bluetoothAvailable;
|
||||
@property (nonatomic, assign) BOOL bluetoothEnabled;
|
||||
@property (readonly) ALAssetsLibrary *photoLibrary;
|
||||
@property (readonly) NSString* contactSipField;
|
||||
@property (readonly,copy) NSString* contactFilter;
|
||||
@property (copy) void (^silentPushCompletion)(UIBackgroundFetchResult);
|
||||
|
|
@ -239,5 +239,6 @@ typedef struct _LinphoneManagerSounds {
|
|||
@property NSDictionary *pushDict;
|
||||
@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap;
|
||||
@property (nonatomic, assign) BOOL contactsUpdated;
|
||||
@property UIImage *avatar;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
|
|||
}
|
||||
|
||||
[self migrateFromUserPrefs];
|
||||
[self loadAvatar];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -3076,4 +3077,33 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
|
|||
const char *curVersionCString = [curVersion cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
linphone_core_check_for_update(theLinphoneCore, curVersionCString);
|
||||
}
|
||||
|
||||
- (void)loadAvatar {
|
||||
NSString *assetId = [self lpConfigStringForKey:@"avatar"];
|
||||
__block UIImage *ret = nil;
|
||||
if (assetId) {
|
||||
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:assetId] options:nil];
|
||||
if (![assets firstObject]) {
|
||||
LOGE(@"Can't fetch avatar image.");
|
||||
}
|
||||
PHAsset *asset = [assets firstObject];
|
||||
// load avatar synchronously so that we can return UIIMage* directly - since we are
|
||||
// only using thumbnail, it must be pretty fast to fetch even without cache.
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image)
|
||||
ret = [UIImage UIImageThumbnail:image thumbSize:150];
|
||||
else
|
||||
LOGE(@"Can't read avatar");
|
||||
}];
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ret = [UIImage imageNamed:@"avatar.png"];
|
||||
}
|
||||
_avatar = ret;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -30,9 +30,8 @@
|
|||
@implementation UIChatBubblePhotoCell {
|
||||
FileTransferDelegate *_ftd;
|
||||
CGSize imageSize, bubbleSize, videoDefaultSize;
|
||||
int actualAvailableWidth;
|
||||
ChatConversationTableView *chatTableView;
|
||||
//CGImageRef displayedImage;
|
||||
BOOL assetIsLoaded;
|
||||
}
|
||||
|
||||
#pragma mark - Lifecycle Functions
|
||||
|
|
@ -51,11 +50,10 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
[self setFrame:CGRectMake(0, 0, 5, 100)];
|
||||
[self addSubview:sub];
|
||||
chatTableView = VIEW(ChatConversationView).tableController;
|
||||
actualAvailableWidth = chatTableView.tableView.frame.size.width;
|
||||
videoDefaultSize = CGSizeMake(320, 240);
|
||||
assetIsLoaded = FALSE;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
@ -76,6 +74,7 @@
|
|||
_finalImage.image = nil;
|
||||
_finalImage.hidden = TRUE;
|
||||
_fileTransferProgress.progress = 0;
|
||||
assetIsLoaded = FALSE;
|
||||
[self disconnectFromFileDelegate];
|
||||
|
||||
if (amessage) {
|
||||
|
|
@ -98,11 +97,10 @@
|
|||
[super setChatMessage:amessage];
|
||||
}
|
||||
|
||||
- (void) loadImageAsset:(ALAsset*) asset thumb:(UIImage *)thumb image:(UIImage *)image {
|
||||
- (void) loadImageAsset:(PHAsset*) asset image:(UIImage *)image {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[_finalImage setImage:image];
|
||||
[_messageImageView setImage:thumb];
|
||||
[_messageImageView setFullImageUrl:asset];
|
||||
[_messageImageView setAsset:asset];
|
||||
[_messageImageView stopLoading];
|
||||
_messageImageView.hidden = YES;
|
||||
_imageGestureRecognizer.enabled = YES;
|
||||
|
|
@ -110,13 +108,22 @@
|
|||
});
|
||||
}
|
||||
|
||||
- (void) loadAsset:(ALAsset*) asset {
|
||||
UIImage *thumb = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
|
||||
ALAssetRepresentation *representation = [asset defaultRepresentation];
|
||||
imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[representation dimensions] withWidth:chatTableView.tableView.frame.size.width];
|
||||
CGImageRef tmpImg = [self cropImageFromRepresentation:representation];
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:tmpImg];
|
||||
[self loadImageAsset:asset thumb:thumb image:image];
|
||||
- (void) loadAsset:(PHAsset *) asset {
|
||||
LOGD(@"SALOPE");
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image) {
|
||||
imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[image size] withWidth:chatTableView.tableView.frame.size.width];
|
||||
UIImage *newImage = [UIImage UIImageResize:image toSize:imageSize];
|
||||
[chatTableView.imagesInChatroom setObject:newImage forKey:[asset localIdentifier]];
|
||||
[self loadImageAsset:asset image:newImage];
|
||||
}
|
||||
else {
|
||||
LOGE(@"Can't read image");
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) loadVideoAsset: (AVAsset *) asset {
|
||||
|
|
@ -139,7 +146,7 @@
|
|||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
[self loadImageAsset:nil thumb:thumb image:image];
|
||||
[self loadImageAsset:nil image:image];
|
||||
|
||||
// put the play button in the top
|
||||
CGRect newFrame = _playButton.frame;
|
||||
|
|
@ -184,39 +191,21 @@
|
|||
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES;
|
||||
fullScreenImage = YES;
|
||||
} else {
|
||||
assetIsLoaded = TRUE;
|
||||
LOGD(@"POUET");
|
||||
if (localImage) {
|
||||
// we did not load the image yet, so start doing so
|
||||
if (_messageImageView.image == nil) {
|
||||
NSURL *imageUrl = [NSURL URLWithString:localImage];
|
||||
[_messageImageView startLoading];
|
||||
__block LinphoneChatMessage *achat = self.message;
|
||||
[LinphoneManager.instance.photoLibrary assetForURL:imageUrl resultBlock:^(ALAsset *asset) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL), ^(void) {
|
||||
if (achat != self.message) // Avoid glitch and scrolling
|
||||
return;
|
||||
|
||||
if (asset) {
|
||||
[self loadAsset:asset];
|
||||
}
|
||||
else {
|
||||
[LinphoneManager.instance.photoLibrary
|
||||
enumerateGroupsWithTypes:ALAssetsGroupAll
|
||||
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
|
||||
[group enumerateAssetsWithOptions:NSEnumerationReverse
|
||||
usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
|
||||
if([result.defaultRepresentation.url isEqual:imageUrl]) {
|
||||
[self loadAsset:result];
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
}
|
||||
failureBlock:^(NSError *error) {
|
||||
LOGE(@"Error: Cannot load asset from photo stream - %@", [error localizedDescription]);
|
||||
}];
|
||||
}
|
||||
});
|
||||
} failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read image");
|
||||
}];
|
||||
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localImage] options:nil];
|
||||
UIImage *img = [chatTableView.imagesInChatroom objectForKey:localImage];
|
||||
if (![assets firstObject])
|
||||
return;
|
||||
PHAsset *asset = [assets firstObject];
|
||||
if (img)
|
||||
[self loadImageAsset:asset image:img];
|
||||
else
|
||||
[self loadAsset:asset];
|
||||
}
|
||||
} else if (localVideo) {
|
||||
if (_messageImageView.image == nil) {
|
||||
|
|
@ -249,13 +238,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
// resize image so that it take the full bubble space available
|
||||
CGRect newFrame = _totalView.frame;
|
||||
newFrame.origin.x = newFrame.origin.y = 0;
|
||||
if (!fullScreenImage) {
|
||||
newFrame.size.height -= _imageSubView.frame.size.height;
|
||||
}
|
||||
_messageImageView.frame = newFrame;
|
||||
}
|
||||
|
||||
- (void)fileErrorBlock {
|
||||
|
|
@ -336,9 +318,18 @@
|
|||
if (![_messageImageView isLoading]) {
|
||||
ImageView *view = VIEW(ImageView);
|
||||
[PhoneMainView.instance changeCurrentView:view.compositeViewDescription];
|
||||
CGImageRef fullScreenRef = [[_messageImageView.fullImageUrl defaultRepresentation] fullScreenImage];
|
||||
UIImage *fullScreen = [UIImage imageWithCGImage:fullScreenRef];
|
||||
[view setImage:fullScreen];
|
||||
PHAsset *asset = [_messageImageView asset];
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image) {
|
||||
[view setImage:image];
|
||||
}
|
||||
else {
|
||||
LOGE(@"Can't read image");
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -399,31 +390,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
+ (CGImageRef)resizeCGImage:(CGImageRef)image toWidth:(int)width andHeight:(int)height {
|
||||
// create context, keeping original image properties
|
||||
CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height,
|
||||
CGImageGetBitsPerComponent(image),
|
||||
CGImageGetBytesPerRow(image),
|
||||
colorspace,
|
||||
CGImageGetAlphaInfo(image));
|
||||
CGColorSpaceRelease(colorspace);
|
||||
|
||||
if(context == NULL)
|
||||
return nil;
|
||||
|
||||
// draw image to context (resizing it)
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||
// extract resulting image from context
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
|
||||
return imgRef;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
//if (!isAssetLoaded) return;
|
||||
//[super layoutSubviews];
|
||||
UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
|
||||
BOOL is_outgoing = linphone_chat_message_is_outgoing(super.message);
|
||||
CGRect bubbleFrame = super.bubbleView.frame;
|
||||
|
|
@ -444,25 +412,6 @@
|
|||
super.bubbleView.frame = bubbleFrame;
|
||||
}
|
||||
|
||||
- (CGImageRef)cropImageFromRepresentation:(ALAssetRepresentation*)rep {
|
||||
CGImageRef newImage = [rep fullResolutionImage];
|
||||
CGSize originalSize = [rep dimensions];
|
||||
float originalAspectRatio = originalSize.width / originalSize.height;
|
||||
// We resize in width and crop in height
|
||||
if (originalSize.width > imageSize.width) {
|
||||
int height = imageSize.width / originalAspectRatio;
|
||||
newImage = [self.class resizeCGImage:newImage toWidth:imageSize.width andHeight:height];
|
||||
originalSize.height = height;
|
||||
}
|
||||
CGRect cropRect = CGRectMake(0, 0, imageSize.width, imageSize.height);
|
||||
if (imageSize.height < originalSize.height) cropRect.origin.y = (originalSize.height - imageSize.height)/2;
|
||||
newImage = CGImageCreateWithImageInRect(newImage, cropRect);
|
||||
LOGD([NSString stringWithFormat:@"Image size : width = %g, height = %g", imageSize.width, imageSize.height]);
|
||||
LOGD([NSString stringWithFormat:@"Bubble size : width = %g, height = %g", super.bubbleView.frame.size.width, super.bubbleView.frame.size.height]);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -235,20 +235,26 @@
|
|||
NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message];
|
||||
NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message];
|
||||
NSString *fileName = localVideo ? localVideo : localFile;
|
||||
NSURL *imageUrl = [NSURL URLWithString:localImage];
|
||||
[self onDelete];
|
||||
if(localImage){
|
||||
[LinphoneManager.instance.photoLibrary assetForURL:imageUrl
|
||||
resultBlock:^(ALAsset *asset) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
|
||||
^(void) {
|
||||
UIImage *image = [[UIImage alloc] initWithCGImage:[[asset defaultRepresentation] fullResolutionImage]];
|
||||
[_chatRoomDelegate startImageUpload:image url:imageUrl withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)];
|
||||
});
|
||||
}
|
||||
failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read image");
|
||||
}];
|
||||
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localImage] options:nil];
|
||||
if (![assets firstObject]) {
|
||||
return;
|
||||
}
|
||||
PHAsset *asset = [assets firstObject];
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
|
||||
^(void) {
|
||||
[_chatRoomDelegate startImageUpload:image assetId:localImage withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)];
|
||||
});
|
||||
} else {
|
||||
LOGE(@"Can't read image");
|
||||
}
|
||||
}];
|
||||
} else if(fileName) {
|
||||
NSString *filePath = [LinphoneManager documentFile:fileName];
|
||||
[_chatRoomDelegate startFileUpload:[NSData dataWithContentsOfFile:filePath] withUrl:[NSURL URLWithString:filePath]];
|
||||
|
|
@ -346,22 +352,16 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44;
|
|||
size = [self getMediaMessageSizefromOriginalSize:videoSize withWidth:width];
|
||||
size.height += CELL_MESSAGE_X_MARGIN;
|
||||
} else {
|
||||
NSURL *imageUrl = [NSURL URLWithString:localImage];
|
||||
__block CGSize originalImageSize = CGSizeMake(0, 0);
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
|
||||
[LinphoneManager.instance.photoLibrary assetForURL:imageUrl
|
||||
resultBlock:^(ALAsset *asset) {
|
||||
originalImageSize = [[asset defaultRepresentation] dimensions];
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read image");
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
});
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
|
||||
LOGE(@"LA BITE EN BOIS");
|
||||
if (!localImage) {
|
||||
return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_HEIGHT);
|
||||
}
|
||||
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localImage] options:nil];
|
||||
if (![assets firstObject]) {
|
||||
return CGSizeMake(CELL_MIN_WIDTH, CELL_MIN_HEIGHT);
|
||||
}
|
||||
PHAsset *asset = [assets firstObject];
|
||||
CGSize originalImageSize = CGSizeMake([asset pixelWidth], [asset pixelHeight]);
|
||||
size = [self getMediaMessageSizefromOriginalSize:originalImageSize withWidth:width];
|
||||
//This fixes the image being too small. I think the issue comes form the fact that the display is retina. This should probably be changed in the future.
|
||||
size.height += CELL_MESSAGE_X_MARGIN;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
- (BOOL)isLoading;
|
||||
- (void)stopLoading;
|
||||
|
||||
@property(nonatomic, strong) ALAsset *fullImageUrl;
|
||||
@property(nonatomic, strong) PHAsset *asset;
|
||||
@property (nonatomic, readonly) IBOutlet UIActivityIndicatorView *waitIndicatorView;
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@
|
|||
|
||||
#pragma mark - Image picker delegate
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info {
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSString *)phAssetId {
|
||||
// When getting image from the camera, it may be 90° rotated due to orientation
|
||||
// (image.imageOrientation = UIImageOrientationRight). Just rotate it to be face up.
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
|
|
@ -120,27 +120,10 @@
|
|||
} else {
|
||||
[PhoneMainView.instance.mainViewController hideSideMenu:NO];
|
||||
}
|
||||
|
||||
NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL];
|
||||
|
||||
// taken from camera, must be saved to device first
|
||||
if (!url) {
|
||||
__block NSURL *assetURL = nil;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
[PHAssetChangeRequest creationRequestForAssetFromImage:image];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
if (success) {
|
||||
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
|
||||
} else {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
}
|
||||
[LinphoneManager.instance lpConfigSetString:assetURL.absoluteString forKey:@"avatar"];
|
||||
_avatarImage.image = [LinphoneUtils selfAvatar];
|
||||
}];
|
||||
} else {
|
||||
[LinphoneManager.instance lpConfigSetString:url.absoluteString forKey:@"avatar"];
|
||||
_avatarImage.image = [LinphoneUtils selfAvatar];
|
||||
}
|
||||
|
||||
[LinphoneManager.instance lpConfigSetString:phAssetId forKey:@"avatar"];
|
||||
_avatarImage.image = [LinphoneUtils selfAvatar];
|
||||
[LinphoneManager.instance loadAvatar];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
@interface FileTransferDelegate : NSObject
|
||||
|
||||
- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
|
||||
- (void)upload:(UIImage *)image withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
|
||||
- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withUrl:(NSURL *)url;
|
||||
- (void)cancel;
|
||||
- (BOOL)download:(LinphoneChatMessage *)message;
|
||||
|
|
|
|||
|
|
@ -75,44 +75,44 @@ static void linphone_iphone_file_transfer_recv(LinphoneChatMessage *message, con
|
|||
// chat bubble is aware of the fact that image is being saved to device
|
||||
[LinphoneManager setValueInMessageAppData:@"saving..." forKey:@"localimage" inMessage:message];
|
||||
|
||||
[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]);
|
||||
[LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:message];
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write image to photo library",
|
||||
nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
} else {
|
||||
LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
|
||||
[LinphoneManager setValueInMessageAppData:[assetURL absoluteString]
|
||||
forKey:@"localimage"
|
||||
inMessage:message];
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter
|
||||
postNotificationName:kLinphoneFileTransferRecvUpdate
|
||||
object:thiz
|
||||
userInfo:@{
|
||||
@"state" : @(LinphoneChatMessageStateDelivered), // we dont want to
|
||||
// trigger
|
||||
// FileTransferDone here
|
||||
@"image" : image,
|
||||
@"progress" : @(1.f),
|
||||
}];
|
||||
|
||||
[thiz stopAndDestroy];
|
||||
CFRelease((__bridge CFTypeRef)thiz);
|
||||
}];
|
||||
__block PHObjectPlaceholder *placeHolder;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromImage:image];
|
||||
placeHolder = [request placeholderForCreatedAsset];
|
||||
} completionHandler:^(BOOL success, NSError *error) {
|
||||
if (success) {
|
||||
LOGI(@"Image saved to [%@]", [placeHolder localIdentifier]);
|
||||
[LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier]
|
||||
forKey:@"localimage"
|
||||
inMessage:message];
|
||||
} else {
|
||||
LOGE(@"Cannot save image data downloaded [%@]", [error localizedDescription]);
|
||||
[LinphoneManager setValueInMessageAppData:nil forKey:@"localimage" inMessage:message];
|
||||
UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
|
||||
message:NSLocalizedString(@"Cannot write image to photo library",
|
||||
nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK"
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {}];
|
||||
|
||||
[errView addAction:defaultAction];
|
||||
[PhoneMainView.instance presentViewController:errView animated:YES completion:nil];
|
||||
}
|
||||
[NSNotificationCenter.defaultCenter
|
||||
postNotificationName:kLinphoneFileTransferRecvUpdate
|
||||
object:thiz
|
||||
userInfo:@{
|
||||
@"state" : @(LinphoneChatMessageStateDelivered),
|
||||
// we dont want to trigger FileTransferDone here
|
||||
@"image" : image,
|
||||
@"progress" : @(1.f),
|
||||
}];
|
||||
|
||||
[thiz stopAndDestroy];
|
||||
CFRelease((__bridge CFTypeRef)thiz);
|
||||
}];
|
||||
} else {
|
||||
[[LinphoneManager.instance fileTransferDelegates] removeObject:thiz];
|
||||
|
||||
|
|
@ -224,10 +224,10 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m
|
|||
}
|
||||
}
|
||||
|
||||
- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality {
|
||||
- (void)upload:(UIImage *)image withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality {
|
||||
NSString *name = [NSString stringWithFormat:@"%li-%f.jpg", (long)image.hash, [NSDate timeIntervalSinceReferenceDate]];
|
||||
if (url)
|
||||
[self uploadData:UIImageJPEGRepresentation(image, quality) forChatRoom:chatRoom type:@"image" subtype:@"jpeg" name:name key:@"localimage" keyData:[url absoluteString] qualityData:[NSNumber numberWithFloat:quality]];
|
||||
if (phAssetId)
|
||||
[self uploadData:UIImageJPEGRepresentation(image, quality) forChatRoom:chatRoom type:@"image" subtype:@"jpeg" name:name key:@"localimage" keyData:phAssetId qualityData:[NSNumber numberWithFloat:quality]];
|
||||
else
|
||||
[self uploadData:UIImageJPEGRepresentation(image, quality) forChatRoom:chatRoom type:@"image" subtype:@"jpeg" name:name key:@"localimage" keyData:nil qualityData:nil];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,16 @@ typedef enum {
|
|||
|
||||
@end
|
||||
|
||||
@interface UIImage (ResizeAndThumbnail)
|
||||
|
||||
+ (UIImage *)UIImageThumbnail:(UIImage *)image thumbSize:(CGFloat) tbSize;
|
||||
|
||||
+ (UIImage *)UIImageResize:(UIImage *)image toSize:(CGSize) newSize;
|
||||
|
||||
+ (CGImageRef)resizeCGImage:(CGImageRef)image toWidth:(int)width andHeight:(int)height;
|
||||
|
||||
@end
|
||||
|
||||
/* Use that macro when you want to invoke a custom initialisation method on your class,
|
||||
whatever is using it (xib, source code, etc., tableview cell) */
|
||||
#define INIT_WITH_COMMON_C \
|
||||
|
|
|
|||
|
|
@ -32,36 +32,10 @@
|
|||
@implementation LinphoneUtils
|
||||
|
||||
+ (BOOL)hasSelfAvatar {
|
||||
return [NSURL URLWithString:[LinphoneManager.instance lpConfigStringForKey:@"avatar"]] != nil;
|
||||
return [LinphoneManager.instance lpConfigStringForKey:@"avatar"] != nil;
|
||||
}
|
||||
+ (UIImage *)selfAvatar {
|
||||
NSURL *url = [NSURL URLWithString:[LinphoneManager.instance lpConfigStringForKey:@"avatar"]];
|
||||
__block UIImage *ret = nil;
|
||||
if (url) {
|
||||
__block NSConditionLock *photoLock = [[NSConditionLock alloc] initWithCondition:1];
|
||||
// load avatar synchronously so that we can return UIIMage* directly - since we are
|
||||
// only using thumbnail, it must be pretty fast to fetch even without cache.
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[LinphoneManager.instance.photoLibrary assetForURL:url
|
||||
resultBlock:^(ALAsset *asset) {
|
||||
ret = [[UIImage alloc] initWithCGImage:[asset thumbnail]];
|
||||
[photoLock lock];
|
||||
[photoLock unlockWithCondition:0];
|
||||
}
|
||||
failureBlock:^(NSError *error) {
|
||||
LOGE(@"Can't read avatar");
|
||||
[photoLock lock];
|
||||
[photoLock unlockWithCondition:0];
|
||||
}];
|
||||
});
|
||||
[photoLock lockWhenCondition:0];
|
||||
[photoLock unlock];
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ret = [UIImage imageNamed:@"avatar.png"];
|
||||
}
|
||||
return ret;
|
||||
return [LinphoneManager.instance avatar];
|
||||
}
|
||||
|
||||
+ (NSString *)durationToString:(int)duration {
|
||||
|
|
@ -777,3 +751,91 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIImage (ResizeAndThumbnail)
|
||||
|
||||
+ (UIImage *)UIImageThumbnail:(UIImage *)image thumbSize:(CGFloat) tbSize {
|
||||
// Create a thumbnail version of the image for the event object.
|
||||
CGSize size = image.size;
|
||||
CGSize croppedSize;
|
||||
CGFloat offsetX = 0.0;
|
||||
CGFloat offsetY = 0.0;
|
||||
CGFloat actualTbSize = MAX(tbSize, MAX(size.height, size.width));
|
||||
// check the size of the image, we want to make it
|
||||
// a square with sides the size of the smallest end
|
||||
if (size.width > size.height) {
|
||||
offsetX = (size.height - size.width) / 2;
|
||||
croppedSize = CGSizeMake(size.height, size.height);
|
||||
} else {
|
||||
offsetY = (size.width - size.height) / 2;
|
||||
croppedSize = CGSizeMake(size.width, size.width);
|
||||
}
|
||||
|
||||
// Crop the image before resize
|
||||
CGRect clippedRect = CGRectMake(offsetX * -1,
|
||||
offsetY * -1,
|
||||
croppedSize.width,
|
||||
croppedSize.height);
|
||||
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage],
|
||||
clippedRect);
|
||||
|
||||
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
|
||||
CGImageRelease(imageRef);
|
||||
// Done cropping
|
||||
|
||||
// Resize the image
|
||||
CGRect rect = CGRectMake(0, 0, actualTbSize, actualTbSize);
|
||||
|
||||
UIGraphicsBeginImageContext(rect.size);
|
||||
[cropped drawInRect:rect];
|
||||
UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
// Done Resizing
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
|
||||
+ (UIImage *)UIImageResize:(UIImage *)image toSize:(CGSize) newSize {
|
||||
CGImageRef newImage = [image CGImage];
|
||||
CGSize originalSize = [image size];
|
||||
float originalAspectRatio = originalSize.width / originalSize.height;
|
||||
// We resize in width and crop in height
|
||||
if (originalSize.width > newSize.width) {
|
||||
int height = newSize.width / originalAspectRatio;
|
||||
newImage = [UIImage resizeCGImage:newImage toWidth:newSize.width andHeight:height];
|
||||
originalSize.height = height;
|
||||
}
|
||||
CGRect cropRect = CGRectMake(0, 0, newSize.width, newSize.height);
|
||||
if (newSize.height < originalSize.height) cropRect.origin.y = (originalSize.height - newSize.height)/2;
|
||||
newImage = CGImageCreateWithImageInRect(newImage, cropRect);
|
||||
|
||||
|
||||
UIImage *cropped = [UIImage imageWithCGImage:newImage];
|
||||
CGImageRelease(newImage);
|
||||
return cropped;
|
||||
}
|
||||
|
||||
+ (CGImageRef)resizeCGImage:(CGImageRef)image toWidth:(int)width andHeight:(int)height {
|
||||
// create context, keeping original image properties
|
||||
CGColorSpaceRef colorspace = CGImageGetColorSpace(image);
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height,
|
||||
CGImageGetBitsPerComponent(image),
|
||||
CGImageGetBytesPerRow(image),
|
||||
colorspace,
|
||||
CGImageGetAlphaInfo(image));
|
||||
CGColorSpaceRelease(colorspace);
|
||||
|
||||
if(context == NULL)
|
||||
return nil;
|
||||
|
||||
// draw image to context (resizing it)
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
|
||||
// extract resulting image from context
|
||||
CGImageRef imgRef = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
|
||||
return imgRef;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue