1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-02 09:27:55 +01:00
Telegram/Share/TGItemProviderSignals.m
2016-02-25 01:03:51 +01:00

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