mirror of
https://github.com/danog/Telegram.git
synced 2024-12-02 09:27:55 +01:00
350 lines
14 KiB
Objective-C
350 lines
14 KiB
Objective-C
#import "TGItemProviderSignals.h"
|
|
|
|
#import <UIKit/UIKit.h>
|
|
#import <MobileCoreServices/MobileCoreServices.h>
|
|
#import <AddressBook/AddressBook.h>
|
|
#import <AVFoundation/AVFoundation.h>
|
|
#import "TGPhoneUtils.h"
|
|
#import "TGMimeTypeMap.h"
|
|
|
|
#import "TGContactModel.h"
|
|
|
|
@implementation TGItemProviderSignals
|
|
|
|
+ (NSArray *)itemSignalsForInputItems:(NSArray *)inputItems
|
|
{
|
|
NSMutableArray *itemSignals = [[NSMutableArray alloc] init];
|
|
NSMutableArray *providers = [[NSMutableArray alloc] init];
|
|
|
|
for (NSExtensionItem *item in inputItems)
|
|
{
|
|
for (NSItemProvider *provider in item.attachments)
|
|
{
|
|
if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeMovie])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeAudio])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeFileURL])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL]) {
|
|
[providers removeAllObjects];
|
|
|
|
[providers addObject:provider];
|
|
break;
|
|
}
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeVCard])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeText])
|
|
[providers addObject:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeData])
|
|
[providers addObject:provider];
|
|
}
|
|
}
|
|
|
|
NSInteger providerIndex = -1;
|
|
for (NSItemProvider *provider in providers)
|
|
{
|
|
providerIndex++;
|
|
|
|
SSignal *dataSignal = nil;
|
|
if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeAudio])
|
|
dataSignal = [self signalForAudioItemProvider:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeMovie])
|
|
dataSignal = [self signalForVideoItemProvider:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage])
|
|
dataSignal = [self signalForImageItemProvider:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeFileURL])
|
|
{
|
|
dataSignal = [[self signalForUrlItemProvider:provider] mapToSignal:^SSignal *(NSURL *url)
|
|
{
|
|
NSData *data = [[NSData alloc] initWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:nil];
|
|
if (data == nil)
|
|
return [SSignal fail:nil];
|
|
NSString *fileName = [[url pathComponents] lastObject];
|
|
if (fileName.length == 0)
|
|
fileName = @"file.bin";
|
|
NSString *extension = [fileName pathExtension];
|
|
NSString *mimeType = [TGMimeTypeMap mimeTypeForExtension:[extension lowercaseString]];
|
|
if (mimeType == nil)
|
|
mimeType = @"application/octet-stream";
|
|
return [SSignal single:@{@"data": data, @"fileName": fileName, @"mimeType": mimeType}];
|
|
}];
|
|
}
|
|
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeVCard])
|
|
dataSignal = [self signalForVCardItemProvider:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeText])
|
|
dataSignal = [self signalForTextItemProvider:provider];
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL])
|
|
dataSignal = [self signalForTextUrlItemProvider:provider];
|
|
|
|
else if ([provider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeData])
|
|
{
|
|
dataSignal = [[self signalForDataItemProvider:provider] map:^id(NSDictionary *dict)
|
|
{
|
|
if (dict[@"fileName"] == nil)
|
|
{
|
|
NSMutableDictionary *updatedDict = [[NSMutableDictionary alloc] initWithDictionary:dict];
|
|
for (NSString *typeIdentifier in provider.registeredTypeIdentifiers)
|
|
{
|
|
NSString *extension = [TGMimeTypeMap extensionForMimeType:typeIdentifier];
|
|
if (extension == nil)
|
|
extension = [TGMimeTypeMap extensionForMimeType:[@"application/" stringByAppendingString:typeIdentifier]];
|
|
|
|
if (extension != nil) {
|
|
updatedDict[@"fileName"] = [@"file" stringByAppendingPathExtension:extension];
|
|
updatedDict[@"mimeType"] = [TGMimeTypeMap mimeTypeForExtension:extension];
|
|
}
|
|
}
|
|
return updatedDict;
|
|
}
|
|
else
|
|
{
|
|
return dict;
|
|
}
|
|
}];
|
|
}
|
|
|
|
if (dataSignal != nil)
|
|
[itemSignals addObject:dataSignal];
|
|
}
|
|
|
|
return itemSignals;
|
|
}
|
|
|
|
+ (SSignal *)signalForDataItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(NSData *data, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:@{@"data": data}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForImageItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeData options:nil completionHandler:^(UIImage *image, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:@{@"image": image}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForAudioItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
SSignal *itemSignal = [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeAudio options:nil completionHandler:^(NSURL *url, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:url];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
return nil;
|
|
}];
|
|
|
|
return [itemSignal map:^id(NSURL *url)
|
|
{
|
|
AVAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
|
|
if (asset == nil)
|
|
return [SSignal fail:nil];
|
|
|
|
NSString *extension = url.pathExtension;
|
|
NSString *mimeType = [TGMimeTypeMap mimeTypeForExtension:[extension lowercaseString]];
|
|
if (mimeType == nil)
|
|
mimeType = @"application/octet-stream";
|
|
|
|
NSString *title = (NSString *)[[AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyTitle keySpace:AVMetadataKeySpaceCommon] firstObject];
|
|
NSString *artist = (NSString *)[[AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeyArtist keySpace:AVMetadataKeySpaceCommon] firstObject];
|
|
|
|
NSString *software = nil;
|
|
AVMetadataItem *softwareItem = [[AVMetadataItem metadataItemsFromArray:asset.commonMetadata withKey:AVMetadataCommonKeySoftware keySpace:AVMetadataKeySpaceCommon] firstObject];
|
|
if ([softwareItem isKindOfClass:[AVMetadataItem class]] && ([softwareItem.value isKindOfClass:[NSString class]]))
|
|
software = (NSString *)[softwareItem value];
|
|
|
|
bool isVoice = [software hasPrefix:@"com.apple.VoiceMemos"];
|
|
|
|
NSTimeInterval duration = CMTimeGetSeconds(asset.duration);
|
|
|
|
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
|
|
result[@"audio"] = url;
|
|
result[@"mimeType"] = mimeType;
|
|
result[@"duration"] = @(duration);
|
|
result[@"isVoice"] = @(isVoice);
|
|
if (artist.length > 0)
|
|
result[@"artist"] = artist;
|
|
if (title.length > 0)
|
|
result[@"title"] = title;
|
|
|
|
return result;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForVideoItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeMovie options:nil completionHandler:^(NSURL *url, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
NSString *extension = url.pathExtension;
|
|
NSString *mimeType = [TGMimeTypeMap mimeTypeForExtension:[extension lowercaseString]];
|
|
if (mimeType == nil)
|
|
mimeType = @"application/octet-stream";
|
|
|
|
[subscriber putNext:@{@"video": url, @"mimeType": mimeType}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForUrlItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeFileURL options:nil completionHandler:^(NSURL *url, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:url];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForTextItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeText options:nil completionHandler:^(NSString *text, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:@{@"text": text}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForTextUrlItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
[subscriber putNext:@{@"url": url}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
+ (SSignal *)signalForVCardItemProvider:(NSItemProvider *)itemProvider
|
|
{
|
|
return [[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber)
|
|
{
|
|
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeVCard options:nil completionHandler:^(NSData *vcard, NSError *error)
|
|
{
|
|
if (error != nil)
|
|
[subscriber putError:nil];
|
|
else
|
|
{
|
|
CFDataRef vCardData = CFDataCreate(NULL, vcard.bytes, vcard.length);
|
|
ABAddressBookRef book = ABAddressBookCreate();
|
|
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
|
|
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
|
|
CFIndex index = 0;
|
|
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
|
|
|
|
NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
|
|
NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
|
|
|
|
if (firstName.length == 0 && lastName.length == 0)
|
|
lastName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonOrganizationProperty);
|
|
|
|
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
|
|
|
|
NSInteger phoneCount = (phones == NULL) ? 0 : ABMultiValueGetCount(phones);
|
|
NSMutableArray *personPhones = [[NSMutableArray alloc] initWithCapacity:phoneCount];
|
|
|
|
for (CFIndex i = 0; i < phoneCount; i++)
|
|
{
|
|
NSString *number = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, i);
|
|
NSString *label = nil;
|
|
|
|
CFStringRef valueLabel = ABMultiValueCopyLabelAtIndex(phones, i);
|
|
if (valueLabel != NULL)
|
|
{
|
|
label = (__bridge_transfer NSString *)ABAddressBookCopyLocalizedLabel(valueLabel);
|
|
CFRelease(valueLabel);
|
|
}
|
|
|
|
if (number.length != 0)
|
|
{
|
|
TGPhoneNumberModel *phoneNumber = [[TGPhoneNumberModel alloc] initWithPhoneNumber:number label:label];
|
|
[personPhones addObject:phoneNumber];
|
|
}
|
|
}
|
|
if (phones != NULL)
|
|
CFRelease(phones);
|
|
|
|
TGContactModel *contact = [[TGContactModel alloc] initWithFirstName:firstName lastName:lastName phoneNumbers:personPhones];
|
|
[subscriber putNext:@{@"contact": contact}];
|
|
[subscriber putCompletion];
|
|
}
|
|
}];
|
|
|
|
return nil;
|
|
}];
|
|
}
|
|
|
|
@end
|