forked from mirrors/linphone-iphone
Merge branch 'feature/sms_invitation'
This commit is contained in:
commit
e704c7317a
37 changed files with 1898 additions and 549 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
<outlet property="chatView" destination="49" id="Rxt-Zy-19x"/>
|
||||
<outlet property="composeIndicatorView" destination="fx4-ao-53M" id="xk5-nK-lur"/>
|
||||
<outlet property="composeLabel" destination="fpY-Fv-ht2" id="4L6-ik-ZAe"/>
|
||||
<outlet property="imagesCollectionView" destination="JGQ-p2-HCX" id="6dt-1f-jpa"/>
|
||||
<outlet property="imagesView" destination="3qd-ys-t2L" id="f9L-FU-PMI"/>
|
||||
<outlet property="infoButton" destination="Vqb-Un-4xv" id="pa1-Iz-5QQ"/>
|
||||
<outlet property="landscapeView" destination="VoU-7Q-fgp" id="iRJ-sh-thF"/>
|
||||
<outlet property="listSwipeGestureRecognizer" destination="dzw-n4-l9i" id="JVP-Vl-lIa"/>
|
||||
|
|
@ -269,6 +271,28 @@
|
|||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" id="3qd-ys-t2L" userLabel="imagesView">
|
||||
<rect key="frame" x="0.0" y="427" width="375" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="color_F.png" id="B6X-D7-Bak" userLabel="backgroundColor">
|
||||
<rect key="frame" x="2" y="1" width="375" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" misplaced="YES" showsVerticalScrollIndicator="NO" dataMode="none" id="JGQ-p2-HCX" userLabel="imagesCollectionView">
|
||||
<rect key="frame" x="2" y="0.0" width="374" height="0.0"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.98780487804878048" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="10" id="c7z-F2-r1y">
|
||||
<size key="itemSize" width="50" height="100"/>
|
||||
<size key="headerReferenceSize" width="0.0" height="0.0"/>
|
||||
<size key="footerReferenceSize" width="0.0" height="0.0"/>
|
||||
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</collectionViewFlowLayout>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
</subviews>
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@
|
|||
|
||||
@protocol ChatConversationDelegate <NSObject>
|
||||
|
||||
- (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<ChatConversationDelegate> chatRoomDelegate;
|
||||
@property NSMutableDictionary<NSString *, UIImage *> *imagesInChatroom;
|
||||
|
||||
- (void)addEventEntry:(LinphoneEventLog *)event;
|
||||
- (void)scrollToBottom:(BOOL)animated;
|
||||
|
|
|
|||
|
|
@ -39,29 +39,36 @@
|
|||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.tableView.accessibilityIdentifier = @"ChatRoom list";
|
||||
_imagesInChatroom = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)clearEventList {
|
||||
[eventList removeAllObjects];
|
||||
for (NSValue *value in eventList) {
|
||||
LinphoneEventLog *event = value.pointerValue;
|
||||
linphone_event_log_unref(event);
|
||||
}
|
||||
[eventList removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)updateData {
|
||||
[self clearEventList];
|
||||
if (!_chatRoom)
|
||||
return;
|
||||
[self clearEventList];
|
||||
|
||||
LinphoneChatRoomCapabilitiesMask capabilities = linphone_chat_room_get_capabilities(_chatRoom);
|
||||
bctbx_list_t *chatRoomEvents = (capabilities & LinphoneChatRoomCapabilitiesOneToOne)
|
||||
? linphone_chat_room_get_history_message_events(_chatRoom, 0)
|
||||
: linphone_chat_room_get_history_events(_chatRoom, 0);
|
||||
|
||||
bctbx_list_t *head = chatRoomEvents;
|
||||
eventList = [[NSMutableArray alloc] initWithCapacity:bctbx_list_size(chatRoomEvents)];
|
||||
while (chatRoomEvents) {
|
||||
LinphoneEventLog *event = (LinphoneEventLog *)chatRoomEvents->data;
|
||||
[eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
chatRoomEvents = chatRoomEvents->next;
|
||||
}
|
||||
bctbx_list_free_with_data(head, (bctbx_list_free_func)linphone_event_log_unref);
|
||||
|
||||
for (FileTransferDelegate *ftd in [LinphoneManager.instance fileTransferDelegates]) {
|
||||
const LinphoneAddress *ftd_peer =
|
||||
|
|
@ -83,7 +90,6 @@
|
|||
- (void)addEventEntry:(LinphoneEventLog *)event {
|
||||
[eventList addObject:[NSValue valueWithPointer:linphone_event_log_ref(event)]];
|
||||
int pos = (int)eventList.count - 1;
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0];
|
||||
[self.tableView beginUpdates];
|
||||
[self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
|
||||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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 <HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatConversationDelegate,
|
||||
UIDocumentInteractionControllerDelegate, UISearchBarDelegate> {
|
||||
: TPMultiLayoutViewController <HPGrowingTextViewDelegate, UICompositeViewDelegate, ImagePickerDelegate, ChatConversationDelegate, UIDocumentPickerDelegate,
|
||||
UIDocumentInteractionControllerDelegate, UISearchBarDelegate, UIImageViewDeletableDelegate, UICollectionViewDataSource> {
|
||||
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 <UIImage *> *imagesArray;
|
||||
@property NSMutableArray <NSString *> *assetIdsArray;
|
||||
@property NSMutableArray <NSNumber *> *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
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Photos/PHAssetChangeRequest.h>
|
||||
|
||||
#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 <NSString *, PHAsset *> * 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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
@protocol ImagePickerDelegate <NSObject>
|
||||
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSDictionary *)info;
|
||||
- (void)imagePickerDelegateImage:(UIImage *)image info:(NSString *)phAssetId;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
#import <AVFoundation/AVCaptureDevice.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <Photos/Photos.h>
|
||||
#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<PHAsset *> *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
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SCNetworkReachability.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AssetsLibrary/ALAssetsLibrary.h>
|
||||
#import <Photos/Photos.h>
|
||||
#import <CoreTelephony/CTCallCenter.h>
|
||||
|
||||
#import <sqlite3.h>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:assetId] options:nil];
|
||||
if (![assets firstObject]) {
|
||||
LOGE(@"Can't fetch avatar image.");
|
||||
}
|
||||
PHAsset *asset = [assets firstObject];
|
||||
// load avatar synchronously so that we can return UIIMage* directly - since we are
|
||||
// only using thumbnail, it must be pretty fast to fetch even without cache.
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image)
|
||||
ret = [UIImage UIImageThumbnail:image thumbSize:150];
|
||||
else
|
||||
LOGE(@"Can't read avatar");
|
||||
}];
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ret = [UIImage imageNamed:@"avatar.png"];
|
||||
}
|
||||
_avatar = ret;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
|
|
@ -21,12 +21,14 @@
|
|||
<outlet property="downloadButton" destination="N75-gL-R6t" id="EgN-Ab-Ded"/>
|
||||
<outlet property="fileName" destination="Dho-UV-6Ev" id="Iro-II-w8a"/>
|
||||
<outlet property="fileTransferProgress" destination="USm-wC-GvG" id="POt-YD-NCG"/>
|
||||
<outlet property="finalAssetView" destination="VYJ-RC-Jmg" id="fnb-mY-nPR"/>
|
||||
<outlet property="finalImage" destination="gzv-K4-5OL" id="YIw-kM-Ld6"/>
|
||||
<outlet property="imageGestureRecognizer" destination="aDF-hC-ddO" id="2jh-Rr-eKk"/>
|
||||
<outlet property="imageSubView" destination="GmN-7v-uuO" id="k9r-Xc-csv"/>
|
||||
<outlet property="imdmIcon" destination="LPj-VT-0fH" id="yYh-pv-EJs"/>
|
||||
<outlet property="imdmLabel" destination="44j-me-Iqi" id="m5R-Dm-V8g"/>
|
||||
<outlet property="messageImageView" destination="yMW-cT-bpU" id="MNr-F2-abQ"/>
|
||||
<outlet property="messageText" destination="cx9-0K-P9L" id="kPh-s4-Ioy"/>
|
||||
<outlet property="openRecognizer" destination="NYA-II-xYn" id="pVM-vD-4Rg"/>
|
||||
<outlet property="playButton" destination="cvc-tl-Pcf" id="eKJ-2T-LUl"/>
|
||||
<outlet property="resendRecognizer" destination="5ZI-Ip-lGl" id="G2r-On-6mV"/>
|
||||
|
|
@ -35,19 +37,19 @@
|
|||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" misplaced="YES" id="UGz-WT-BUv">
|
||||
<rect key="frame" x="0.0" y="0.0" width="377" height="301"/>
|
||||
<view contentMode="scaleToFill" id="UGz-WT-BUv">
|
||||
<rect key="frame" x="0.0" y="0.0" width="377" height="351"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" id="Y7i-Gm-AdY" userLabel="innerView">
|
||||
<rect key="frame" x="6" y="5" width="365" height="291"/>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Y7i-Gm-AdY" userLabel="innerView">
|
||||
<rect key="frame" x="6" y="5" width="365" height="341"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.20000000298023224" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" id="U2P-5n-gg8" userLabel="backgroundColorImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="365" height="291"/>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.20000000298023224" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="U2P-5n-gg8" userLabel="backgroundColorImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="365" height="341"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" image="avatar.png" id="hD2-19-7IH" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="avatar.png" translatesAutoresizingMaskIntoConstraints="NO" id="hD2-19-7IH" userLabel="avatarImage" customClass="UIRoundedImageView">
|
||||
<rect key="frame" x="7" y="7" width="40" height="40"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact avatar">
|
||||
|
|
@ -55,7 +57,7 @@
|
|||
<bool key="isElement" value="YES"/>
|
||||
</accessibility>
|
||||
</imageView>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="11:35 John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JyR-RQ-uwF" userLabel="contactDateLabel">
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" fixedFrame="YES" text="11:35 John Doe" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JyR-RQ-uwF" userLabel="contactDateLabel">
|
||||
<rect key="frame" x="55" y="8" width="286" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Contact name"/>
|
||||
|
|
@ -63,16 +65,16 @@
|
|||
<color key="textColor" red="0.98766469955444336" green="0.27512490749359131" blue="0.029739789664745331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" misplaced="YES" id="8I3-n2-0kS" userLabel="view">
|
||||
<rect key="frame" x="39" y="55" width="298" height="190"/>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8I3-n2-0kS" userLabel="view">
|
||||
<rect key="frame" x="39" y="55" width="298" height="230"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="linphone_logo.png" id="yMW-cT-bpU" userLabel="image" customClass="UILoadingImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="298" height="122"/>
|
||||
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="linphone_logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="yMW-cT-bpU" userLabel="image" customClass="UILoadingImageView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="298" height="148"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<gestureRecognizers/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Label" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Dho-UV-6Ev" userLabel="fileName">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dho-UV-6Ev" userLabel="fileName">
|
||||
<rect key="frame" x="0.0" y="0.0" width="200" height="50"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
|
|
@ -80,16 +82,16 @@
|
|||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" id="GmN-7v-uuO" userLabel="imageSubView">
|
||||
<rect key="frame" x="0.0" y="128" width="297" height="62"/>
|
||||
<view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GmN-7v-uuO" userLabel="imageSubView">
|
||||
<rect key="frame" x="0.0" y="155" width="297" height="75"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" id="USm-wC-GvG" userLabel="transferProgress">
|
||||
<rect key="frame" x="10" y="29" width="277" height="2"/>
|
||||
<progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" fixedFrame="YES" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="USm-wC-GvG" userLabel="transferProgress">
|
||||
<rect key="frame" x="10" y="42" width="277" height="2"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
</progressView>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="N75-gL-R6t" userLabel="downloadButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="84" y="33" width="115" height="27"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="N75-gL-R6t" userLabel="downloadButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="84" y="46" width="115" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Download"/>
|
||||
<state key="normal" title="DOWNLOAD" backgroundImage="color_G.png">
|
||||
|
|
@ -100,8 +102,8 @@
|
|||
<action selector="onDownloadClick:" destination="-1" eventType="touchUpInside" id="8BO-9E-iOX"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="6dl-Nz-rdv" userLabel="cancelButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="84" y="33" width="115" height="27"/>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6dl-Nz-rdv" userLabel="cancelButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="84" y="46" width="115" height="27"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
|
|
@ -117,16 +119,16 @@
|
|||
</view>
|
||||
</subviews>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" misplaced="YES" id="VYJ-RC-Jmg">
|
||||
<rect key="frame" x="8" y="55" width="349" height="213"/>
|
||||
<view clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" preservesSuperviewLayoutMargins="YES" translatesAutoresizingMaskIntoConstraints="NO" id="VYJ-RC-Jmg" userLabel="finalAssetView">
|
||||
<rect key="frame" x="0.0" y="55" width="365" height="230"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" id="gzv-K4-5OL" userLabel="finalImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="349" height="213"/>
|
||||
<imageView hidden="YES" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gzv-K4-5OL" userLabel="finalImage">
|
||||
<rect key="frame" x="0.0" y="0.0" width="365" height="230"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<gestureRecognizers/>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="cvc-tl-Pcf" userLabel="playButton" customClass="UIRoundBorderedButton">
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="cvc-tl-Pcf" userLabel="playButton" customClass="UIRoundBorderedButton">
|
||||
<rect key="frame" x="125" y="93" width="50" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Cancel"/>
|
||||
|
|
@ -145,28 +147,35 @@
|
|||
<outletCollection property="gestureRecognizers" destination="NYA-II-xYn" appends="YES" id="fK6-ld-zOX"/>
|
||||
</connections>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" id="6dA-3U-OPW" userLabel="bottomBarColor">
|
||||
<rect key="frame" x="0.0" y="290" width="365" height="1"/>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="6dA-3U-OPW" userLabel="bottomBarColor">
|
||||
<rect key="frame" x="0.0" y="340" width="365" height="1"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
</imageView>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="gray" id="Eab-ND-ix3" userLabel="statusInprogressSpinner">
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" hidesWhenStopped="YES" animating="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="Eab-ND-ix3" userLabel="statusInprogressSpinner">
|
||||
<rect key="frame" x="345" y="0.0" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="chat_unsecure.png" id="IST-5o-DCu" userLabel="LIMEKO">
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="chat_unsecure.png" translatesAutoresizingMaskIntoConstraints="NO" id="IST-5o-DCu" userLabel="LIMEKO">
|
||||
<rect key="frame" x="351" y="6" width="8" height="12"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Delivered" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="44j-me-Iqi" userLabel="imdmLabel">
|
||||
<rect key="frame" x="283" y="274" width="64" height="20"/>
|
||||
<textView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" editable="NO" text="Lore ipsum..." translatesAutoresizingMaskIntoConstraints="NO" id="cx9-0K-P9L" userLabel="messageText" customClass="UITextViewNoDefine">
|
||||
<rect key="frame" x="8" y="285" width="349" height="47"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
<dataDetectorType key="dataDetectorTypes" link="YES"/>
|
||||
</textView>
|
||||
<label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Delivered" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="44j-me-Iqi" userLabel="imdmLabel">
|
||||
<rect key="frame" x="283" y="324" width="64" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="1" green="0.36862745099999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="valid_default.png" id="LPj-VT-0fH" userLabel="imdmIcon">
|
||||
<rect key="frame" x="349" y="276" width="13" height="13"/>
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="valid_default.png" translatesAutoresizingMaskIntoConstraints="NO" id="LPj-VT-0fH" userLabel="imdmIcon">
|
||||
<rect key="frame" x="349" y="326" width="13" height="13"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed"/>
|
||||
</imageView>
|
||||
|
|
@ -179,7 +188,7 @@
|
|||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<point key="canvasLocation" x="-73.5" y="246.5"/>
|
||||
<point key="canvasLocation" x="-73.5" y="271.5"/>
|
||||
</view>
|
||||
<tapGestureRecognizer id="5ZI-Ip-lGl" userLabel="resendClick">
|
||||
<connections>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="chat_read.png" id="aa2-Kl-c1H" userLabel="imdmIcon">
|
||||
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" image="chat_read.png" id="aa2-Kl-c1H" userLabel="imdmIcon">
|
||||
<rect key="frame" x="59" y="39" width="13" height="13"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration" label="Delivery failed">
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<PHAsset *> *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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<PHAsset *> *assets = [PHAsset fetchAssetsWithLocalIdentifiers:[NSArray arrayWithObject:localImage] options:nil];
|
||||
if (![assets firstObject])
|
||||
return;
|
||||
PHAsset *asset = [assets firstObject];
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.synchronous = TRUE;
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeDefault options:options
|
||||
resultHandler:^(UIImage *image, NSDictionary * info) {
|
||||
if (image) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
|
||||
^(void) {
|
||||
[_chatRoomDelegate startImageUpload: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<PHAsset *> *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;
|
||||
}
|
||||
|
|
|
|||
26
Classes/LinphoneUI/UIImageViewDeletable.h
Normal file
26
Classes/LinphoneUI/UIImageViewDeletable.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// UIImageViewDeletable.h
|
||||
// linphone
|
||||
//
|
||||
// Created by benjamin_verdier on 28/06/2018.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol UIImageViewDeletableDelegate
|
||||
|
||||
@required
|
||||
|
||||
- (void)deleteImageWithAssetId:(NSString *)assetId;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIImageViewDeletable : UICollectionViewCell
|
||||
|
||||
@property NSString *assetId;
|
||||
@property(nonatomic, strong) id<UIImageViewDeletableDelegate> deleteDelegate;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *image;
|
||||
|
||||
- (IBAction)onDeletePressed;
|
||||
|
||||
@end
|
||||
59
Classes/LinphoneUI/UIImageViewDeletable.m
Normal file
59
Classes/LinphoneUI/UIImageViewDeletable.m
Normal file
|
|
@ -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
|
||||
50
Classes/LinphoneUI/UIImageViewDeletable.xib
Normal file
50
Classes/LinphoneUI/UIImageViewDeletable.xib
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="UIImageViewDeletable">
|
||||
<connections>
|
||||
<outlet property="image" destination="y2f-LK-bVa" id="VPy-6D-kNb"/>
|
||||
</connections>
|
||||
</placeholder>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="y2f-LK-bVa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="50" height="100"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</imageView>
|
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="J60-eT-n9R">
|
||||
<rect key="frame" x="30" y="0.0" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||
<accessibility key="accessibilityConfiguration">
|
||||
<accessibilityTraits key="traits" button="YES" image="YES"/>
|
||||
</accessibility>
|
||||
<state key="normal" image="delete_img.png"/>
|
||||
<connections>
|
||||
<action selector="onDeletePressed" destination="-1" eventType="touchUpInside" id="cmV-ac-rq7"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/>
|
||||
<point key="canvasLocation" x="7" y="47"/>
|
||||
</view>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="delete_img.png" width="50" height="50"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ typedef enum {
|
|||
+ (NSString *)durationToString:(int)duration;
|
||||
+ (NSString *)intervalToString:(NSTimeInterval)interval ;
|
||||
|
||||
+ (NSMutableDictionary <NSString *, PHAsset *> *)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 \
|
||||
|
|
|
|||
|
|
@ -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 <NSString *, PHAsset *> *)photoAssetsDictionary {
|
||||
NSMutableDictionary <NSString *, PHAsset *> *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 <NSString *, PHAsset *> *)videoAssetsDictionary {
|
||||
NSMutableDictionary <NSString *, PHAsset *> *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
|
||||
|
|
|
|||
BIN
Resources/images/delete_img.png
Normal file
BIN
Resources/images/delete_img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
|
|
@ -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 = "<group>"; };
|
||||
570742631D5A1860004B9C84 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ShopView.strings; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
5E223A9820E244B400D06A36 /* NotificationTableViewCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationTableViewCell.m; sourceTree = "<group>"; };
|
||||
5E30780420D8F00D00256DAE /* latestChatroomsWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = latestChatroomsWidget.entitlements; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
5E31290420D7A37E00CF3AAE /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = "<group>"; };
|
||||
5E31290720D7A37E00CF3AAE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
5E31290920D7A37E00CF3AAE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
5E58962920DCE5700030868C /* NotificationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NotificationViewController.m; sourceTree = "<group>"; };
|
||||
5E58962C20DCE5700030868C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
|
||||
5E58962E20DCE5710030868C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
5EEE8F9E20C80C23006E4176 /* TodayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TodayViewController.m; sourceTree = "<group>"; };
|
||||
|
|
@ -1829,6 +1859,10 @@
|
|||
C90FAA7615AF54E6002091CB /* HistoryDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryDetailsView.h; sourceTree = "<group>"; };
|
||||
C90FAA7715AF54E6002091CB /* HistoryDetailsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HistoryDetailsView.m; sourceTree = "<group>"; };
|
||||
C9B3A6FD15B485DB006F52EE /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = Utils/Utils.h; sourceTree = "<group>"; };
|
||||
CF15F21B20E4F9A3008B1DE6 /* UIImageViewDeletable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIImageViewDeletable.h; sourceTree = "<group>"; };
|
||||
CF15F21C20E4F9A3008B1DE6 /* UIImageViewDeletable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIImageViewDeletable.m; sourceTree = "<group>"; };
|
||||
CF15F21D20E4F9A3008B1DE6 /* UIImageViewDeletable.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UIImageViewDeletable.xib; sourceTree = "<group>"; };
|
||||
CFBD7A2320E504AD007C5286 /* delete_img.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = delete_img.png; sourceTree = "<group>"; };
|
||||
D306459C1611EC2900BB571E /* UILoadingImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UILoadingImageView.h; sourceTree = "<group>"; };
|
||||
D306459D1611EC2900BB571E /* UILoadingImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UILoadingImageView.m; sourceTree = "<group>"; };
|
||||
D3128FDE15AABC7E00A2147A /* ContactDetailsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactDetailsView.h; sourceTree = "<group>"; };
|
||||
|
|
@ -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 = "<group>";
|
||||
|
|
@ -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 = "<group>";
|
||||
|
|
@ -2506,6 +2555,19 @@
|
|||
path = latestChatroomsWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
};
|
||||
5E58962B20DCE5700030868C /* MainInterface.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
5E58962C20DCE5700030868C /* Base */,
|
||||
);
|
||||
name = MainInterface.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = (
|
||||
|
|
|
|||
|
|
@ -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<NSSecureCoding> _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];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
|||
135
richNotifications/Base.lproj/MainInterface.storyboard
Normal file
135
richNotifications/Base.lproj/MainInterface.storyboard
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="X9Y-jO-gVr">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Notification View Controller-->
|
||||
<scene sceneID="ciY-6l-Mki">
|
||||
<objects>
|
||||
<tableViewController id="X9Y-jO-gVr" customClass="NotificationViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="xjB-Tn-AYr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="notificationCell" id="4dO-Sq-LtB" customClass="NotificationTableViewCell">
|
||||
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="4dO-Sq-LtB" id="Q3t-C0-U1O">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="OXj-8D-5BS">
|
||||
<rect key="frame" x="60" y="10" width="310" height="32"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="WZa-ow-o0L">
|
||||
<rect key="frame" x="0.0" y="0.0" width="310" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="17" id="tvJ-aj-CIf"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" text="Lorem ipsum " textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="3tK-2u-Ixe">
|
||||
<rect key="frame" x="0.0" y="17" width="310" height="1.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="rnc-rL-KN8">
|
||||
<rect key="frame" x="0.0" y="18.5" width="310" height="13.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gv1-l8-gh3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="292" height="13.5"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="VYP-sN-Q5F">
|
||||
<rect key="frame" x="297" y="0.0" width="13" height="13.5"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="13" id="Drj-Lw-Eis"/>
|
||||
<constraint firstAttribute="width" constant="13" id="NvK-gG-A0n"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="VYP-sN-Q5F" secondAttribute="trailing" id="6ov-Ze-XHU"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="WZa-ow-o0L" firstAttribute="leading" secondItem="OXj-8D-5BS" secondAttribute="leading" id="7wZ-7m-XoH"/>
|
||||
<constraint firstItem="3tK-2u-Ixe" firstAttribute="leading" secondItem="OXj-8D-5BS" secondAttribute="leading" id="A4k-hw-bfV"/>
|
||||
<constraint firstItem="3tK-2u-Ixe" firstAttribute="top" secondItem="WZa-ow-o0L" secondAttribute="bottom" id="XWZ-K9-hVC"/>
|
||||
<constraint firstItem="WZa-ow-o0L" firstAttribute="top" secondItem="OXj-8D-5BS" secondAttribute="top" id="dSr-F5-pKr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rnc-rL-KN8" secondAttribute="bottom" id="o3L-83-aYX"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rnc-rL-KN8" secondAttribute="trailing" id="xIZ-Pw-t6a"/>
|
||||
</constraints>
|
||||
</stackView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="SKQ-W1-Lmw">
|
||||
<rect key="frame" x="10" y="10" width="40" height="40"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="d6N-Hv-RS0"/>
|
||||
<constraint firstAttribute="width" constant="40" id="kWJ-Qu-esd"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="Wh2-bk-96C" userLabel="BottomBar">
|
||||
<rect key="frame" x="0.0" y="43" width="375" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="xx0-Om-qom"/>
|
||||
</constraints>
|
||||
</imageView>
|
||||
<imageView userInteractionEnabled="NO" alpha="0.20000000000000001" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="color_A.png" translatesAutoresizingMaskIntoConstraints="NO" id="FHB-G3-atz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="OXj-8D-5BS" firstAttribute="top" secondItem="Q3t-C0-U1O" secondAttribute="top" constant="10" id="9no-0X-SIc"/>
|
||||
<constraint firstItem="SKQ-W1-Lmw" firstAttribute="top" secondItem="Q3t-C0-U1O" secondAttribute="top" constant="10" id="EqG-ZA-H0w"/>
|
||||
<constraint firstItem="Wh2-bk-96C" firstAttribute="centerX" secondItem="Q3t-C0-U1O" secondAttribute="centerX" id="GiJ-VV-sUL"/>
|
||||
<constraint firstItem="FHB-G3-atz" firstAttribute="centerX" secondItem="Q3t-C0-U1O" secondAttribute="centerX" id="Il9-x1-er0"/>
|
||||
<constraint firstItem="FHB-G3-atz" firstAttribute="centerY" secondItem="Q3t-C0-U1O" secondAttribute="centerY" id="M94-ru-dxk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="OXj-8D-5BS" secondAttribute="trailing" constant="5" id="Oq5-ST-lUC"/>
|
||||
<constraint firstItem="FHB-G3-atz" firstAttribute="top" secondItem="Q3t-C0-U1O" secondAttribute="top" id="UHW-lR-QSP"/>
|
||||
<constraint firstItem="SKQ-W1-Lmw" firstAttribute="leading" secondItem="Q3t-C0-U1O" secondAttribute="leading" constant="10" id="ZPR-9n-0E4"/>
|
||||
<constraint firstItem="FHB-G3-atz" firstAttribute="leading" secondItem="Q3t-C0-U1O" secondAttribute="leading" id="d7N-zS-IjG"/>
|
||||
<constraint firstItem="OXj-8D-5BS" firstAttribute="leading" secondItem="Q3t-C0-U1O" secondAttribute="leading" constant="60" id="e0Q-na-hor"/>
|
||||
<constraint firstItem="Wh2-bk-96C" firstAttribute="leading" secondItem="Q3t-C0-U1O" secondAttribute="leading" id="hOW-4m-Ke6"/>
|
||||
<constraint firstItem="OXj-8D-5BS" firstAttribute="bottom" secondItem="Q3t-C0-U1O" secondAttribute="bottom" constant="-2" id="mVA-WG-D1q"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Wh2-bk-96C" secondAttribute="bottom" id="scj-em-N61"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<outlet property="background" destination="FHB-G3-atz" id="x5b-Bw-EFi"/>
|
||||
<outlet property="bottomBarColor" destination="Wh2-bk-96C" id="wxV-mb-eTf"/>
|
||||
<outlet property="contactImage" destination="SKQ-W1-Lmw" id="nsD-4b-g0W"/>
|
||||
<outlet property="imdm" destination="gv1-l8-gh3" id="ceS-Ho-kpi"/>
|
||||
<outlet property="imdmImage" destination="VYP-sN-Q5F" id="hNY-Ig-KqX"/>
|
||||
<outlet property="msgText" destination="3tK-2u-Ixe" id="aVq-ra-Sd7"/>
|
||||
<outlet property="nameDate" destination="WZa-ow-o0L" id="WdA-QI-xv1"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<sections/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="X9Y-jO-gVr" id="TwP-dT-I3s"/>
|
||||
<outlet property="delegate" destination="X9Y-jO-gVr" id="2OC-kx-QgD"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="EXl-Zq-25w" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-263.19999999999999" y="18.440779610194905"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="color_A.png" width="2" height="2"/>
|
||||
</resources>
|
||||
</document>
|
||||
40
richNotifications/Info.plist
Normal file
40
richNotifications/Info.plist
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>richNotifications</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>UNNotificationExtensionDefaultContentHidden</key>
|
||||
<true/>
|
||||
<key>UNNotificationExtensionCategory</key>
|
||||
<string>msg_cat</string>
|
||||
<key>UNNotificationExtensionInitialContentSizeRatio</key>
|
||||
<real>1</real>
|
||||
</dict>
|
||||
<key>NSExtensionMainStoryboard</key>
|
||||
<string>MainInterface</string>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.usernotifications.content-extension</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
24
richNotifications/NotificationTableViewCell.h
Normal file
24
richNotifications/NotificationTableViewCell.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// NotificationTableViewCell.h
|
||||
// richNotifications
|
||||
//
|
||||
// Created by David Idmansour on 26/06/2018.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@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
|
||||
94
richNotifications/NotificationTableViewCell.m
Normal file
94
richNotifications/NotificationTableViewCell.m
Normal file
|
|
@ -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
|
||||
12
richNotifications/NotificationViewController.h
Normal file
12
richNotifications/NotificationViewController.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
//
|
||||
// NotificationViewController.h
|
||||
// richNotifications
|
||||
//
|
||||
// Created by David Idmansour on 22/06/2018.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NotificationViewController : UITableViewController
|
||||
|
||||
@end
|
||||
110
richNotifications/NotificationViewController.m
Normal file
110
richNotifications/NotificationViewController.m
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
//
|
||||
// NotificationViewController.m
|
||||
// richNotifications
|
||||
//
|
||||
// Created by David Idmansour on 22/06/2018.
|
||||
//
|
||||
|
||||
#import "NotificationViewController.h"
|
||||
#import "NotificationTableViewCell.h"
|
||||
#import <UserNotifications/UserNotifications.h>
|
||||
#import <UserNotificationsUI/UserNotificationsUI.h>
|
||||
|
||||
@interface NotificationViewController () <UNNotificationContentExtension>
|
||||
|
||||
@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
|
||||
Loading…
Add table
Reference in a new issue