mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
365 lines
13 KiB
Objective-C
365 lines
13 KiB
Objective-C
#import "TGShareLocationSignals.h"
|
|
|
|
NSString *const TGShareAppleMapsHost = @"maps.apple.com";
|
|
NSString *const TGShareAppleMapsPath = @"/maps";
|
|
NSString *const TGShareAppleMapsLatLonKey = @"ll";
|
|
NSString *const TGShareAppleMapsNameKey = @"q";
|
|
NSString *const TGShareAppleMapsAddressKey = @"address";
|
|
NSString *const TGShareAppleMapsIdKey = @"auid";
|
|
NSString *const TGShareAppleMapsProvider = @"apple";
|
|
|
|
NSString *const TGShareFoursquareHost = @"foursquare.com";
|
|
NSString *const TGShareFoursquareVenuePath = @"/v";
|
|
|
|
NSString *const TGShareFoursquareVenueEndpointUrl = @"https://api.foursquare.com/v2/venues/";
|
|
NSString *const TGShareFoursquareClientId = @"BN3GWQF1OLMLKKQTFL0OADWD1X1WCDNISPPOT1EMMUYZTQV1";
|
|
NSString *const TGShareFoursquareClientSecret = @"WEEZHCKI040UVW2KWW5ZXFAZ0FMMHKQ4HQBWXVSX4WXWBWYN";
|
|
NSString *const TGShareFoursquareVersion = @"20150326";
|
|
NSString *const TGShareFoursquareVenuesCountLimit = @"25";
|
|
NSString *const TGShareFoursquareLocale = @"en";
|
|
NSString *const TGShareFoursquareProvider = @"foursquare";
|
|
|
|
NSString *const TGShareGoogleShortenerEndpointUrl = @"https://www.googleapis.com/urlshortener/v1/url";
|
|
NSString *const TGShareGoogleAPIKey = @"AIzaSyBCTH4aAdvi0MgDGlGNmQAaFS8GTNBrfj4";
|
|
NSString *const TGShareGoogleMapsShortHost = @"goo.gl";
|
|
NSString *const TGShareGoogleMapsShortPath = @"/maps";
|
|
NSString *const TGShareGoogleMapsHost = @"google.com";
|
|
NSString *const TGShareGoogleMapsSearchPath = @"maps/search";
|
|
NSString *const TGShareGoogleMapsPlacePath = @"maps/place";
|
|
NSString *const TGShareGoogleProvider = @"google";
|
|
|
|
@implementation TGShareLocationResult
|
|
|
|
- (instancetype)initWithLatitude:(double)latitude longitude:(double)longitude title:(NSString *)title address:(NSString *)address provider:(NSString *)provider venueId:(NSString *)venueId venueType:(NSString *)venueType {
|
|
self = [super init];
|
|
if (self != nil) {
|
|
_latitude = latitude;
|
|
_longitude = longitude;
|
|
_title = title;
|
|
_address = address;
|
|
_provider = provider;
|
|
_venueId = venueId;
|
|
_venueType = venueType;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
@end
|
|
|
|
@interface TGQueryStringComponent : NSObject {
|
|
@private
|
|
NSString *_key;
|
|
NSString *_value;
|
|
}
|
|
|
|
@property (readwrite, nonatomic, retain) id key;
|
|
@property (readwrite, nonatomic, retain) id value;
|
|
|
|
- (id)initWithKey:(id)key value:(id)value;
|
|
- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding;
|
|
|
|
@end
|
|
|
|
NSString * TGURLEncodedStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding) {
|
|
static NSString * const kAFLegalCharactersToBeEscaped = @"?!@#$^&%*+=,:;'\"`<>()[]{}/\\|~ ";
|
|
NSString *unescapedString = [string stringByReplacingPercentEscapesUsingEncoding:encoding];
|
|
if (unescapedString) {
|
|
string = unescapedString;
|
|
}
|
|
|
|
return (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFLegalCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding));
|
|
}
|
|
|
|
@implementation TGQueryStringComponent
|
|
@synthesize key = _key;
|
|
@synthesize value = _value;
|
|
|
|
- (id)initWithKey:(id)key value:(id)value {
|
|
self = [super init];
|
|
if (!self) {
|
|
return nil;
|
|
}
|
|
|
|
self.key = key;
|
|
self.value = value;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding {
|
|
return [NSString stringWithFormat:@"%@=%@", self.key, TGURLEncodedStringFromStringWithEncoding([self.value description], stringEncoding)];
|
|
}
|
|
|
|
@end
|
|
|
|
static NSString * TGQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding);
|
|
static NSArray * TGQueryStringComponentsFromKeyAndValue(NSString *key, id value);
|
|
NSArray * TGQueryStringComponentsFromKeyAndDictionaryValue(NSString *key, NSDictionary *value);
|
|
NSArray * TGQueryStringComponentsFromKeyAndArrayValue(NSString *key, NSArray *value);
|
|
|
|
static NSString * TGQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) {
|
|
NSMutableArray *mutableComponents = [NSMutableArray array];
|
|
for (TGQueryStringComponent *component in TGQueryStringComponentsFromKeyAndValue(nil, parameters)) {
|
|
[mutableComponents addObject:[component URLEncodedStringValueWithEncoding:stringEncoding]];
|
|
}
|
|
|
|
return [mutableComponents componentsJoinedByString:@"&"];
|
|
}
|
|
|
|
static NSArray * TGQueryStringComponentsFromKeyAndValue(NSString *key, id value) {
|
|
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
|
|
|
|
if([value isKindOfClass:[NSDictionary class]]) {
|
|
[mutableQueryStringComponents addObjectsFromArray:TGQueryStringComponentsFromKeyAndDictionaryValue(key, value)];
|
|
} else if([value isKindOfClass:[NSArray class]]) {
|
|
[mutableQueryStringComponents addObjectsFromArray:TGQueryStringComponentsFromKeyAndArrayValue(key, value)];
|
|
} else {
|
|
[mutableQueryStringComponents addObject:[[TGQueryStringComponent alloc] initWithKey:key value:value]];
|
|
}
|
|
|
|
return mutableQueryStringComponents;
|
|
}
|
|
|
|
NSArray * TGQueryStringComponentsFromKeyAndDictionaryValue(NSString *key, NSDictionary *value){
|
|
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
|
|
|
|
[value enumerateKeysAndObjectsUsingBlock:^(id nestedKey, id nestedValue, __unused BOOL *stop) {
|
|
[mutableQueryStringComponents addObjectsFromArray:TGQueryStringComponentsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
|
|
}];
|
|
|
|
return mutableQueryStringComponents;
|
|
}
|
|
|
|
NSArray * TGQueryStringComponentsFromKeyAndArrayValue(NSString *key, NSArray *value) {
|
|
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
|
|
|
|
[value enumerateObjectsUsingBlock:^(id nestedValue, __unused NSUInteger idx, __unused BOOL *stop) {
|
|
[mutableQueryStringComponents addObjectsFromArray:TGQueryStringComponentsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
|
|
}];
|
|
|
|
return mutableQueryStringComponents;
|
|
}
|
|
|
|
@implementation TGShareLocationSignals
|
|
|
|
+ (MTSignal *)locationMessageContentForURL:(NSURL *)url
|
|
{
|
|
if ([self isAppleMapsURL:url])
|
|
return [self _appleMapsLocationContentForURL:url];
|
|
else if ([self isFoursquareURL:url])
|
|
return [self _foursquareLocationForURL:url];
|
|
|
|
return [MTSignal single:nil];
|
|
}
|
|
|
|
+ (MTSignal *)_appleMapsLocationContentForURL:(NSURL *)url
|
|
{
|
|
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:false];
|
|
NSArray *queryItems = urlComponents.queryItems;
|
|
|
|
NSString *latLon = nil;
|
|
NSString *name = nil;
|
|
NSString *address = nil;
|
|
NSString *venueId = nil;
|
|
for (NSURLQueryItem *queryItem in queryItems)
|
|
{
|
|
if ([queryItem.name isEqualToString:TGShareAppleMapsLatLonKey])
|
|
{
|
|
latLon = queryItem.value;
|
|
}
|
|
else if ([queryItem.name isEqualToString:TGShareAppleMapsNameKey])
|
|
{
|
|
if (![queryItem.value isEqualToString:latLon])
|
|
name = queryItem.value;
|
|
}
|
|
else if ([queryItem.name isEqualToString:TGShareAppleMapsAddressKey])
|
|
{
|
|
address = queryItem.value;
|
|
}
|
|
else if ([queryItem.name isEqualToString:TGShareAppleMapsIdKey])
|
|
{
|
|
venueId = queryItem.value;
|
|
}
|
|
}
|
|
|
|
if (latLon == nil)
|
|
return [MTSignal fail:nil];
|
|
|
|
NSArray *coordComponents = [latLon componentsSeparatedByString:@","];
|
|
if (coordComponents.count != 2)
|
|
return [MTSignal fail:nil];
|
|
|
|
double latitude = [coordComponents.firstObject floatValue];
|
|
double longitude = [coordComponents.lastObject floatValue];
|
|
|
|
return [MTSignal single:[[TGShareLocationResult alloc] initWithLatitude:latitude longitude:longitude title:name address:address provider:TGShareAppleMapsProvider venueId:venueId venueType:@""]];
|
|
}
|
|
|
|
+ (MTSignal *)_foursquareLocationForURL:(NSURL *)url
|
|
{
|
|
NSArray *pathComponents = url.pathComponents;
|
|
NSString *venueId = nil;
|
|
for (NSString *component in pathComponents)
|
|
{
|
|
if (component.length == 24)
|
|
{
|
|
venueId = component;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (venueId == nil)
|
|
return [MTSignal fail:nil];
|
|
|
|
NSString *urlString = [NSString stringWithFormat:@"%@?%@", [TGShareFoursquareVenueEndpointUrl stringByAppendingPathComponent:venueId], TGQueryStringFromParametersWithEncoding([self _defaultParametersForFoursquare], NSUTF8StringEncoding)];
|
|
|
|
return [[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:urlString]] mapToSignal:^id(NSData *data)
|
|
{
|
|
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
|
|
if (![json respondsToSelector:@selector(objectForKey:)])
|
|
return nil;
|
|
|
|
NSDictionary *venue = json[@"response"][@"venue"];
|
|
if (![venue respondsToSelector:@selector(objectForKey:)])
|
|
return nil;
|
|
|
|
NSString *name = venue[@"name"];
|
|
|
|
NSDictionary *location = venue[@"location"];
|
|
|
|
NSString *address = location[@"address"];
|
|
if (address.length == 0)
|
|
address = location[@"crossStreet"];
|
|
if (address.length == 0)
|
|
address = location[@"city"];
|
|
if (address.length == 0)
|
|
address = location[@"country"];
|
|
if (address.length == 0)
|
|
address = @"";
|
|
|
|
double latitude = [location[@"lat"] doubleValue];
|
|
double longitude = [location[@"lng"] doubleValue];
|
|
|
|
if (name.length == 0)
|
|
return [MTSignal fail:nil];
|
|
|
|
return [MTSignal single:[[TGShareLocationResult alloc] initWithLatitude:latitude longitude:longitude title:name address:address provider:TGShareFoursquareProvider venueId:venueId venueType:@""]];
|
|
}];
|
|
}
|
|
|
|
+ (MTSignal *)_googleMapsLocationForURL:(NSURL *)url
|
|
{
|
|
NSString *shortenerUrl = [NSString stringWithFormat:@"%@?fields=longUrl,status&shortUrl=%@&key=%@", TGShareGoogleShortenerEndpointUrl, TGURLEncodedStringFromStringWithEncoding(url.absoluteString, NSUTF8StringEncoding), TGShareGoogleAPIKey];
|
|
|
|
MTSignal *shortenerSignal = [[MTHttpRequestOperation dataForHttpUrl:[NSURL URLWithString:shortenerUrl]] mapToSignal:^MTSignal *(NSData *data)
|
|
{
|
|
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
if (![json respondsToSelector:@selector(objectForKey:)])
|
|
return [MTSignal fail:nil];
|
|
|
|
NSString *status = json[@"status"];
|
|
if (![status isEqualToString:@"OK"])
|
|
return [MTSignal fail:nil];
|
|
|
|
return [MTSignal single:[NSURL URLWithString:json[@"longUrl"]]];
|
|
}];
|
|
|
|
MTSignal *(^processLongUrl)(NSURL *) = ^MTSignal *(NSURL *longUrl)
|
|
{
|
|
NSArray *pathComponents = longUrl.pathComponents;
|
|
|
|
bool isSearch = false;
|
|
double latitude = 0.0;
|
|
double longitude = 0.0;
|
|
|
|
for (NSString *component in pathComponents)
|
|
{
|
|
if ([component isEqualToString:@"search"])
|
|
{
|
|
isSearch = true;
|
|
}
|
|
else if ([component isEqualToString:@"place"])
|
|
{
|
|
return [MTSignal fail:nil];
|
|
}
|
|
else if (isSearch && [component containsString:@","])
|
|
{
|
|
NSArray *coordinates = [component componentsSeparatedByString:@","];
|
|
if (coordinates.count == 2)
|
|
{
|
|
latitude = [coordinates.firstObject doubleValue];
|
|
longitude = [coordinates.lastObject doubleValue];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fabs(latitude) < DBL_EPSILON && fabs(longitude) < DBL_EPSILON)
|
|
return [MTSignal fail:nil];
|
|
|
|
return [MTSignal single:[[TGShareLocationResult alloc] initWithLatitude:latitude longitude:longitude title:nil address:nil provider:nil venueId:nil venueType:nil]];
|
|
};
|
|
|
|
MTSignal *signal = nil;
|
|
if ([self _isShortGoogleMapsURL:url])
|
|
{
|
|
signal = [shortenerSignal mapToSignal:^MTSignal *(NSURL *longUrl)
|
|
{
|
|
return processLongUrl(longUrl);
|
|
}];
|
|
}
|
|
else
|
|
{
|
|
signal = processLongUrl(url);
|
|
}
|
|
|
|
return [signal catch:^MTSignal *(id error)
|
|
{
|
|
return [MTSignal single:url.absoluteString];
|
|
}];
|
|
}
|
|
|
|
+ (NSDictionary *)_defaultParametersForFoursquare
|
|
{
|
|
return @
|
|
{
|
|
@"v": TGShareFoursquareVersion,
|
|
@"locale": TGShareFoursquareLocale,
|
|
@"client_id": TGShareFoursquareClientId,
|
|
@"client_secret" :TGShareFoursquareClientSecret
|
|
};
|
|
}
|
|
|
|
+ (bool)isLocationURL:(NSURL *)url
|
|
{
|
|
return [self isAppleMapsURL:url] || [self isFoursquareURL:url];
|
|
}
|
|
|
|
+ (bool)isAppleMapsURL:(NSURL *)url
|
|
{
|
|
return ([url.host isEqualToString:TGShareAppleMapsHost] && [url.path isEqualToString:TGShareAppleMapsPath]);
|
|
}
|
|
|
|
+ (bool)isFoursquareURL:(NSURL *)url
|
|
{
|
|
return ([url.host isEqualToString:TGShareFoursquareHost] && [url.path hasPrefix:TGShareFoursquareVenuePath]);
|
|
}
|
|
|
|
+ (bool)_isShortGoogleMapsURL:(NSURL *)url
|
|
{
|
|
return ([url.host isEqualToString:TGShareGoogleMapsShortHost] && [url.path hasPrefix:TGShareGoogleMapsShortPath]);
|
|
}
|
|
|
|
+ (bool)_isLongGoogleMapsURL:(NSURL *)url
|
|
{
|
|
return ([url.host isEqualToString:TGShareGoogleMapsHost] && ([url.path hasPrefix:TGShareGoogleMapsSearchPath] || [url.path hasPrefix:TGShareGoogleMapsPlacePath]));
|
|
}
|
|
|
|
+ (bool)isGoogleMapsURL:(NSURL *)url
|
|
{
|
|
return [self _isShortGoogleMapsURL:url] || [self _isLongGoogleMapsURL:url];
|
|
}
|
|
|
|
@end
|