diff --git a/CHANGELOG.md b/CHANGELOG.md
index 232e6f4c2..b9956e1ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,8 +13,17 @@ Group changes to describe their impact on the project, as follows:
## [Unreleased]
### Added
+- Auto-layout of images in chat messages
+- Selection of multiple images to send in a chat message
+- Sending text with image
+- Latest Calls widget
+- Latest Chatrooms widget
+- Homescreen quick action : New message
+- Rich message notifications with Linphone UI
- Support of H265 video format based on Apple's VideoToolbox framework.
+### Changed
+- Use of Photokit instead of Asset Library for image handling
### Fixed
- Fix Bluetooth management
diff --git a/Classes/Base.lproj/ChatConversationView.xib b/Classes/Base.lproj/ChatConversationView.xib
index 604c03dc1..90c5815cd 100644
--- a/Classes/Base.lproj/ChatConversationView.xib
+++ b/Classes/Base.lproj/ChatConversationView.xib
@@ -18,6 +18,8 @@
+
+
@@ -269,6 +271,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Classes/ChatConversationTableView.h b/Classes/ChatConversationTableView.h
index 0f6162f47..551a22a4d 100644
--- a/Classes/ChatConversationTableView.h
+++ b/Classes/ChatConversationTableView.h
@@ -27,8 +27,7 @@
@protocol ChatConversationDelegate
-- (BOOL)startImageUpload:(UIImage *)image url:(NSURL *)url withQuality:(float)quality;
-- (BOOL)startFileUpload:(NSData *)data withUrl:(NSURL *)url;
+- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality;
- (void)resendChat:(NSString *)message withExternalUrl:(NSString *)url;
- (void)tableViewIsScrolling;
@@ -41,6 +40,7 @@
@property(nonatomic) LinphoneChatRoom *chatRoom;
@property(nonatomic, strong) id chatRoomDelegate;
+@property NSMutableDictionary *imagesInChatroom;
- (void)addEventEntry:(LinphoneEventLog *)event;
- (void)scrollToBottom:(BOOL)animated;
diff --git a/Classes/ChatConversationTableView.m b/Classes/ChatConversationTableView.m
index 0ff816e0d..20842d192 100644
--- a/Classes/ChatConversationTableView.m
+++ b/Classes/ChatConversationTableView.m
@@ -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];
@@ -98,16 +104,16 @@
}
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:index inSection:0]]
withRowAnimation:FALSE]; // just reload
- return;
+ return;
}
- (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];
diff --git a/Classes/ChatConversationView.h b/Classes/ChatConversationView.h
index 7a264ca8e..422cad12a 100644
--- a/Classes/ChatConversationView.h
+++ b/Classes/ChatConversationView.h
@@ -27,12 +27,13 @@
#import "UIRoundedImageView.h"
#import "UIBackToCallButton.h"
#import "Utils/HPGrowingTextView/HPGrowingTextView.h"
+#import "UIImageViewDeletable.h"
#include "linphone/linphonecore.h"
@interface ChatConversationView
- : TPMultiLayoutViewController {
+ : TPMultiLayoutViewController {
OrderedDictionary *imageQualities;
BOOL scrollOnGrowingEnabled;
BOOL composingVisible;
@@ -60,6 +61,13 @@
@property (weak, nonatomic) IBOutlet UIIconButton *infoButton;
@property (weak, nonatomic) IBOutlet UILabel *particpantsLabel;
@property (nonatomic, strong) UIDocumentInteractionController *documentInteractionController;
+@property (nonatomic, strong) UIDocumentPickerViewController *documentPicker;
+@property NSMutableArray *imagesArray;
+@property NSMutableArray *assetIdsArray;
+@property NSMutableArray *qualitySettingsArray;
+@property (weak, nonatomic) IBOutlet UICollectionView *imagesCollectionView;
+@property (weak, nonatomic) IBOutlet UIView *imagesView;
+
+ (void)markAsRead:(LinphoneChatRoom *)chatRoom;
- (void)configureForRoom:(BOOL)editing;
@@ -73,6 +81,8 @@
- (IBAction)onDeleteClick:(id)sender;
- (IBAction)onEditionChangeClick:(id)sender;
- (void)update;
-- (void)openResults:(NSString *) filePath;
+- (void)getIcloudFiles;
+- (void)openFile:(NSString *) filePath;
+- (void)clearMessageView;
@end
diff --git a/Classes/ChatConversationView.m b/Classes/ChatConversationView.m
index bf5dd6555..cd0d3edd4 100644
--- a/Classes/ChatConversationView.m
+++ b/Classes/ChatConversationView.m
@@ -17,6 +17,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#import
+
#import "ChatConversationView.h"
#import "PhoneMainView.h"
#import "Utils.h"
@@ -99,6 +101,8 @@ static UICompositeViewDescription *compositeDescription = nil;
_messageField.contentInset = UIEdgeInsetsMake(-15, 0, 0, 0);
// _messageField.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 0, 10);
[_tableController setChatRoomDelegate:self];
+ [_imagesCollectionView registerClass:[UIImageViewDeletable class] forCellWithReuseIdentifier:NSStringFromClass([UIImageViewDeletable class])];
+ [_imagesCollectionView setDataSource:self];
}
- (void)viewWillAppear:(BOOL)animated {
@@ -123,6 +127,24 @@ static UICompositeViewDescription *compositeDescription = nil;
selector:@selector(callUpdateEvent:)
name:kLinphoneCallUpdate
object:nil];
+
+ if ([_imagesArray count] > 0) {
+ [UIView animateWithDuration:0
+ delay:0
+ options:UIViewAnimationOptionBeginFromCurrentState
+ animations:^{
+ // resizing imagesView
+ CGRect imagesFrame = [_imagesView frame];
+ imagesFrame.origin.y = [_messageView frame].origin.y - 100;
+ imagesFrame.size.height = 100;
+ [_imagesView setFrame:imagesFrame];
+ // resizing chatTable
+ CGRect tableViewFrame = [_tableController.tableView frame];
+ tableViewFrame.size.height -= 100;
+ [_tableController.tableView setFrame:tableViewFrame];
+ }
+ completion:nil];
+ }
}
- (void)viewWillDisappear:(BOOL)animated {
@@ -151,6 +173,7 @@ static UICompositeViewDescription *compositeDescription = nil;
[self configureForRoom:true];
_backButton.hidden = _tableController.isEditing;
[_tableController scrollToBottom:true];
+ [self refreshImageDrawer];
}
#pragma mark -
@@ -201,7 +224,6 @@ static UICompositeViewDescription *compositeDescription = nil;
_messageField.editable = !linphone_chat_room_has_been_left(_chatRoom);
_pictureButton.enabled = !linphone_chat_room_has_been_left(_chatRoom);
_messageView.userInteractionEnabled = !linphone_chat_room_has_been_left(_chatRoom);
- [_messageField setText:@""];
[_tableController setChatRoom:_chatRoom];
_chatView.hidden = NO;
@@ -211,38 +233,34 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)shareFile {
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
-
- NSDictionary *dict = [defaults valueForKey:@"img"];
- NSDictionary *dictWeb = [defaults valueForKey:@"web"];
- NSDictionary *dictFile = [defaults valueForKey:@"mov"];
- NSDictionary *dictText = [defaults valueForKey:@"text"];
+ NSDictionary *dict = [defaults valueForKey:@"photoData"];
+ NSDictionary *dictFile = [defaults valueForKey:@"icloudData"];
+ NSDictionary *dictUrl = [defaults valueForKey:@"url"];
if (dict) {
- //share photo
- NSData *data = dict[@"nsData"];
- UIImage *image = [[UIImage alloc] initWithData:data];
- [self chooseImageQuality:image url:nil];
- [defaults removeObjectForKey:@"img"];
- } else if (dictWeb) {
- //share url, if local file, then upload file
- NSString *url = dictWeb[@"url"];
- NSURL *fileUrl = [NSURL fileURLWithPath:url];
- if ([url hasPrefix:@"file"]) {
- //local file
- NSData *data = dictWeb[@"nsData"];
- [self confirmShare:data url:fileUrl text:nil];
+ //file shared from photo lib
+ NSString *fileName = dict[@"url"];
+ NSString *key = [[fileName componentsSeparatedByString:@"."] firstObject];
+ NSMutableDictionary * assetDict = [LinphoneUtils photoAssetsDictionary];
+ if ([fileName hasSuffix:@"JPG"] || [fileName hasSuffix:@"PNG"]) {
+ UIImage *image = [[UIImage alloc] initWithData:dict[@"nsData"]];
+ [self chooseImageQuality:image assetId:[[assetDict objectForKey:key] localIdentifier]];
+ } else if ([fileName hasSuffix:@"MOV"]) {
+ [self confirmShare:dict[@"nsData"] url:nil fileName:nil assetId:[[assetDict objectForKey:key] localIdentifier]];
} else {
- [self confirmShare:nil url:nil text:url];
+ LOGE(@"Unable to parse file %@",fileName);
}
- [defaults removeObjectForKey:@"web"];
- }else if (dictFile) {
- //share file
- NSData *data = dictFile[@"nsData"];
- [self confirmShare:data url:[NSURL fileURLWithPath:dictFile[@"url"]] text:nil];
- [defaults removeObjectForKey:@"mov"];
- }else if (dictText) {
- //share text
- [self confirmShare:nil url:nil text:dictText[@"name"]];
- [defaults removeObjectForKey:@"text"];
+
+ [defaults removeObjectForKey:@"photoData"];
+ } else if (dictFile) {
+ NSString *fileName = dictFile[@"url"];
+ [self confirmShare:dictFile[@"nsData"] url:nil fileName:fileName assetId:nil];
+
+ [defaults removeObjectForKey:@"icloudData"];
+ } else if (dictUrl) {
+ NSString *url = dictUrl[@"url"];
+ [self confirmShare:nil url:url fileName:nil assetId:nil];
+
+ [defaults removeObjectForKey:@"url"];
}
}
@@ -308,38 +326,15 @@ static UICompositeViewDescription *compositeDescription = nil;
return TRUE;
}
-- (void)saveAndSend:(UIImage *)image url:(NSURL *)url withQuality:(float)quality{
- // photo from Camera, must be saved first
- if (url == 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]);
-
- 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 {
- LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
- [self startImageUpload:image url:assetURL withQuality:quality];
- }
- }];
- } else {
- [self startImageUpload:image url:url withQuality:quality];
- }
+- (void)saveAndSend:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality{
+
+ [_imagesArray addObject:image];
+ [_assetIdsArray addObject:phAssetId];
+ [_qualitySettingsArray addObject:@(quality)];
+ [self refreshImageDrawer];
}
-- (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]) {
@@ -349,7 +344,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];
@@ -359,17 +354,17 @@ static UICompositeViewDescription *compositeDescription = nil;
});
}
-- (void)confirmShare:(NSData *)data url:(NSURL *)url text:(NSString *)text {
+- (void)confirmShare:(NSData *)data url:(NSString *)url fileName:(NSString *)fileName assetId:(NSString *)phAssetId {
DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"", nil)];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
-
[sheet addButtonWithTitle:@"send to this friend"
block:^() {
- if(data && url)
- [self startFileUpload:data withUrl:url];
+ if (url)
+ [self sendMessage:url withExterlBodyUrl:nil withInternalURL:nil];
+ else if (fileName)
+ [self startFileUpload:data withName:fileName];
else
- [self sendMessage:text withExterlBodyUrl:nil withInternalURL:nil];
-
+ [self startFileUpload:data assetId:phAssetId];
}];
[sheet addCancelButtonWithTitle:NSLocalizedString(@"Cancel", nil) block:nil];
@@ -481,6 +476,12 @@ static UICompositeViewDescription *compositeDescription = nil;
messageRect.size.height += diff;
[_messageView setFrame:messageRect];
+ if ([_imagesArray count] > 0) {
+ CGRect _imagesRect = [_imagesView frame];
+ _imagesRect.origin.y -= diff;
+ [_imagesView setFrame:_imagesRect];
+ }
+
// Always stay at bottom
if (scrollOnGrowingEnabled) {
CGRect tableFrame = [_tableController.view frame];
@@ -518,6 +519,15 @@ static UICompositeViewDescription *compositeDescription = nil;
}
- (IBAction)onSendClick:(id)event {
+ if ([_imagesArray count] > 0) {
+ int i = 0;
+ for (i = 0; i < [_imagesArray count] - 1; ++i) {
+ [self startImageUpload:[_imagesArray objectAtIndex:i] assetId:[_assetIdsArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue];
+ }
+ [self startImageUpload:[_imagesArray objectAtIndex:i] assetId:[_assetIdsArray objectAtIndex:i] withQuality:[_qualitySettingsArray objectAtIndex:i].floatValue andMessage:[self.messageField text]];
+ [self clearMessageView];
+ return;
+ }
if ([self sendMessage:[_messageField text] withExterlBodyUrl:nil withInternalURL:nil]) {
scrollOnGrowingEnabled = FALSE;
[_messageField setText:@""];
@@ -601,16 +611,31 @@ 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;
}
-- (BOOL)startFileUpload:(NSData *)data withUrl:(NSURL *)url {
+- (BOOL)startImageUpload:(UIImage *)image assetId:(NSString *)phAssetId withQuality:(float)quality andMessage:(NSString *)message {
FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
- [fileTransfer uploadFile:data forChatRoom:_chatRoom withUrl:url];
+ [fileTransfer setText:message];
+ [fileTransfer upload:image withassetId:phAssetId forChatRoom:_chatRoom withQuality:quality];
+ [_tableController scrollToBottom:true];
+ return TRUE;
+}
+
+- (BOOL)startFileUpload:(NSData *)data assetId:phAssetId {
+ FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
+ [fileTransfer uploadVideo:data withassetId:phAssetId forChatRoom:_chatRoom];
+ [_tableController scrollToBottom:true];
+ return TRUE;
+}
+
+- (BOOL)startFileUpload:(NSData *)data withName:(NSString *)name {
+ FileTransferDelegate *fileTransfer = [[FileTransferDelegate alloc] init];
+ [fileTransfer uploadFile:data forChatRoom:_chatRoom withName:name];
[_tableController scrollToBottom:true];
return TRUE;
}
@@ -621,7 +646,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) {
@@ -635,9 +660,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 {
@@ -651,6 +674,9 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)keyboardWillHide:(NSNotification *)notif {
NSTimeInterval duration = [[[notif userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+
+ int heightDiff = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 55 : 105;
+
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
@@ -694,6 +720,19 @@ static UICompositeViewDescription *compositeDescription = nil;
}
}
}
+
+
+ if ([_imagesArray count] > 0){
+ // resizing imagesView
+ CGRect imagesFrame = [_imagesView frame];
+ imagesFrame.origin.y = [_messageView frame].origin.y - heightDiff;
+ imagesFrame.size.height = heightDiff;
+ [_imagesView setFrame:imagesFrame];
+ // resizing chatTable
+ CGRect tableViewFrame = [_tableController.tableView frame];
+ tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
+ [_tableController.tableView setFrame:tableViewFrame];
+ }
}
completion:^(BOOL finished){
@@ -702,7 +741,9 @@ static UICompositeViewDescription *compositeDescription = nil;
- (void)keyboardWillShow:(NSNotification *)notif {
NSTimeInterval duration = [[[notif userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
-
+
+ int heightDiff = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 55 : 105;
+
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
@@ -749,6 +790,18 @@ static UICompositeViewDescription *compositeDescription = nil;
[_messageView frame].origin.y - tableFrame.origin.y - composeIndicatorCompensation;
[_tableController.view setFrame:tableFrame];
}
+
+ if ([_imagesArray count] > 0){
+ // resizing imagesView
+ CGRect imagesFrame = [_imagesView frame];
+ imagesFrame.origin.y = [_messageView frame].origin.y - heightDiff;
+ imagesFrame.size.height = heightDiff;
+ [_imagesView setFrame:imagesFrame];
+ // resizing chatTable
+ CGRect tableViewFrame = [_tableController.tableView frame];
+ tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
+ [_tableController.tableView setFrame:tableViewFrame];
+ }
// Scroll
NSInteger lastSection = [_tableController.tableView numberOfSections] - 1;
@@ -761,8 +814,10 @@ static UICompositeViewDescription *compositeDescription = nil;
animated:FALSE];
}
}
+
}
completion:^(BOOL finished){
+
}];
}
@@ -852,7 +907,17 @@ void on_chat_room_conference_left(LinphoneChatRoom *cr, const LinphoneEventLog *
[view.tableController scrollToBottom:true];
}
-- (void)openResults:(NSString *) filePath
+- (void)getIcloudFiles
+{
+ _documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"public.data"]
+ inMode:UIDocumentPickerModeImport];
+ _documentPicker.delegate = self;
+
+ _documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
+ [self presentViewController:_documentPicker animated:YES completion:nil];
+}
+
+- (void)openFile:(NSString *) filePath
{
// Open the controller.
_documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:filePath]];
@@ -866,4 +931,95 @@ void on_chat_room_conference_left(LinphoneChatRoom *cr, const LinphoneEventLog *
}
}
+- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
+
+ NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
+ [fileCoordinator coordinateReadingItemAtURL:url options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL * _Nonnull newURL) {
+
+ NSString *fileName = [newURL lastPathComponent];
+ NSData *data = [NSData dataWithContentsOfURL:newURL];
+
+ NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:fileName];
+
+ [[NSFileManager defaultManager] createFileAtPath:filePath contents:data attributes:nil];
+ [self openFile:filePath];
+ }];
+}
+
+- (void)deleteImageWithAssetId:(NSString *)assetId {
+ NSUInteger key = [_assetIdsArray indexOfObject:assetId];
+ [_imagesArray removeObjectAtIndex:key];
+ [_assetIdsArray removeObjectAtIndex:key];
+ [self refreshImageDrawer];
+}
+
+- (void)clearMessageView {
+ [_messageField setText:@""];
+ _imagesArray = [NSMutableArray array];
+ _assetIdsArray = [NSMutableArray array];
+
+ [self refreshImageDrawer];
+}
+
+- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
+ return [_imagesArray count];
+}
+
+- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
+ UIImageViewDeletable *imgView = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UIImageViewDeletable class]) forIndexPath:indexPath];
+ CGRect imgFrame = imgView.frame;
+ imgFrame.origin.y = 5;
+ if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
+ imgFrame.size.height = 50;
+ } else {
+ imgFrame.size.height = 100;
+ }
+ [imgView.image setImage:[UIImage resizeImage:[_imagesArray objectAtIndex:[indexPath item]] withMaxWidth:imgFrame.size.width andMaxHeight:imgFrame.size.height]];
+ [imgView setAssetId:[_assetIdsArray objectAtIndex:[indexPath item]]];
+ [imgView setDeleteDelegate:self];
+ [imgView setFrame:imgFrame];
+ [_sendButton setEnabled:TRUE];
+ return imgView;
+}
+
+- (void)refreshImageDrawer {
+ int heightDiff = UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) ? 55 : 105;
+
+ if ([_imagesArray count] == 0) {
+ [UIView animateWithDuration:0
+ delay:0
+ options:UIViewAnimationOptionBeginFromCurrentState
+ animations:^{
+ // resizing imagesView
+ CGRect imagesFrame = [_imagesView frame];
+ imagesFrame.origin.y = [_messageView frame].origin.y;
+ imagesFrame.size.height = 0;
+ [_imagesView setFrame:imagesFrame];
+ // resizing chatTable
+ CGRect tableViewFrame = [_tableController.tableView frame];
+ tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
+ [_tableController.tableView setFrame:tableViewFrame];
+ }
+ completion:nil];
+ if ([_messageField.text isEqualToString:@""])
+ [_sendButton setEnabled:FALSE];
+ } else {
+ [UIView animateWithDuration:0
+ delay:0
+ options:UIViewAnimationOptionBeginFromCurrentState
+ animations:^{
+ // resizing imagesView
+ CGRect imagesFrame = [_imagesView frame];
+ imagesFrame.origin.y = [_messageView frame].origin.y - heightDiff;
+ imagesFrame.size.height = heightDiff;
+ [_imagesView setFrame:imagesFrame];
+ // resizing chatTable
+ CGRect tableViewFrame = [_tableController.tableView frame];
+ tableViewFrame.size.height = imagesFrame.origin.y - tableViewFrame.origin.y;
+ [_tableController.tableView setFrame:tableViewFrame];
+ }
+ completion:^(BOOL result){[_imagesCollectionView reloadData];}];
+ }
+}
+
@end
diff --git a/Classes/ChatsListTableView.m b/Classes/ChatsListTableView.m
index abeeeee96..ad78cb768 100644
--- a/Classes/ChatsListTableView.m
+++ b/Classes/ChatsListTableView.m
@@ -141,6 +141,10 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
while (sorted) {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
LinphoneChatRoom *cr = sorted->data;
+ if (!cr) {
+ sorted = sorted->next;
+ continue;
+ }
const LinphoneAddress *peer_address = linphone_chat_room_get_peer_address(cr);
const LinphoneAddress *local_address = linphone_chat_room_get_local_address(cr);
NSString *display;
@@ -148,9 +152,17 @@ static int sorted_history_comparison(LinphoneChatRoom *to_insert, LinphoneChatRo
forKey:@"peer"];
[dict setObject:[NSString stringWithUTF8String:linphone_address_as_string_uri_only(local_address)]
forKey:@"local"];
- if (linphone_chat_room_get_conference_address(cr))
+ if (linphone_chat_room_get_conference_address(cr)) {
+ if (!linphone_chat_room_get_subject(cr)) {
+ sorted = sorted->next;
+ continue;
+ }
display = [NSString stringWithUTF8String:linphone_chat_room_get_subject(cr)];
- else {
+ } else {
+ if (!linphone_address_get_username(peer_address)) {
+ sorted = sorted->next;
+ continue;
+ }
display = [NSString stringWithUTF8String:linphone_address_get_display_name(peer_address)?:linphone_address_get_username(peer_address)];
if ([FastAddressBook imageForAddress:peer_address])
[dict setObject:UIImageJPEGRepresentation([UIImage resizeImage:[FastAddressBook imageForAddress:peer_address]
diff --git a/Classes/ImagePickerView.h b/Classes/ImagePickerView.h
index 1f03bb5fd..bc02c7a15 100644
--- a/Classes/ImagePickerView.h
+++ b/Classes/ImagePickerView.h
@@ -21,7 +21,7 @@
@protocol ImagePickerDelegate
-- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info;
+- (void)imagePickerDelegateImage:(UIImage *)image info:(NSString *)phAssetId;
@end
diff --git a/Classes/ImagePickerView.m b/Classes/ImagePickerView.m
index c5ee92daf..fdf5f602c 100644
--- a/Classes/ImagePickerView.m
+++ b/Classes/ImagePickerView.m
@@ -20,7 +20,6 @@
#import
#import
#import
-#import
#import "ImagePickerView.h"
#import "PhoneMainView.h"
@@ -162,15 +161,42 @@ 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 && imagePickerDelegate != nil) {
- [imagePickerDelegate imagePickerDelegateImage:image info:info];
- }
+
+ NSURL *alassetURL = [info objectForKey:UIImagePickerControllerReferenceURL];
+ PHFetchResult *phFetchResult = [PHAsset fetchAssetsWithALAssetURLs:@[alassetURL] options:nil];
+ PHAsset *phasset = [phFetchResult firstObject];
+ //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) 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];
}
@@ -223,35 +249,57 @@ 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];
+ if ([PHPhotoLibrary authorizationStatus] == 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 {
+ [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if ([PHPhotoLibrary authorizationStatus] == 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];
+ }
+ });
+ }];
+ }
}
@end
diff --git a/Classes/LinphoneManager.h b/Classes/LinphoneManager.h
index c1eab0464..9dd0454de 100644
--- a/Classes/LinphoneManager.h
+++ b/Classes/LinphoneManager.h
@@ -20,7 +20,7 @@
#import
#import
#import
-#import
+#import
#import
#import
@@ -208,6 +208,8 @@ typedef struct _LinphoneManagerSounds {
- (void)checkNewVersion;
+- (void)loadAvatar;
+
@property ProviderDelegate *providerDelegate;
@property (readonly) BOOL isTesting;
@@ -225,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);
@@ -238,5 +239,6 @@ typedef struct _LinphoneManagerSounds {
@property NSDictionary *pushDict;
@property(strong, nonatomic) OrderedDictionary *linphoneManagerAddressBookMap;
@property (nonatomic, assign) BOOL contactsUpdated;
+@property UIImage *avatar;
@end
diff --git a/Classes/LinphoneManager.m b/Classes/LinphoneManager.m
index f67b607c0..bb6365458 100644
--- a/Classes/LinphoneManager.m
+++ b/Classes/LinphoneManager.m
@@ -264,7 +264,6 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
_fileTransferDelegates = [[NSMutableArray alloc] init];
_linphoneManagerAddressBookMap = [[OrderedDictionary alloc] init];
pushCallIDs = [[NSMutableArray alloc] init];
- _photoLibrary = [[ALAssetsLibrary alloc] init];
_isTesting = [LinphoneManager isRunningTests];
[self renameDefaultSettings];
[self copyDefaultSettings];
@@ -289,6 +288,7 @@ struct codec_name_pref_table codec_pref_table[] = {{"speex", 8000, "speex_8k_pre
}
[self migrateFromUserPrefs];
+ [self loadAvatar];
}
return self;
}
@@ -1231,7 +1231,39 @@ static void linphone_iphone_popup_password_request(LinphoneCore *lc, LinphoneAut
}
content.sound = [UNNotificationSound soundNamed:@"msg.caf"];
content.categoryIdentifier = @"msg_cat";
- content.userInfo = @{@"from" : from, @"peer_addr" : peer_uri, @"local_addr" : local_uri, @"CallId" : callID};
+ // save data to user info for rich notification content
+ NSMutableArray *msgs = [NSMutableArray array];
+ bctbx_list_t *history = linphone_chat_room_get_history(room, 6);
+ while (history) {
+ NSMutableDictionary *msgData = [NSMutableDictionary dictionary];
+ LinphoneChatMessage *msg = history->data;
+ const char *state = linphone_chat_message_state_to_string(linphone_chat_message_get_state(msg));
+ bool_t isOutgoing = linphone_chat_message_is_outgoing(msg);
+ bool_t isFileTransfer = (linphone_chat_message_get_file_transfer_information(msg) != NULL);
+ const LinphoneAddress *fromAddress = linphone_chat_message_get_from_address(msg);
+ NSString *displayNameDate = [NSString stringWithFormat:@"%@ - %@", [LinphoneUtils timeToString:linphone_chat_message_get_time(msg)
+ withFormat:LinphoneDateChatBubble],
+ [FastAddressBook displayNameForAddress:fromAddress]];
+ UIImage *fromImage = [UIImage resizeImage:[FastAddressBook imageForAddress:fromAddress]
+ withMaxWidth:200
+ andMaxHeight:200];
+ NSData *fromImageData = UIImageJPEGRepresentation(fromImage, 1);
+ [msgData setObject:[NSString stringWithUTF8String:state] forKey:@"state"];
+ [msgData setObject:displayNameDate forKey:@"displayNameDate"];
+ [msgData setObject:[NSNumber numberWithBool:isFileTransfer] forKey:@"isFileTransfer"];
+ [msgData setObject:fromImageData forKey:@"fromImageData"];
+ if (isFileTransfer) {
+ LinphoneContent *file = linphone_chat_message_get_file_transfer_information(msg);
+ const char *filename = linphone_content_get_name(file);
+ [msgData setObject:[NSString stringWithUTF8String:filename] forKey:@"msg"];
+ } else {
+ [msgData setObject:[UIChatBubbleTextCell TextMessageForChat:msg] forKey:@"msg"];
+ }
+ [msgData setObject:[NSNumber numberWithBool:isOutgoing] forKey:@"isOutgoing"];
+ [msgs addObject:msgData];
+ history = bctbx_list_next(history);
+ }
+ content.userInfo = @{@"from" : from, @"peer_addr" : peer_uri, @"local_addr" : local_uri, @"CallId" : callID, @"msgs" : msgs};
content.accessibilityLabel = @"Message notif";
UNNotificationRequest *req = [UNNotificationRequest requestWithIdentifier:@"call_request" content:content trigger:NULL];
[[UNUserNotificationCenter currentNotificationCenter]
@@ -2888,20 +2920,19 @@ static int comp_call_state_paused(const LinphoneCall *call, const void *param) {
}
+ (void)setValueInMessageAppData:(id)value forKey:(NSString *)key inMessage:(LinphoneChatMessage *)msg {
+ NSMutableDictionary *appDataDict = [NSMutableDictionary dictionary];
+ const char *appData = linphone_chat_message_get_appdata(msg);
+ if (appData) {
+ appDataDict = [NSJSONSerialization JSONObjectWithData:[NSData dataWithBytes:appData length:strlen(appData)]
+ options:NSJSONReadingMutableContainers
+ error:nil];
+ }
- NSMutableDictionary *appDataDict = [NSMutableDictionary dictionary];
- const char *appData = linphone_chat_message_get_appdata(msg);
- if (appData) {
- appDataDict = [NSJSONSerialization JSONObjectWithData:[NSData dataWithBytes:appData length:strlen(appData)]
- options:NSJSONReadingMutableContainers
- error:nil];
- }
+ [appDataDict setValue:value forKey:key];
- [appDataDict setValue:value forKey:key];
-
- NSData *data = [NSJSONSerialization dataWithJSONObject:appDataDict options:0 error:nil];
- NSString *appdataJSON = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- linphone_chat_message_set_appdata(msg, [appdataJSON UTF8String]);
+ NSData *data = [NSJSONSerialization dataWithJSONObject:appDataDict options:0 error:nil];
+ NSString *appdataJSON = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+ linphone_chat_message_set_appdata(msg, [appdataJSON UTF8String]);
}
#pragma mark - LPConfig Functions
@@ -3078,4 +3109,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 *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
diff --git a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
index 65e3aef60..50403d66f 100644
--- a/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
+++ b/Classes/LinphoneUI/Base.lproj/UIChatBubblePhotoCell.xib
@@ -1,5 +1,5 @@
-
+
@@ -21,12 +21,14 @@
+
+
@@ -35,19 +37,19 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -55,7 +57,7 @@
-
-
+
diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.h b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
index 43e4deeb0..1aa697eec 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.h
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.h
@@ -36,6 +36,7 @@
@property(weak, nonatomic) IBOutlet UIView *imageSubView;
@property (strong, nonatomic) IBOutlet UITapGestureRecognizer *openRecognizer;
@property(weak, nonatomic) IBOutlet UIView *totalView;
+@property (weak, nonatomic) IBOutlet UIView *finalAssetView;
@property (weak, nonatomic) IBOutlet UIImageView *finalImage;
@property(strong, nonatomic) IBOutlet UITapGestureRecognizer *imageGestureRecognizer;
diff --git a/Classes/LinphoneUI/UIChatBubblePhotoCell.m b/Classes/LinphoneUI/UIChatBubblePhotoCell.m
index d5217c68e..ca81111a7 100644
--- a/Classes/LinphoneUI/UIChatBubblePhotoCell.m
+++ b/Classes/LinphoneUI/UIChatBubblePhotoCell.m
@@ -30,16 +30,14 @@
@implementation UIChatBubblePhotoCell {
FileTransferDelegate *_ftd;
CGSize imageSize, bubbleSize, videoDefaultSize;
- int actualAvailableWidth;
ChatConversationTableView *chatTableView;
- //CGImageRef displayedImage;
+ BOOL assetIsLoaded;
}
#pragma mark - Lifecycle Functions
- (id)initWithIdentifier:(NSString *)identifier {
if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]) != nil) {
- // TODO: remove text cell subview
NSArray *arrayOfViews =
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
// resize cell to match .nib size. It is needed when resized the cell to
@@ -51,15 +49,18 @@
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;
}
+- (void)onDelete {
+ [super onDelete];
+}
+
#pragma mark -
- (void)setEvent:(LinphoneEventLog *)event {
if (!event || !(linphone_event_log_get_type(event) == LinphoneEventLogTypeConferenceChatMessage))
@@ -76,6 +77,7 @@
_finalImage.image = nil;
_finalImage.hidden = TRUE;
_fileTransferProgress.progress = 0;
+ assetIsLoaded = FALSE;
[self disconnectFromFileDelegate];
if (amessage) {
@@ -98,54 +100,33 @@
[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;
_finalImage.hidden = NO;
+ [self layoutSubviews];
});
}
-- (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) loadVideoAsset: (AVAsset *) asset {
- // Calculate a time for the snapshot - I'm using the half way mark.
- CMTime duration = [asset duration];
- CMTime snapshot = CMTimeMake(duration.value / 2, duration.timescale);
- // Create a generator and copy image at the time.
- // I'm not capturing the actual time or an error.
- AVAssetImageGenerator *generator =
- [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
- CGImageRef imageRef = [generator copyCGImageAtTime:snapshot
- actualTime:nil
- error:nil];
-
- UIImage *thumb = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
-
- UIGraphicsBeginImageContext(videoDefaultSize);
- [thumb drawInRect:CGRectMake(0, 0, videoDefaultSize.width, videoDefaultSize.height)];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- [self loadImageAsset:nil thumb:thumb image:image];
-
- // put the play button in the top
- CGRect newFrame = _playButton.frame;
- newFrame.origin.x = _finalImage.frame.origin.x/2;
- newFrame.origin.y = _finalImage.frame.origin.y/2;
- _playButton.frame = newFrame;
+- (void) loadAsset:(PHAsset *) 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) {
+ imageSize = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[image size] withWidth:chatTableView.tableView.frame.size.width - 40];
+ 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) loadFileAsset {
@@ -156,13 +137,25 @@
});
}
+- (void) loadPlaceholder {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // Change this to load placeholder image when no asset id
+ //[_finalImage setImage:image];
+ //[_messageImageView setAsset:asset];
+ [_messageImageView stopLoading];
+ _messageImageView.hidden = YES;
+ _imageGestureRecognizer.enabled = YES;
+ _finalImage.hidden = NO;
+ [self layoutSubviews];
+ });
+}
+
- (void)update {
if (self.message == nil) {
LOGW(@"Cannot update message room cell: NULL message");
return;
}
- [super update];
-
+ [super update];
const char *url = linphone_chat_message_get_external_body_url(self.message);
BOOL is_external =
(url && (strstr(url, "http") == url)) || linphone_chat_message_get_file_transfer_information(self.message);
@@ -183,52 +176,21 @@
if ([localImage isEqualToString:@"saving..."] || [localVideo isEqualToString:@"saving..."] || [localFile isEqualToString:@"saving..."]) {
_cancelButton.hidden = _fileTransferProgress.hidden = _downloadButton.hidden = _playButton.hidden = _fileName.hidden = YES;
fullScreenImage = YES;
- } else {
+ } else if(!assetIsLoaded) {
+ assetIsLoaded = TRUE;
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");
- }];
+ [self loadFirstImage:localImage type:PHAssetMediaTypeImage];
}
- } else if (localVideo) {
+ }
+ else if (localVideo) {
if (_messageImageView.image == nil) {
- [_messageImageView startLoading];
- // read video from Documents
- NSString *filePath = [LinphoneManager documentFile:localVideo];
- NSURL *url = [NSURL fileURLWithPath:filePath];
- AVAsset *asset = [AVAsset assetWithURL:url];
- if (asset)
- [self loadVideoAsset:asset];
+ [self loadFirstImage:localVideo type:PHAssetMediaTypeVideo];
+ _imageGestureRecognizer.enabled = NO;
}
- } else if (localFile) {
+ }
+ else if (localFile) {
NSString *text = [NSString stringWithFormat:@"📎 %@",localFile];
_fileName.text = text;
[self loadFileAsset];
@@ -246,20 +208,32 @@
fullScreenImage = YES;
_playButton.hidden = localVideo ? NO : YES;
_fileName.hidden = localFile ? NO : YES;
+ // Should fix cell not resizing after doanloading image.
+ [self layoutSubviews];
}
}
}
- // 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)loadFirstImage:(NSString *)key type:(PHAssetMediaType)type {
+ [_messageImageView startLoading];
+ PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:key] options:nil];
+ UIImage *img = nil;
+
+ img = [chatTableView.imagesInChatroom objectForKey:key];
+ PHAsset *asset = [assets firstObject];
+ if (!asset)
+ [self loadPlaceholder];
+ else if (asset.mediaType == type)
+ img = nil;
+ if (img)
+ [self loadImageAsset:asset image:img];
+ else
+ [self loadAsset:asset];
}
- (void)fileErrorBlock {
- DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Can't open this file", nil)];
+ DTActionSheet *sheet = [[DTActionSheet alloc] initWithTitle:NSLocalizedString(@"Can't find this file", nil)];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[sheet addCancelButtonWithTitle:NSLocalizedString(@"OK", nil) block:nil];
dispatch_async(dispatch_get_main_queue(), ^{
@@ -280,33 +254,35 @@
}
- (IBAction)onPlayClick:(id)sender {
- NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:self.message];
- NSString *filePath = [LinphoneManager documentFile:localVideo];
- NSFileManager *fileManager = [NSFileManager defaultManager];
-
- if ([fileManager fileExistsAtPath:filePath]) {
- // create a player view controller
- AVPlayer *player = [AVPlayer playerWithURL:[[NSURL alloc] initFileURLWithPath:filePath]];
- AVPlayerViewController *controller = [[AVPlayerViewController alloc] init];
- [PhoneMainView.instance presentViewController:controller animated:YES completion:nil];
- controller.player = player;
- [player play];
- } else {
- [self fileErrorBlock];
- }
+ PHAsset *asset = [_messageImageView asset];
+ PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
+ // options.synchronous = TRUE;
+ [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:options resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
+ if(playerItem) {
+ AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
+ AVPlayerViewController *controller = [[AVPlayerViewController alloc] init];
+ [PhoneMainView.instance presentViewController:controller animated:YES completion:nil];
+ controller.player = player;
+ [player play];
+ }
+ else {
+ [self fileErrorBlock];
+ }
+ }];
}
- (IBAction)onOpenClick:(id)event {
- NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:self.message];
- NSString *filePath = [LinphoneManager documentFile:localFile];
- NSFileManager *fileManager = [NSFileManager defaultManager];
-
- if ([fileManager fileExistsAtPath:filePath]) {
- ChatConversationView *view = VIEW(ChatConversationView);
- [view openResults:filePath];
- } else {
- [self fileErrorBlock];
- }
+ ChatConversationView *view = VIEW(ChatConversationView);
+ NSString *cachedFile = [LinphoneManager getMessageAppDataForKey:@"cachedfile" inMessage:self.message];
+ if (cachedFile) {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if ([fileManager fileExistsAtPath:cachedFile]) {
+ [view openFile:cachedFile];
+ } else {
+ [self fileErrorBlock];
+ }
+ } else
+ [view getIcloudFiles];
}
@@ -336,9 +312,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");
+ }
+ }];
}
}
}
@@ -366,7 +351,8 @@
}
- (void)disconnectFromFileDelegate {
- [NSNotificationCenter.defaultCenter removeObserver:self];
+ [NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneFileTransferSendUpdate object:_ftd];
+ [NSNotificationCenter.defaultCenter removeObserver:self name:kLinphoneFileTransferRecvUpdate object:_ftd];
_ftd = nil;
}
@@ -399,32 +385,7 @@
}
}
-+ (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;
- UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
BOOL is_outgoing = linphone_chat_message_is_outgoing(super.message);
CGRect bubbleFrame = super.bubbleView.frame;
int origin_x;
@@ -433,7 +394,7 @@
bubbleFrame.size = bubbleSize;
- if (tableView.isEditing) {
+ if (chatTableView.tableView.isEditing) {
origin_x = 0;
} else {
origin_x = (is_outgoing ? self.frame.size.width - bubbleFrame.size.width : 0);
@@ -442,27 +403,30 @@
bubbleFrame.origin.x = origin_x;
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;
+
+ // Resizing Image view
+ if (_finalImage.image) {
+ CGRect imgFrame = self.finalAssetView.frame;
+ imgFrame.size = [UIChatBubbleTextCell getMediaMessageSizefromOriginalSize:[_finalImage.image size] withWidth:chatTableView.tableView.frame.size.width - 40];
+ imgFrame.origin.x = (bubbleFrame.size.width - imgFrame.size.width)/2;
+ self.finalAssetView.frame = imgFrame;
+
+ // Positioning text message
+ const char *utf8Text = linphone_chat_message_get_text_content(self.message);
+
+ CGRect textFrame = self.messageText.frame;
+ textFrame.origin = CGPointMake(textFrame.origin.x, self.finalAssetView.frame.origin.y + self.finalAssetView.frame.size.height);
+ if (!utf8Text) {
+ textFrame.size.height = 0;
+ } else {
+ textFrame.size.height = bubbleFrame.size.height - textFrame.origin.x;
+ }
+
+ self.messageText.frame = textFrame;
+ LOGD([NSString stringWithFormat:@"Text of the photoCell: %@, size of the text of the photoCell: %@", [self.messageText text], NSStringFromCGSize(textFrame.size)]);
}
- 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
diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.h b/Classes/LinphoneUI/UIChatBubbleTextCell.h
index 26966cbb5..18f5d879c 100644
--- a/Classes/LinphoneUI/UIChatBubbleTextCell.h
+++ b/Classes/LinphoneUI/UIChatBubbleTextCell.h
@@ -55,5 +55,6 @@
+ (CGSize)ViewHeightForMessage:(LinphoneChatMessage *)chat withWidth:(int)width;
+ (NSString *)TextMessageForChat:(LinphoneChatMessage *)message;
+ (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font;
++ (NSString *)ContactDateForChat:(LinphoneChatMessage *)message;
@end
diff --git a/Classes/LinphoneUI/UIChatBubbleTextCell.m b/Classes/LinphoneUI/UIChatBubbleTextCell.m
index 0aabc729c..85b20dce9 100644
--- a/Classes/LinphoneUI/UIChatBubbleTextCell.m
+++ b/Classes/LinphoneUI/UIChatBubbleTextCell.m
@@ -96,9 +96,11 @@
const LinphoneContent *last_content = linphone_chat_message_get_file_transfer_information(message);
// Last message was a file transfer (image) so display a picture...
if (url || last_content) {
+ if (linphone_chat_message_get_text_content(message))
+ return [NSString stringWithUTF8String:linphone_chat_message_get_text_content(message)];
return @"🗻";
} else {
- const char *text = linphone_chat_message_get_text_content(message) ?: "";
+ const char *text = linphone_chat_message_get_text_content(message) ?: "";
return [NSString stringWithUTF8String:text] ?: [NSString stringWithCString:text encoding:NSASCIIStringEncoding]
?: NSLocalizedString(@"(invalid string)", nil);
}
@@ -127,6 +129,7 @@
_statusInProgressSpinner.accessibilityLabel = @"Delivery in progress";
if (_messageText) {
+ LOGD(_messageText.text);
[_messageText 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 */
@@ -232,29 +235,45 @@
if (linphone_chat_message_get_file_transfer_information(_message) != NULL) {
NSString *localImage = [LinphoneManager getMessageAppDataForKey:@"localimage" inMessage:_message];
NSNumber *uploadQuality =[LinphoneManager getMessageAppDataForKey:@"uploadQuality" inMessage:_message];
- NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message];
- NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message];
- NSString *fileName = localVideo ? localVideo : localFile;
- NSURL *imageUrl = [NSURL URLWithString:localImage];
+
+ // TODO: do resend for video and files
+ /*NSString *localVideo = [LinphoneManager getMessageAppDataForKey:@"localvideo" inMessage:_message];
+ NSString *localFile = [LinphoneManager getMessageAppDataForKey:@"localfile" inMessage:_message];*/
+
[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");
- }];
- } else if(fileName) {
+ ChatConversationTableView *tableView = VIEW(ChatConversationView).tableController;
+ UIImage *img = [tableView.imagesInChatroom objectForKey:localImage];
+ if (img) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
+ ^(void) {
+ [_chatRoomDelegate startImageUpload:img assetId:localImage withQuality:(uploadQuality ? [uploadQuality floatValue] : 0.9)];
+ });
+ } else {
+ PHFetchResult *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:img 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]];
- }
+ }*/
} else {
- [self onDelete];
+ [self onDelete];
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) {
@@ -324,8 +343,6 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44;
[[UIChatBubbleTextCell alloc] initWithIdentifier:NSStringFromClass(UIChatBubbleTextCell.class)];
messageFont = cell.messageText.font;
}
- // UITableView *tableView = VIEW(ChatConversationView).tableController.tableView;
- // if (tableView.isEditing)
width -= 40; /*checkbox */
CGSize size;
const char *url = linphone_chat_message_get_external_body_url(chat);
@@ -341,30 +358,33 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44;
if(localFile) {
CGSize fileSize = CGSizeMake(200, 80);
size = [self getMediaMessageSizefromOriginalSize:fileSize withWidth:width];
- } else if (localVideo) {
- CGSize videoSize = CGSizeMake(320, 240);
- 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);
-
- 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;
+ if (!localImage && !localVideo) {
+ //We are loading the image
+ return CGSizeMake(CELL_MIN_WIDTH + CELL_MESSAGE_X_MARGIN, CELL_MIN_HEIGHT + CELL_MESSAGE_Y_MARGIN);
+ }
+ PHFetchResult *assets;
+ if(localImage)
+ assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localImage] options:nil];
+ else
+ assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localVideo] 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 += 40;
+ size.width -= CELL_MESSAGE_X_MARGIN;
+
+ if (![messageText isEqualToString:@"🗻"]) {
+ CGSize textSize = [self computeBoundingBox:messageText
+ size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX)
+ font:messageFont];
+ size.height += textSize.height;
+ size.width = MAX(textSize.width, size.width);
+ }
}
}
@@ -416,7 +436,7 @@ static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44;
+ (CGSize)getMediaMessageSizefromOriginalSize:(CGSize)originalSize withWidth:(int)width {
CGSize mediaSize = CGSizeMake(0, 0);
- int availableWidth = width - CELL_MESSAGE_X_MARGIN;
+ int availableWidth = width;
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
availableWidth = availableWidth /3;
}
diff --git a/Classes/LinphoneUI/UIImageViewDeletable.h b/Classes/LinphoneUI/UIImageViewDeletable.h
new file mode 100644
index 000000000..f036fd6b7
--- /dev/null
+++ b/Classes/LinphoneUI/UIImageViewDeletable.h
@@ -0,0 +1,26 @@
+//
+// UIImageViewDeletable.h
+// linphone
+//
+// Created by benjamin_verdier on 28/06/2018.
+//
+
+#import
+
+@protocol UIImageViewDeletableDelegate
+
+@required
+
+- (void)deleteImageWithAssetId:(NSString *)assetId;
+
+@end
+
+@interface UIImageViewDeletable : UICollectionViewCell
+
+@property NSString *assetId;
+@property(nonatomic, strong) id deleteDelegate;
+@property (weak, nonatomic) IBOutlet UIImageView *image;
+
+- (IBAction)onDeletePressed;
+
+@end
diff --git a/Classes/LinphoneUI/UIImageViewDeletable.m b/Classes/LinphoneUI/UIImageViewDeletable.m
new file mode 100644
index 000000000..157dd640a
--- /dev/null
+++ b/Classes/LinphoneUI/UIImageViewDeletable.m
@@ -0,0 +1,59 @@
+//
+// UIImageViewDeletable.m
+// linphone
+//
+// Created by benjamin_verdier on 28/06/2018.
+//
+
+#import "UIImageViewDeletable.h"
+
+@interface UIImageViewDeletable ()
+
+@end
+
+@implementation UIImageViewDeletable
+
+- (UIImageViewDeletable *)init {
+ self = [super init];
+ if (self) {
+ NSArray *arrayOfViews =
+ [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
+ // resize cell to match .nib size. It is needed when resized the cell to
+ // correctly adapt its height too
+ UIView *sub = ((UIView *)[arrayOfViews objectAtIndex:arrayOfViews.count - 1]);
+ [self setFrame:CGRectMake(0, 0, sub.frame.size.width, sub.frame.size.height)];
+ [self addSubview:sub];
+ }
+ return self;
+}
+
+
+- (UIImageViewDeletable *)initWithFrame:(CGRect)frame {
+ self = [super initWithFrame:frame];
+ if (self) {
+ NSArray *arrayOfViews =
+ [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil];
+ // resize cell to match .nib size. It is needed when resized the cell to
+ // correctly adapt its height too
+ UIView *sub = ((UIView *)[arrayOfViews objectAtIndex:arrayOfViews.count - 1]);
+ [self setFrame:frame];
+ [self addSubview:sub];
+ }
+ return self;
+}
+
+- (IBAction)onDeletePressed {
+ [_deleteDelegate deleteImageWithAssetId:_assetId];
+}
+
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+ // Get the new view controller using [segue destinationViewController].
+ // Pass the selected object to the new view controller.
+}
+*/
+
+@end
diff --git a/Classes/LinphoneUI/UIImageViewDeletable.xib b/Classes/LinphoneUI/UIImageViewDeletable.xib
new file mode 100644
index 000000000..2fa5d17e1
--- /dev/null
+++ b/Classes/LinphoneUI/UIImageViewDeletable.xib
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Classes/LinphoneUI/UILoadingImageView.h b/Classes/LinphoneUI/UILoadingImageView.h
index be8d0e738..d4caa1794 100644
--- a/Classes/LinphoneUI/UILoadingImageView.h
+++ b/Classes/LinphoneUI/UILoadingImageView.h
@@ -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
diff --git a/Classes/PhoneMainView.m b/Classes/PhoneMainView.m
index 0a0bfd3d8..366e65911 100644
--- a/Classes/PhoneMainView.m
+++ b/Classes/PhoneMainView.m
@@ -923,6 +923,8 @@ static RootViewManager *rootViewManagerInstance = nil;
linphone_chat_room_remove_callbacks(view.chatRoom, view.chatRoomCbs);
view.chatRoomCbs = NULL;
+ if (view.chatRoom != cr)
+ [view clearMessageView];
view.chatRoom = cr;
self.currentRoom = view.chatRoom;
if (PhoneMainView.instance.currentView == view.compositeViewDescription)
diff --git a/Classes/SideMenuView.m b/Classes/SideMenuView.m
index f898c9e60..8a57f81d8 100644
--- a/Classes/SideMenuView.m
+++ b/Classes/SideMenuView.m
@@ -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) {
@@ -113,6 +113,10 @@
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
+
+ [LinphoneManager.instance lpConfigSetString:phAssetId forKey:@"avatar"];
+ _avatarImage.image = [LinphoneUtils selfAvatar];
+ [LinphoneManager.instance loadAvatar];
// Dismiss popover on iPad
if (IPAD) {
@@ -120,27 +124,6 @@
} else {
[PhoneMainView.instance.mainViewController hideSideMenu:NO];
}
-
- NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL];
-
- // taken from camera, must be saved to device first
- if (!url) {
- [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]);
- } else {
- LOGI(@"Image saved to [%@]", [assetURL absoluteString]);
- }
- [LinphoneManager.instance lpConfigSetString:assetURL.absoluteString forKey:@"avatar"];
- _avatarImage.image = [LinphoneUtils selfAvatar];
- }];
- } else {
- [LinphoneManager.instance lpConfigSetString:url.absoluteString forKey:@"avatar"];
- _avatarImage.image = [LinphoneUtils selfAvatar];
- }
}
@end
diff --git a/Classes/Utils/FileTransferDelegate.h b/Classes/Utils/FileTransferDelegate.h
index 10504b144..867285eef 100644
--- a/Classes/Utils/FileTransferDelegate.h
+++ b/Classes/Utils/FileTransferDelegate.h
@@ -12,11 +12,13 @@
@interface FileTransferDelegate : NSObject
-- (void)upload:(UIImage *)image withURL:(NSURL *)url forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
-- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withUrl:(NSURL *)url;
+- (void)upload:(UIImage *)image withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom withQuality:(float)quality;
+- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name;
+- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom;
- (void)cancel;
- (BOOL)download:(LinphoneChatMessage *)message;
- (void)stopAndDestroy;
@property() LinphoneChatMessage *message;
+@property() NSString *text;
@end
diff --git a/Classes/Utils/FileTransferDelegate.m b/Classes/Utils/FileTransferDelegate.m
index 7cd878e71..4b2fd6915 100644
--- a/Classes/Utils/FileTransferDelegate.m
+++ b/Classes/Utils/FileTransferDelegate.m
@@ -75,60 +75,117 @@ 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) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ 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 [%@]", [placeHolder localIdentifier]);
+ [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier]
+ 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),
}];
- } else {
+
+ [thiz stopAndDestroy];
+ CFRelease((__bridge CFTypeRef)thiz);
+ });
+ }];
+ } else if([fileType isEqualToString:@"video"]) {
+ CFBridgingRetain(thiz);
[[LinphoneManager.instance fileTransferDelegates] removeObject:thiz];
+ NSString *name =[NSString stringWithUTF8String:linphone_content_get_name(content)];
+ NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name];
+ [[NSFileManager defaultManager] createFileAtPath:filePath
+ contents:thiz.data
+ attributes:nil];
+ // until image is properly saved, keep a reminder on it so that the
+ // chat bubble is aware of the fact that image is being saved to device
+ [LinphoneManager setValueInMessageAppData:@"saving..." forKey:@"localvideo" inMessage:message];
- NSString *key = [fileType isEqualToString:@"file"] ? @"localfile" : @"localvideo";
+ __block PHObjectPlaceholder *placeHolder;
+ [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
+ PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:filePath]];
+ placeHolder = [request placeholderForCreatedAsset];
+ } completionHandler:^(BOOL success, NSError * _Nullable error) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (error) {
+ LOGE(@"Cannot save video data downloaded [%@]", [error localizedDescription]);
+ [LinphoneManager setValueInMessageAppData:nil forKey:@"localvideo" inMessage:message];
+ UIAlertController *errView = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Transfer error", nil)
+ message:NSLocalizedString(@"Cannot write video 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(@"video saved to [%@]", [placeHolder localIdentifier]);
+ [LinphoneManager setValueInMessageAppData:[placeHolder localIdentifier]
+ forKey:@"localvideo"
+ inMessage:message];
+ }
+ [NSNotificationCenter.defaultCenter
+ postNotificationName:kLinphoneFileTransferRecvUpdate
+ object:thiz
+ userInfo:@{
+ @"state" : @(LinphoneChatMessageStateDelivered), // we dont want to
+ // trigger
+ // FileTransferDone here
+ @"progress" : @(1.f),
+ }];
+
+ [thiz stopAndDestroy];
+ CFRelease((__bridge CFTypeRef)thiz);
+ });
+ }];
+
+ } else {
+ [[LinphoneManager.instance fileTransferDelegates] removeObject:thiz];
+ NSString *key = @"localfile" ;
NSString *name =[NSString stringWithUTF8String:linphone_content_get_name(content)];
[LinphoneManager setValueInMessageAppData:@"saving..." forKey:key inMessage:message];
//write file to path
dispatch_async(dispatch_get_main_queue(), ^{
- NSString *filePath = [LinphoneManager documentFile:name];
+ NSString *filePath = [[LinphoneManager cacheDirectory] stringByAppendingPathComponent:name];
+ //NSString *filePath = [LinphoneManager documentFile:name];
[[NSFileManager defaultManager] createFileAtPath:filePath
contents:thiz.data
attributes:nil];
[LinphoneManager setValueInMessageAppData:name forKey:key inMessage:message];
+ [LinphoneManager setValueInMessageAppData:filePath forKey:@"cachedfile" inMessage:message];
[NSNotificationCenter.defaultCenter
postNotificationName:kLinphoneFileTransferRecvUpdate
@@ -205,14 +262,15 @@ static LinphoneBuffer *linphone_iphone_file_transfer_send(LinphoneChatMessage *m
linphone_content_set_subtype(content, [subtype UTF8String]);
linphone_content_set_name(content, [name UTF8String]);
linphone_content_set_size(content, _data.length);
-
_message = linphone_chat_room_create_file_transfer_message(chatRoom, content);
+ //linphone_chat_message_add_text_content(_message, [_text UTF8String]);
linphone_content_unref(content);
linphone_chat_message_cbs_set_file_transfer_send(linphone_chat_message_get_callbacks(_message),
linphone_iphone_file_transfer_send);
// internal url is saved in the appdata for display and later save
+ LOGE(@"nnnn %@ %@",key, keyData);
[LinphoneManager setValueInMessageAppData:keyData forKey:key inMessage:_message];
[LinphoneManager setValueInMessageAppData:qualityData forKey:@"uploadQuality" inMessage:_message];
@@ -224,26 +282,24 @@ 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];
}
-- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withUrl:(NSURL *)url {
- NSString *name = [url lastPathComponent];
- //save file to Documents
- NSString *filePath = [LinphoneManager documentFile:name];
- [[NSFileManager defaultManager] createFileAtPath:filePath
- contents:[NSMutableData dataWithData:data]
- attributes:nil];
-
- if ([[url pathExtension] isEqualToString:@"MOV"])
- [self uploadData:data forChatRoom:chatRoom type:nil subtype:nil name:name key:@"localvideo" keyData:name qualityData:nil];
+- (void)uploadVideo:(NSData *)data withassetId:(NSString *)phAssetId forChatRoom:(LinphoneChatRoom *)chatRoom {
+ NSString *name = [NSString stringWithFormat:@"IMG-%f.MOV", [NSDate timeIntervalSinceReferenceDate]];
+ if (phAssetId)
+ [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:nil name:name key:@"localvideo" keyData:phAssetId qualityData:nil];
else
- [self uploadData:data forChatRoom:chatRoom type:@"file" subtype:nil name:name key:@"localfile" keyData:name qualityData:nil];
+ [self uploadData:data forChatRoom:chatRoom type:@"video" subtype:nil name:name key:@"localvideo" keyData:@"ending..." qualityData:nil];
+}
+
+- (void)uploadFile:(NSData *)data forChatRoom:(LinphoneChatRoom *)chatRoom withName:(NSString *)name {
+ [self uploadData:data forChatRoom:chatRoom type:@"file" subtype:nil name:name key:@"localfile" keyData:name qualityData:nil];
}
diff --git a/Classes/Utils/Utils.h b/Classes/Utils/Utils.h
index ced7d6937..aa3ceeda7 100644
--- a/Classes/Utils/Utils.h
+++ b/Classes/Utils/Utils.h
@@ -49,6 +49,8 @@ typedef enum {
+ (NSString *)durationToString:(int)duration;
+ (NSString *)intervalToString:(NSTimeInterval)interval ;
++ (NSMutableDictionary *)photoAssetsDictionary;
+
@end
@interface NSNumber (HumanReadableSize)
@@ -102,6 +104,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 \
diff --git a/Classes/Utils/Utils.m b/Classes/Utils/Utils.m
index 42002b4fc..089902852 100644
--- a/Classes/Utils/Utils.m
+++ b/Classes/Utils/Utils.m
@@ -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 {
@@ -81,6 +55,41 @@
return [formatter stringFromTimeInterval:interval];
}
+
++ (NSMutableDictionary *)photoAssetsDictionary {
+ NSMutableDictionary *assetDict = [NSMutableDictionary dictionary];
+
+ PHFetchOptions *options = [[PHFetchOptions alloc] init];
+ [options setIncludeHiddenAssets:YES];
+ [options setIncludeAllBurstAssets:YES];
+
+ PHFetchResult *fetchRes = [PHAsset fetchAssetsWithOptions:options];
+
+ for (PHAsset *asset in fetchRes) {
+ NSString *key = [asset valueForKey:@"filename"];
+ [assetDict setObject:asset forKey:[[key componentsSeparatedByString:@"."] firstObject]];
+ }
+
+ return assetDict;
+}
+
+/*+ (NSMutableDictionary *)videoAssetsDictionary {
+ NSMutableDictionary *assetDict = [NSMutableDictionary dictionary];
+
+ PHFetchOptions *options = [[PHFetchOptions alloc] init];
+ [options setIncludeHiddenAssets:YES];
+ [options setIncludeAllBurstAssets:YES];
+
+ PHFetchResult *fetchRes = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:options];
+
+ for (PHAsset *asset in fetchRes) {
+ NSString *key = [asset valueForKey:@"filename"];
+ [assetDict setObject:asset forKey:[[key componentsSeparatedByString:@"."] firstObject]];
+ }
+
+ return assetDict;
+}*/
+
+ (NSString *)timeToString:(time_t)time withFormat:(LinphoneDateFormat)format {
NSString *formatstr;
NSDate *todayDate = [[NSDate alloc] init];
@@ -777,3 +786,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
diff --git a/Resources/images/delete_img.png b/Resources/images/delete_img.png
new file mode 100644
index 000000000..b9aaa86c9
Binary files /dev/null and b/Resources/images/delete_img.png differ
diff --git a/linphone.xcodeproj/project.pbxproj b/linphone.xcodeproj/project.pbxproj
index 11dafdd79..03c8f4e3a 100755
--- a/linphone.xcodeproj/project.pbxproj
+++ b/linphone.xcodeproj/project.pbxproj
@@ -63,12 +63,23 @@
570742671D5A63DB004B9C84 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 570742661D5A63DB004B9C84 /* StoreKit.framework */; };
5E10ED4820D00630002BF6FE /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEBE61D3CD5570014B822 /* avatar.png */; };
5E10ED4920D006C9002BF6FE /* chat_group_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81941F87B8000012A66B /* chat_group_avatar.png */; };
+ 5E223A9920E244B400D06A36 /* NotificationTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */; };
5E31290120D7A37E00CF3AAE /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EF0C33820C806A5005081B0 /* NotificationCenter.framework */; };
5E31290520D7A37E00CF3AAE /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E31290420D7A37E00CF3AAE /* TodayViewController.m */; };
5E31290820D7A37E00CF3AAE /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E31290620D7A37E00CF3AAE /* MainInterface.storyboard */; };
5E31290C20D7A37E00CF3AAE /* latestChatroomsWidget.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
5E31291320D7AAA100CF3AAE /* avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEBE61D3CD5570014B822 /* avatar.png */; };
5E31291A20D7AAAD00CF3AAE /* chat_group_avatar.png in Resources */ = {isa = PBXBuildFile; fileRef = 8C2A81941F87B8000012A66B /* chat_group_avatar.png */; };
+ 5E32944520E4C29000BBA896 /* chat_delivered.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AC1E8266CC0037A187 /* chat_delivered.png */; };
+ 5E32944C20E4C29300BBA896 /* chat_error.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AD1E8266CC0037A187 /* chat_error.png */; };
+ 5E32944D20E4C29700BBA896 /* chat_read.png in Resources */ = {isa = PBXBuildFile; fileRef = 244523AE1E8266CC0037A187 /* chat_read.png */; };
+ 5E3391EC20E387E000F66299 /* color_A.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEC701D3CD5570014B822 /* color_A.png */; };
+ 5E3391F320E387E700F66299 /* color_D.png in Resources */ = {isa = PBXBuildFile; fileRef = 633FEC721D3CD5570014B822 /* color_D.png */; };
+ 5E58962420DCE5700030868C /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C73477B1D9BA3A00022EE8C /* UserNotifications.framework */; };
+ 5E58962620DCE5700030868C /* UserNotificationsUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E58962520DCE5700030868C /* UserNotificationsUI.framework */; };
+ 5E58962A20DCE5700030868C /* NotificationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E58962920DCE5700030868C /* NotificationViewController.m */; };
+ 5E58962D20DCE5700030868C /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E58962B20DCE5700030868C /* MainInterface.storyboard */; };
+ 5E58963120DCE5710030868C /* richNotifications.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5E58962320DCE5700030868C /* richNotifications.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
5EEE8F9B20C80C23006E4176 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EF0C33820C806A5005081B0 /* NotificationCenter.framework */; };
5EEE8F9F20C80C23006E4176 /* TodayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5EEE8F9E20C80C23006E4176 /* TodayViewController.m */; };
5EEE8FA220C80C23006E4176 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5EEE8FA020C80C23006E4176 /* MainInterface.storyboard */; };
@@ -730,6 +741,9 @@
8CF25D9D1F9F76BD00BEA0C1 /* chat_group_informations.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D9B1F9F76BC00BEA0C1 /* chat_group_informations.png */; };
8CF25D9E1F9F76BD00BEA0C1 /* chat_group_informations@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8CF25D9C1F9F76BD00BEA0C1 /* chat_group_informations@2x.png */; };
C90FAA7915AF54E6002091CB /* HistoryDetailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */; };
+ CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */ = {isa = PBXBuildFile; fileRef = CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */; };
+ CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */ = {isa = PBXBuildFile; fileRef = CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */; };
+ CFBD7A2A20E504AE007C5286 /* delete_img.png in Resources */ = {isa = PBXBuildFile; fileRef = CFBD7A2320E504AD007C5286 /* delete_img.png */; };
D306459E1611EC2A00BB571E /* UILoadingImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = D306459D1611EC2900BB571E /* UILoadingImageView.m */; };
D3128FE115AABC7E00A2147A /* ContactDetailsView.m in Sources */ = {isa = PBXBuildFile; fileRef = D3128FDF15AABC7E00A2147A /* ContactDetailsView.m */; };
D31AAF5E159B3919002C6B02 /* CallPausedTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = D31AAF5D159B3919002C6B02 /* CallPausedTableView.m */; };
@@ -831,6 +845,13 @@
remoteGlobalIDString = 5E3128FF20D7A37E00CF3AAE;
remoteInfo = latestChatroomsWidget;
};
+ 5E58962F20DCE5710030868C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5E58962220DCE5700030868C;
+ remoteInfo = richNotifications;
+ };
5EEE8FA420C80C23006E4176 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
@@ -934,6 +955,7 @@
61AE365620C00B370089D9D3 /* linphoneExtension.appex in Embed App Extensions */,
5E31290C20D7A37E00CF3AAE /* latestChatroomsWidget.appex in Embed App Extensions */,
5EEE8FA620C80C23006E4176 /* latestCallsWidget.appex in Embed App Extensions */,
+ 5E58963120DCE5710030868C /* richNotifications.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
@@ -1075,12 +1097,20 @@
570742601D5A09B8004B9C84 /* ShopView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShopView.h; sourceTree = ""; };
570742631D5A1860004B9C84 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShopView.strings; sourceTree = ""; };
570742661D5A63DB004B9C84 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ 5E223A9720E244B400D06A36 /* NotificationTableViewCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationTableViewCell.h; sourceTree = ""; };
+ 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationTableViewCell.m; sourceTree = ""; };
5E30780420D8F00D00256DAE /* latestChatroomsWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = latestChatroomsWidget.entitlements; sourceTree = ""; };
5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = latestChatroomsWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; };
5E31290320D7A37E00CF3AAE /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; };
5E31290420D7A37E00CF3AAE /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; };
5E31290720D7A37E00CF3AAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; };
5E31290920D7A37E00CF3AAE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 5E58962320DCE5700030868C /* richNotifications.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = richNotifications.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5E58962520DCE5700030868C /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
+ 5E58962820DCE5700030868C /* NotificationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotificationViewController.h; sourceTree = ""; };
+ 5E58962920DCE5700030868C /* NotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationViewController.m; sourceTree = ""; };
+ 5E58962C20DCE5700030868C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; };
+ 5E58962E20DCE5710030868C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
5EEE8F9A20C80C23006E4176 /* latestCallsWidget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = latestCallsWidget.appex; sourceTree = BUILT_PRODUCTS_DIR; };
5EEE8F9D20C80C23006E4176 /* TodayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TodayViewController.h; sourceTree = ""; };
5EEE8F9E20C80C23006E4176 /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = ""; };
@@ -1829,6 +1859,10 @@
C90FAA7615AF54E6002091CB /* HistoryDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryDetailsView.h; sourceTree = ""; };
C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryDetailsView.m; sourceTree = ""; };
C9B3A6FD15B485DB006F52EE /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = Utils/Utils.h; sourceTree = ""; };
+ CF15F21B20E4F9A3008B1DE6 /* UIImageViewDeletable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIImageViewDeletable.h; sourceTree = ""; };
+ CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIImageViewDeletable.m; sourceTree = ""; };
+ CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UIImageViewDeletable.xib; sourceTree = ""; };
+ CFBD7A2320E504AD007C5286 /* delete_img.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = delete_img.png; sourceTree = ""; };
D306459C1611EC2900BB571E /* UILoadingImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UILoadingImageView.h; sourceTree = ""; };
D306459D1611EC2900BB571E /* UILoadingImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UILoadingImageView.m; sourceTree = ""; };
D3128FDE15AABC7E00A2147A /* ContactDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsView.h; sourceTree = ""; };
@@ -2068,6 +2102,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 5E58962020DCE5700030868C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E58962620DCE5700030868C /* UserNotificationsUI.framework in Frameworks */,
+ 5E58962420DCE5700030868C /* UserNotifications.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5EEE8F9720C80C23006E4176 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2282,6 +2325,7 @@
61AE364B20C00B370089D9D3 /* linphoneExtension.appex */,
5EEE8F9A20C80C23006E4176 /* latestCallsWidget.appex */,
5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */,
+ 5E58962320DCE5700030868C /* richNotifications.appex */,
);
name = Products;
sourceTree = "";
@@ -2289,6 +2333,9 @@
2214EB7012F84668002A5394 /* LinphoneUI */ = {
isa = PBXGroup;
children = (
+ CF15F21B20E4F9A3008B1DE6 /* UIImageViewDeletable.h */,
+ CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */,
+ CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */,
63F1DF421BCE618E00EDED90 /* UIAddressTextField.h */,
63F1DF431BCE618E00EDED90 /* UIAddressTextField.m */,
63C441C11BBC23ED0053DC5E /* UIAssistantTextField.h */,
@@ -2399,6 +2446,7 @@
61AE364C20C00B370089D9D3 /* linphoneExtension */,
5EEE8F9C20C80C23006E4176 /* latestCallsWidget */,
5E31290220D7A37E00CF3AAE /* latestChatroomsWidget */,
+ 5E58962720DCE5700030868C /* richNotifications */,
29B97323FDCFA39411CA2CEA /* Frameworks */,
F0938158188E629800A55DFA /* iTunesArtwork */,
63058A0C1B4E821E00EFAE36 /* LiblinphoneTester */,
@@ -2490,6 +2538,7 @@
2264B6D111200342002C2C53 /* SystemConfiguration.framework */,
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
5EF0C33820C806A5005081B0 /* NotificationCenter.framework */,
+ 5E58962520DCE5700030868C /* UserNotificationsUI.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -2506,6 +2555,19 @@
path = latestChatroomsWidget;
sourceTree = "";
};
+ 5E58962720DCE5700030868C /* richNotifications */ = {
+ isa = PBXGroup;
+ children = (
+ 5E58962820DCE5700030868C /* NotificationViewController.h */,
+ 5E58962920DCE5700030868C /* NotificationViewController.m */,
+ 5E58962B20DCE5700030868C /* MainInterface.storyboard */,
+ 5E58962E20DCE5710030868C /* Info.plist */,
+ 5E223A9720E244B400D06A36 /* NotificationTableViewCell.h */,
+ 5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */,
+ );
+ path = richNotifications;
+ sourceTree = "";
+ };
5EEE8F9C20C80C23006E4176 /* latestCallsWidget */ = {
isa = PBXGroup;
children = (
@@ -2632,6 +2694,7 @@
633FEBE11D3CD5570014B822 /* images */ = {
isa = PBXGroup;
children = (
+ CFBD7A2320E504AD007C5286 /* delete_img.png */,
24BFAA9B209B062F004F47A7 /* callkit_logo.png */,
24BFAA99209B062E004F47A7 /* contacts_sip_default.png */,
24BFAA94209B062C004F47A7 /* contacts_sip_default@2x.png */,
@@ -3325,6 +3388,7 @@
61AE365520C00B370089D9D3 /* PBXTargetDependency */,
5EEE8FA520C80C23006E4176 /* PBXTargetDependency */,
5E31290B20D7A37E00CF3AAE /* PBXTargetDependency */,
+ 5E58963020DCE5710030868C /* PBXTargetDependency */,
);
name = linphone;
productName = linphone;
@@ -3348,6 +3412,23 @@
productReference = 5E31290020D7A37E00CF3AAE /* latestChatroomsWidget.appex */;
productType = "com.apple.product-type.app-extension";
};
+ 5E58962220DCE5700030868C /* richNotifications */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5E58963C20DCE5710030868C /* Build configuration list for PBXNativeTarget "richNotifications" */;
+ buildPhases = (
+ 5E58961F20DCE5700030868C /* Sources */,
+ 5E58962020DCE5700030868C /* Frameworks */,
+ 5E58962120DCE5700030868C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = richNotifications;
+ productName = richNotifications;
+ productReference = 5E58962320DCE5700030868C /* richNotifications.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
5EEE8F9920C80C23006E4176 /* latestCallsWidget */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5EEE8FA720C80C24006E4176 /* Build configuration list for PBXNativeTarget "latestCallsWidget" */;
@@ -3462,6 +3543,9 @@
com.apple.Push = {
enabled = 1;
};
+ com.apple.iCloud = {
+ enabled = 0;
+ };
};
};
5E3128FF20D7A37E00CF3AAE = {
@@ -3474,6 +3558,11 @@
};
};
};
+ 5E58962220DCE5700030868C = {
+ CreatedOnToolsVersion = 9.4;
+ DevelopmentTeam = Z2V957B3D6;
+ ProvisioningStyle = Automatic;
+ };
5EEE8F9920C80C23006E4176 = {
CreatedOnToolsVersion = 9.4;
DevelopmentTeam = Z2V957B3D6;
@@ -3548,6 +3637,7 @@
61AE364A20C00B370089D9D3 /* linphoneExtension */,
5EEE8F9920C80C23006E4176 /* latestCallsWidget */,
5E3128FF20D7A37E00CF3AAE /* latestChatroomsWidget */,
+ 5E58962220DCE5700030868C /* richNotifications */,
);
};
/* End PBXProject section */
@@ -3691,6 +3781,7 @@
633FEE401D3CD5590014B822 /* contacts_all_selected.png in Resources */,
633FEE0C1D3CD5590014B822 /* chat_attachment_disabled.png in Resources */,
633FEF001D3CD55A0014B822 /* options_default.png in Resources */,
+ CF15F21F20E4F9A3008B1DE6 /* UIImageViewDeletable.xib in Resources */,
633FEE951D3CD55A0014B822 /* micro_default@2x.png in Resources */,
633FEE6A1D3CD5590014B822 /* footer_dialer_default.png in Resources */,
633FEEC91D3CD55A0014B822 /* numpad_5~ipad.png in Resources */,
@@ -3822,6 +3913,7 @@
633FEED71D3CD55A0014B822 /* numpad_7_over~ipad.png in Resources */,
633FEF2A1D3CD55A0014B822 /* route_earpiece_disabled.png in Resources */,
633FEDDB1D3CD5590014B822 /* call_start_body_disabled@2x.png in Resources */,
+ CFBD7A2A20E504AE007C5286 /* delete_img.png in Resources */,
633FEDFD1D3CD5590014B822 /* camera_switch_default@2x.png in Resources */,
633FEEC51D3CD55A0014B822 /* numpad_5_over.png in Resources */,
633FEE721D3CD5590014B822 /* history_all_default.png in Resources */,
@@ -4159,6 +4251,19 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 5E58962120DCE5700030868C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E32944C20E4C29300BBA896 /* chat_error.png in Resources */,
+ 5E32944D20E4C29700BBA896 /* chat_read.png in Resources */,
+ 5E32944520E4C29000BBA896 /* chat_delivered.png in Resources */,
+ 5E3391F320E387E700F66299 /* color_D.png in Resources */,
+ 5E58962D20DCE5700030868C /* MainInterface.storyboard in Resources */,
+ 5E3391EC20E387E000F66299 /* color_A.png in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5EEE8F9820C80C23006E4176 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4278,6 +4383,7 @@
1D60589B0D05DD56006BFB54 /* main.m in Sources */,
8CD99A3C2090B9FA008A7CDA /* ChatConversationImdnView.m in Sources */,
1D3623260D0F684500981E51 /* LinphoneAppDelegate.m in Sources */,
+ CF15F21E20E4F9A3008B1DE6 /* UIImageViewDeletable.m in Sources */,
22F2508E107141E100AC9B3F /* DialerView.m in Sources */,
633756451B67D2B200E21BAD /* SideMenuView.m in Sources */,
8CD99A422090CE6F008A7CDA /* UIChatConversationImdnTableViewCell.m in Sources */,
@@ -4407,6 +4513,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ 5E58961F20DCE5700030868C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5E223A9920E244B400D06A36 /* NotificationTableViewCell.m in Sources */,
+ 5E58962A20DCE5700030868C /* NotificationViewController.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
5EEE8F9620C80C23006E4176 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -4466,6 +4581,11 @@
target = 5E3128FF20D7A37E00CF3AAE /* latestChatroomsWidget */;
targetProxy = 5E31290A20D7A37E00CF3AAE /* PBXContainerItemProxy */;
};
+ 5E58963020DCE5710030868C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5E58962220DCE5700030868C /* richNotifications */;
+ targetProxy = 5E58962F20DCE5710030868C /* PBXContainerItemProxy */;
+ };
5EEE8FA520C80C23006E4176 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5EEE8F9920C80C23006E4176 /* latestCallsWidget */;
@@ -4512,6 +4632,14 @@
name = MainInterface.storyboard;
sourceTree = "";
};
+ 5E58962B20DCE5700030868C /* MainInterface.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 5E58962C20DCE5700030868C /* Base */,
+ );
+ name = MainInterface.storyboard;
+ sourceTree = "";
+ };
5EEE8FA020C80C23006E4176 /* MainInterface.storyboard */ = {
isa = PBXVariantGroup;
children = (
@@ -5590,6 +5718,178 @@
};
name = DistributionAdhoc;
};
+ 5E58963220DCE5710030868C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEVELOPMENT_TEAM = Z2V957B3D6;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ INFOPLIST_FILE = richNotifications/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 5E58963320DCE5710030868C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = Z2V957B3D6;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ INFOPLIST_FILE = richNotifications/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 5E58963420DCE5710030868C /* Distribution */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = Z2V957B3D6;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ INFOPLIST_FILE = richNotifications/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Distribution;
+ };
+ 5E58963520DCE5710030868C /* DistributionAdhoc */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEVELOPMENT_TEAM = Z2V957B3D6;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ INFOPLIST_FILE = richNotifications/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_BUNDLE_IDENTIFIER = org.linphone.phone.richNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE = "";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = DistributionAdhoc;
+ };
5EEE8FA820C80C24006E4176 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -6595,6 +6895,17 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Debug;
};
+ 5E58963C20DCE5710030868C /* Build configuration list for PBXNativeTarget "richNotifications" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E58963220DCE5710030868C /* Debug */,
+ 5E58963320DCE5710030868C /* Release */,
+ 5E58963420DCE5710030868C /* Distribution */,
+ 5E58963520DCE5710030868C /* DistributionAdhoc */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
5EEE8FA720C80C24006E4176 /* Build configuration list for PBXNativeTarget "latestCallsWidget" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/linphoneExtension/ShareViewController.m b/linphoneExtension/ShareViewController.m
index ae71c00c3..1f656a9bc 100644
--- a/linphoneExtension/ShareViewController.m
+++ b/linphoneExtension/ShareViewController.m
@@ -20,32 +20,35 @@ static NSString* groupName = @"group.belledonne-communications.linphone";
- (void)didSelectPost {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
-
+ BOOL support = TRUE;
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *provider in item.attachments) {
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:groupName];
-
+ // TODO: Use [provider registeredTypeIdentifiersWithFileOptions:0]; to get all type identifiers of the provider instead of this if/else if structure
+ support = TRUE;
if ([provider hasItemConformingToTypeIdentifier:@"public.jpeg"]) {
- [self loadItem:provider typeIdentifier:@"public.jpeg" defaults:defaults key:@"img"];
+ [self loadItem:provider typeIdentifier:@"public.jpeg" defaults:defaults];
+ } else if ([provider hasItemConformingToTypeIdentifier:@"com.compuserve.gif"]) {
+ [self loadItem:provider typeIdentifier:@"com.compuserve.gif" defaults:defaults];
} else if ([provider hasItemConformingToTypeIdentifier:@"public.url"]) {
- [self loadItem:provider typeIdentifier:@"public.url" defaults:defaults key:@"web"];
+ [self loadItem:provider typeIdentifier:@"public.url" defaults:defaults];
} else if ([provider hasItemConformingToTypeIdentifier:@"public.movie"]) {
- [self loadItem:provider typeIdentifier:@"public.movie" defaults:defaults key:@"mov"];
- } else if ([provider hasItemConformingToTypeIdentifier:@"public.plain-text"]) {
- [self loadItem:provider typeIdentifier:@"public.plain-text" defaults:defaults key:@"text"];
- } else if ([provider hasItemConformingToTypeIdentifier:@"com.adobe.pdf"]) {
- [self loadItem:provider typeIdentifier:@"com.adobe.pdf" defaults:defaults key:@"web"];
- }
- /*else if ([provider hasItemConformingToTypeIdentifier:@"public.png"]) {
- [self loadItem:provider typeIdentifier:@"public.png" defaults:defaults key:@"img"];
- }*/
- else{
+ [self loadItem:provider typeIdentifier:@"public.movie" defaults:defaults];
+ } else if ([provider hasItemConformingToTypeIdentifier:@"com.apple.mapkit.map-item"]) {
+ [self loadItem:provider typeIdentifier:@"com.apple.mapkit.map-item" defaults:defaults];
+ } else if ([provider hasItemConformingToTypeIdentifier:@"com.adobe.pdf"]) {
+ [self loadItem:provider typeIdentifier:@"com.adobe.pdf" defaults:defaults];
+ } else if ([provider hasItemConformingToTypeIdentifier:@"public.png"]) {
+ [self loadItem:provider typeIdentifier:@"public.png" defaults:defaults];
+ } else{
NSLog(@"Unkown itemprovider = %@", provider);
- [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
+ support = false;
}
}
}
+ if (!support)
+ [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
- (NSArray *)configurationItems {
@@ -53,46 +56,57 @@ static NSString* groupName = @"group.belledonne-communications.linphone";
return @[];
}
-- (void)loadItem:(NSItemProvider *)provider typeIdentifier:(NSString *)typeIdentifier defaults:(NSUserDefaults *)defaults key:(NSString *)key {
+- (void)loadItem:(NSItemProvider *)provider typeIdentifier:(NSString *)typeIdentifier defaults:(NSUserDefaults *)defaults
+{
[provider loadItemForTypeIdentifier:typeIdentifier options:nil completionHandler:^(id _Nullable item, NSError * _Null_unspecified error) {
+ /*if([(NSObject*)item isKindOfClass:[NSDictionary class]]) {
+ NSDictionary *dico = (NSDictionary *)item;
+ if (dico) {
+ return;
+ }
+ }*/
if([(NSObject*)item isKindOfClass:[NSURL class]]) {
- NSData *nsData = [NSData dataWithContentsOfURL:(NSURL*)item];
+ NSURL *url = (NSURL *)item;
+ NSData *nsData = [NSData dataWithContentsOfURL:url];
+
if (nsData) {
- NSDictionary *dict = @{@"nsData" : nsData,
- @"url" : [(NSURL*)item absoluteString]};
- [defaults setObject:dict forKey:key];
+ NSString *imgPath = url.path;
+ NSString *filename = [imgPath lastPathComponent];
+ if([imgPath containsString:@"var/mobile/Media/PhotoData"]) {
+ // We get the corresponding PHAsset identifier so we can display the image in the app without having to duplicate it.
+ NSDictionary *dict = @{@"nsData" : nsData,
+ @"url" : filename};
+ [defaults setObject:dict forKey:@"photoData"];
+ } else if ([imgPath containsString:@"var/mobile/Library/Mobile Documents/com~apple~CloudDocs"]) {
+ // shared files from icloud drive
+ NSDictionary *dict = @{@"nsData" : nsData,
+ @"url" : filename};
+ [defaults setObject:dict forKey:@"icloudData"];
+ }else {
+ //Others
+ NSDictionary *dict = @{@"url" : [url absoluteString]};
+ [defaults setObject:dict forKey:@"url"];
+ }
} else {
NSLog(@"NSExtensionItem Error, provider = %@", provider);
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
- }
- else if ([(NSObject*)item isKindOfClass:[UIImage class]]) {
- NSData *imgData = UIImagePNGRepresentation((UIImage*)item);
- if (imgData) {
- NSDictionary *dict = @{@"nsData" : imgData,
- };
- [defaults setObject:dict forKey:key];
- } else {
- NSLog(@"NSExtensionItem Error, provider = %@", provider);
- [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
+
+ UIResponder *responder = self;
+ while (responder != nil) {
+ if ([responder respondsToSelector:@selector(openURL:)]) {
+ [responder performSelector:@selector(openURL:)
+ withObject:[NSURL URLWithString:@"message-linphone://" ]];
+ [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
+ break;
+ }
+ responder = [responder nextResponder];
}
+ [defaults synchronize];
+ } else {
+ //share text
+ NSLog(@"Unsupported provider = %@", provider);
}
- else {
- NSDictionary *dict = @{@"name" : self.contentText};
- [defaults setObject:dict forKey:key];
- }
-
- UIResponder *responder = self;
- while (responder != nil) {
- if ([responder respondsToSelector:@selector(openURL:)]) {
- [responder performSelector:@selector(openURL:)
- withObject:[NSURL URLWithString:@"message-linphone://" ]];
- [self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
- break;
- }
- responder = [responder nextResponder];
- }
- [defaults synchronize];
}];
}
diff --git a/richNotifications/Base.lproj/MainInterface.storyboard b/richNotifications/Base.lproj/MainInterface.storyboard
new file mode 100644
index 000000000..f50b1b59d
--- /dev/null
+++ b/richNotifications/Base.lproj/MainInterface.storyboard
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/richNotifications/Info.plist b/richNotifications/Info.plist
new file mode 100644
index 000000000..f6e516e4d
--- /dev/null
+++ b/richNotifications/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ richNotifications
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ XPC!
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionAttributes
+
+ UNNotificationExtensionDefaultContentHidden
+
+ UNNotificationExtensionCategory
+ msg_cat
+ UNNotificationExtensionInitialContentSizeRatio
+ 1
+
+ NSExtensionMainStoryboard
+ MainInterface
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.content-extension
+
+
+
diff --git a/richNotifications/NotificationTableViewCell.h b/richNotifications/NotificationTableViewCell.h
new file mode 100644
index 000000000..77b74e1d3
--- /dev/null
+++ b/richNotifications/NotificationTableViewCell.h
@@ -0,0 +1,24 @@
+//
+// NotificationTableViewCell.h
+// richNotifications
+//
+// Created by David Idmansour on 26/06/2018.
+//
+
+#import
+
+@interface NotificationTableViewCell : UITableViewCell
+@property (weak, nonatomic) IBOutlet UIImageView *contactImage;
+@property (weak, nonatomic) IBOutlet UILabel *nameDate;
+@property (strong, nonatomic) IBOutlet UITextView *msgText;
+@property (weak, nonatomic) IBOutlet UILabel *imdm;
+@property (weak, nonatomic) IBOutlet UIImageView *background;
+@property (weak, nonatomic) IBOutlet UIImageView *bottomBarColor;
+@property (weak, nonatomic) IBOutlet UIImageView *imdmImage;
+@property BOOL isOutgoing;
+@property float width;
+@property float height;
+
+- (CGSize)ViewSizeForMessage:(NSString *)chat withWidth:(int)width;
+
+@end
diff --git a/richNotifications/NotificationTableViewCell.m b/richNotifications/NotificationTableViewCell.m
new file mode 100644
index 000000000..26fe0f188
--- /dev/null
+++ b/richNotifications/NotificationTableViewCell.m
@@ -0,0 +1,94 @@
+//
+// NotificationTableViewCell.m
+// richNotifications
+//
+// Created by David Idmansour on 26/06/2018.
+//
+
+#import "NotificationTableViewCell.h"
+
+@implementation NotificationTableViewCell
+
+- (void)awakeFromNib {
+ [super awakeFromNib];
+ // Initialization code
+ _contactImage.layer.cornerRadius = _contactImage.frame.size.height / 2;
+ _contactImage.clipsToBounds = YES;
+ [self.contentView sendSubviewToBack:_background];
+}
+
+- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
+ [super setSelected:selected animated:animated];
+
+ // Configure the view for the selected state
+}
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+ CGRect bubbleFrame = self.contentView.frame;
+ int originX;
+
+ bubbleFrame.size = CGSizeMake(_width, _height);
+
+ originX = (_isOutgoing ? self.frame.size.width - bubbleFrame.size.width - 5 : 5);
+
+ bubbleFrame.origin.x = originX;
+ self.contentView.frame = bubbleFrame;
+
+ _msgText.textContainerInset = UIEdgeInsetsZero;
+ _msgText.textContainer.lineFragmentPadding = 0;
+}
+
+#pragma mark - Bubble size computing
+
+- (CGSize)computeBoundingBox:(NSString *)text size:(CGSize)size font:(UIFont *)font {
+ if (!text || text.length == 0)
+ return CGSizeMake(0, 0);
+
+ return [text boundingRectWithSize:size
+ options:(NSStringDrawingUsesLineFragmentOrigin |
+ NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading)
+ attributes:@{
+ NSFontAttributeName : font
+ }
+ context:nil].size;
+}
+
+static const CGFloat CELL_MIN_HEIGHT = 60.0f;
+static const CGFloat CELL_MIN_WIDTH = 190.0f;
+static const CGFloat CELL_MESSAGE_X_MARGIN = 78 + 10.0f;
+static const CGFloat CELL_MESSAGE_Y_MARGIN = 52; // 44;
+
+- (CGSize)ViewHeightForMessage:(NSString *)messageText withWidth:(int)width {
+ static UIFont *messageFont = nil;
+
+ if (!messageFont) {
+ messageFont = _msgText.font;
+ }
+ CGSize size;
+ size = [self computeBoundingBox:messageText
+ size:CGSizeMake(width - CELL_MESSAGE_X_MARGIN - 4, CGFLOAT_MAX)
+ font:messageFont];
+
+ size.width = MAX(size.width + CELL_MESSAGE_X_MARGIN, CELL_MIN_WIDTH);
+ size.height = MAX(size.height + CELL_MESSAGE_Y_MARGIN, CELL_MIN_HEIGHT);
+ return size;
+}
+- (CGSize)ViewSizeForMessage:(NSString *)chat withWidth:(int)width {
+ static UIFont *dateFont = nil;
+ static CGSize dateViewSize;
+
+ if (!dateFont) {
+ dateFont = _nameDate.font;
+ dateViewSize = _nameDate.frame.size;
+ dateViewSize.width = CGFLOAT_MAX;
+ }
+
+ CGSize messageSize = [self ViewHeightForMessage:chat withWidth:width];
+ CGSize dateSize = [self computeBoundingBox:_nameDate.text size:dateViewSize font:dateFont];
+ messageSize.width = MAX(MAX(messageSize.width, MIN(dateSize.width + CELL_MESSAGE_X_MARGIN, width)), CELL_MIN_WIDTH);
+
+ return messageSize;
+}
+
+@end
diff --git a/richNotifications/NotificationViewController.h b/richNotifications/NotificationViewController.h
new file mode 100644
index 000000000..f96beffbd
--- /dev/null
+++ b/richNotifications/NotificationViewController.h
@@ -0,0 +1,12 @@
+//
+// NotificationViewController.h
+// richNotifications
+//
+// Created by David Idmansour on 22/06/2018.
+//
+
+#import
+
+@interface NotificationViewController : UITableViewController
+
+@end
diff --git a/richNotifications/NotificationViewController.m b/richNotifications/NotificationViewController.m
new file mode 100644
index 000000000..69aa955a8
--- /dev/null
+++ b/richNotifications/NotificationViewController.m
@@ -0,0 +1,110 @@
+//
+// NotificationViewController.m
+// richNotifications
+//
+// Created by David Idmansour on 22/06/2018.
+//
+
+#import "NotificationViewController.h"
+#import "NotificationTableViewCell.h"
+#import
+#import
+
+@interface NotificationViewController ()
+
+@end
+
+@implementation NotificationViewController {
+ @private
+ NSMutableArray *msgs;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+ self.tableView.scrollEnabled = TRUE;
+ // Do any required interface initialization here.
+}
+
+- (void)didReceiveNotification:(UNNotification *)notification {
+// static float initialHeight = -1;
+// if (initialHeight < 0)
+// initialHeight = self.tableView.frame.size.height;
+ if (msgs)
+ [msgs addObject:[((NSArray *)[[[[notification request] content] userInfo] objectForKey:@"msgs"]) lastObject]];
+ else
+ msgs = [NSMutableArray arrayWithArray:[[[[notification request] content] userInfo] objectForKey:@"msgs"]];
+ [self.tableView reloadData];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:msgs.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
+// float height = 0;
+// for (int i = 0 ; i < self->msgs.count ; i++) {
+// height += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
+// }
+// if (height > initialHeight) {
+// CGRect frame = self.tableView.frame;
+// frame.size.height = height;
+// frame.origin = CGPointMake(0, 0);
+// self.tableView.frame = frame;
+// self.tableView.bounds = frame;
+// self.preferredContentSize = CGSizeMake(self.preferredContentSize.width, height);
+// }
+}
+
+#pragma mark - UITableViewDataSource Functions
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return msgs.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ BOOL isOutgoing = ((NSNumber *)[msgs[indexPath.row] objectForKey:@"isOutgoing"]).boolValue;
+ NSString *display = ((NSString *)[msgs[indexPath.row] objectForKey:@"displayNameDate"]);
+ NSString *msgText = ((NSString *)[msgs[indexPath.row] objectForKey:@"msg"]);
+ NSString *imdm = ((NSString *)[msgs[indexPath.row] objectForKey:@"state"]);
+ NSData *imageData = [msgs[indexPath.row] objectForKey:@"fromImageData"];
+ NotificationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"notificationCell" forIndexPath:indexPath];
+
+ cell.background.image = cell.bottomBarColor.image = [UIImage imageNamed:isOutgoing ? @"color_A" : @"color_D.png"];
+ cell.contactImage.image = [UIImage imageWithData:imageData];
+ cell.nameDate.text = display;
+ cell.msgText.text = msgText;
+ cell.isOutgoing = isOutgoing;
+ CGSize size = [cell ViewSizeForMessage:msgText withWidth:self.view.bounds.size.width - 10];
+ cell.width = size.width;
+ cell.height = size.height;
+ cell.nameDate.textColor = [UIColor colorWithPatternImage:cell.background.image];
+ cell.msgText.textColor = [UIColor darkGrayColor];
+ cell.imdm.hidden = cell.imdmImage.hidden = !isOutgoing;
+
+ if ([imdm isEqualToString:@"LinphoneChatMessageStateDelivered"] || [imdm isEqualToString:@"LinphoneChatMessageStateDeliveredToUser"]) {
+ cell.imdm.text = NSLocalizedString(@"Delivered", nil);
+ cell.imdm.textColor = [UIColor grayColor];
+ cell.imdmImage.image = [UIImage imageNamed:@"chat_delivered.png"];
+ } else if ([imdm isEqualToString:@"LinphoneChatMessageStateDisplayed"]) {
+ cell.imdm.text = NSLocalizedString(@"Read", nil);
+ cell.imdm.textColor = [UIColor colorWithRed:(24 / 255.0) green:(167 / 255.0) blue:(175 / 255.0) alpha:1.0];
+ cell.imdmImage.image = [UIImage imageNamed:@"chat_read.png"];
+ } else if ([imdm isEqualToString:@"LinphoneChatMessageStateNotDelivered"] || [imdm isEqualToString:@"LinphoneChatMessageStateFileTransferError"]) {
+ cell.imdm.text = NSLocalizedString(@"Error", nil);
+ cell.imdm.textColor = [UIColor redColor];
+ cell.imdmImage.image = [UIImage imageNamed:@"chat_error.png"];
+ } else
+ cell.imdm.hidden = YES;
+
+ return cell;
+}
+
+#pragma mark - UITableViewDelegate Functions
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
+ NotificationTableViewCell *cell = [[NotificationTableViewCell alloc] init];
+ cell.msgText = [[UITextView alloc] init];
+ cell.msgText.text = ((NSString *)[msgs[indexPath.row] objectForKey:@"msg"]);
+ cell.msgText.font = [UIFont systemFontOfSize:17];
+ return [cell ViewSizeForMessage:cell.msgText.text withWidth:self.view.bounds.size.width - 10].height + 5;
+}
+
+@end