1b987b50fSBen Roth// Copyright 2015-present 650 Industries. All rights reserved. 2b987b50fSBen Roth 39a7f140aSEric Samelson#import "EXEnvironment.h" 4b987b50fSBen Roth#import "EXHomeModule.h" 5*8a20a963SEric Samelson#import "EXSession.h" 6b987b50fSBen Roth#import "EXUnversioned.h" 7b987b50fSBen Roth 8b987b50fSBen Roth#import <React/RCTEventDispatcher.h> 9b987b50fSBen Roth 10b987b50fSBen Roth@interface EXHomeModule () 11b987b50fSBen Roth 12b987b50fSBen Roth@property (nonatomic, assign) BOOL hasListeners; 13b987b50fSBen Roth@property (nonatomic, strong) NSMutableDictionary *eventSuccessBlocks; 14b987b50fSBen Roth@property (nonatomic, strong) NSMutableDictionary *eventFailureBlocks; 15b987b50fSBen Roth@property (nonatomic, strong) NSArray * _Nonnull sdkVersions; 16b987b50fSBen Roth@property (nonatomic, weak) id<EXHomeModuleDelegate> delegate; 17b987b50fSBen Roth 18b987b50fSBen Roth@end 19b987b50fSBen Roth 20b987b50fSBen Roth@implementation EXHomeModule 21b987b50fSBen Roth 22b987b50fSBen Roth+ (NSString *)moduleName { return @"ExponentKernel"; } 23b987b50fSBen Roth 24b987b50fSBen Roth- (instancetype)initWithExperienceId:(NSString *)experienceId kernelServiceDelegate:(id)kernelServiceInstance params:(NSDictionary *)params 25b987b50fSBen Roth{ 26b987b50fSBen Roth if (self = [super initWithExperienceId:experienceId kernelServiceDelegate:kernelServiceInstance params:params]) { 27b987b50fSBen Roth _eventSuccessBlocks = [NSMutableDictionary dictionary]; 28b987b50fSBen Roth _eventFailureBlocks = [NSMutableDictionary dictionary]; 29b987b50fSBen Roth _sdkVersions = params[@"supportedSdkVersions"]; 30b987b50fSBen Roth _delegate = kernelServiceInstance; 31b987b50fSBen Roth } 32b987b50fSBen Roth return self; 33b987b50fSBen Roth} 34b987b50fSBen Roth 35b987b50fSBen Roth+ (BOOL)requiresMainQueueSetup 36b987b50fSBen Roth{ 37b987b50fSBen Roth return NO; 38b987b50fSBen Roth} 39b987b50fSBen Roth 40b987b50fSBen Roth- (NSDictionary *)constantsToExport 41b987b50fSBen Roth{ 42b987b50fSBen Roth return @{ @"sdkVersions": _sdkVersions }; 43b987b50fSBen Roth} 44b987b50fSBen Roth 45b987b50fSBen Roth#pragma mark - RCTEventEmitter methods 46b987b50fSBen Roth 47b987b50fSBen Roth- (NSArray<NSString *> *)supportedEvents 48b987b50fSBen Roth{ 49b987b50fSBen Roth return @[]; 50b987b50fSBen Roth} 51b987b50fSBen Roth 52b987b50fSBen Roth/** 53b987b50fSBen Roth * Override this method to avoid the [self supportedEvents] validation 54b987b50fSBen Roth */ 55b987b50fSBen Roth- (void)sendEventWithName:(NSString *)eventName body:(id)body 56b987b50fSBen Roth{ 57b987b50fSBen Roth // Note that this could be a versioned bridge! 58b987b50fSBen Roth [self.bridge enqueueJSCall:@"RCTDeviceEventEmitter.emit" 59b987b50fSBen Roth args:body ? @[eventName, body] : @[eventName]]; 60b987b50fSBen Roth} 61b987b50fSBen Roth 62b987b50fSBen Roth#pragma mark - 63b987b50fSBen Roth 64b987b50fSBen Roth- (void)dispatchJSEvent:(NSString *)eventName body:(NSDictionary *)eventBody onSuccess:(void (^)(NSDictionary *))success onFailure:(void (^)(NSString *))failure 65b987b50fSBen Roth{ 66b987b50fSBen Roth NSString *qualifiedEventName = [NSString stringWithFormat:@"ExponentKernel.%@", eventName]; 67b987b50fSBen Roth NSMutableDictionary *qualifiedEventBody = (eventBody) ? [eventBody mutableCopy] : [NSMutableDictionary dictionary]; 68b987b50fSBen Roth 69b987b50fSBen Roth if (success && failure) { 70b987b50fSBen Roth NSString *eventId = [[NSUUID UUID] UUIDString]; 71b987b50fSBen Roth [_eventSuccessBlocks setObject:success forKey:eventId]; 72b987b50fSBen Roth [_eventFailureBlocks setObject:failure forKey:eventId]; 73b987b50fSBen Roth [qualifiedEventBody setObject:eventId forKey:@"eventId"]; 74b987b50fSBen Roth } 75b987b50fSBen Roth 76b987b50fSBen Roth [self sendEventWithName:qualifiedEventName body:qualifiedEventBody]; 77b987b50fSBen Roth} 78b987b50fSBen Roth 79b987b50fSBen Roth/** 80b987b50fSBen Roth * Duplicates Linking.openURL but does not validate that this is an exponent URL; 81b987b50fSBen Roth * in other words, we just take your word for it and never hand it off to iOS. 82b987b50fSBen Roth * Used by the home screen URL bar. 83b987b50fSBen Roth */ 84b987b50fSBen RothRCT_EXPORT_METHOD(openURL:(NSURL *)URL 85b987b50fSBen Roth resolve:(RCTPromiseResolveBlock)resolve 86b987b50fSBen Roth reject:(__unused RCTPromiseRejectBlock)reject) 87b987b50fSBen Roth{ 88b987b50fSBen Roth if (URL) { 89b987b50fSBen Roth [_delegate homeModule:self didOpenUrl:URL.absoluteString]; 90b987b50fSBen Roth resolve(@YES); 91b987b50fSBen Roth } else { 92b987b50fSBen Roth NSError *err = [NSError errorWithDomain:EX_UNVERSIONED(@"EXKernelErrorDomain") code:-1 userInfo:@{ NSLocalizedDescriptionKey: @"Cannot open a nil url" }]; 93b987b50fSBen Roth reject(@"E_INVALID_URL", err.localizedDescription, err); 94b987b50fSBen Roth } 95b987b50fSBen Roth} 96b987b50fSBen Roth 97b987b50fSBen RothRCT_REMAP_METHOD(doesCurrentTaskEnableDevtools, 98b987b50fSBen Roth doesCurrentTaskEnableDevtoolsWithResolver:(RCTPromiseResolveBlock)resolve 99b987b50fSBen Roth reject:(RCTPromiseRejectBlock)reject) 100b987b50fSBen Roth{ 101b987b50fSBen Roth if (_delegate) { 102b987b50fSBen Roth resolve(@([_delegate homeModuleShouldEnableDevtools:self])); 103b987b50fSBen Roth } else { 104b987b50fSBen Roth // don't reject, just disable devtools 105b987b50fSBen Roth resolve(@NO); 106b987b50fSBen Roth } 107b987b50fSBen Roth} 108b987b50fSBen Roth 109b987b50fSBen RothRCT_REMAP_METHOD(isLegacyMenuBehaviorEnabledAsync, 110b987b50fSBen Roth isLegacyMenuBehaviorEnabledWithResolver:(RCTPromiseResolveBlock)resolve 111b987b50fSBen Roth rejecter:(RCTPromiseRejectBlock)reject) 112b987b50fSBen Roth{ 113b987b50fSBen Roth if (_delegate) { 114b987b50fSBen Roth resolve(@([_delegate homeModuleShouldEnableLegacyMenuBehavior:self])); 115b987b50fSBen Roth } else { 116b987b50fSBen Roth resolve(@(NO)); 117b987b50fSBen Roth } 118b987b50fSBen Roth} 119b987b50fSBen Roth 120b987b50fSBen RothRCT_EXPORT_METHOD(setIsLegacyMenuBehaviorEnabledAsync:(BOOL)isEnabled) 121b987b50fSBen Roth{ 122b987b50fSBen Roth if (_delegate) { 123b987b50fSBen Roth [_delegate homeModule:self didSelectEnableLegacyMenuBehavior:isEnabled]; 124b987b50fSBen Roth } 125b987b50fSBen Roth} 126b987b50fSBen Roth 127b987b50fSBen RothRCT_REMAP_METHOD(getDevMenuItemsToShow, 128b987b50fSBen Roth getDevMenuItemsToShowWithResolver:(RCTPromiseResolveBlock)resolve 129b987b50fSBen Roth reject:(RCTPromiseRejectBlock)reject) 130b987b50fSBen Roth{ 131b987b50fSBen Roth if (_delegate && [_delegate homeModuleShouldEnableDevtools:self]) { 132b987b50fSBen Roth resolve([_delegate devMenuItemsForHomeModule:self]); 133b987b50fSBen Roth } else { 134b987b50fSBen Roth // don't reject, just show no devtools 135b987b50fSBen Roth resolve(@{}); 136b987b50fSBen Roth } 137b987b50fSBen Roth} 138b987b50fSBen Roth 139b987b50fSBen RothRCT_EXPORT_METHOD(selectDevMenuItemWithKey:(NSString *)key) 140b987b50fSBen Roth{ 141b987b50fSBen Roth if (_delegate) { 142b987b50fSBen Roth [_delegate homeModule:self didSelectDevMenuItemWithKey:key]; 143b987b50fSBen Roth } 144b987b50fSBen Roth} 145b987b50fSBen Roth 146b987b50fSBen RothRCT_EXPORT_METHOD(selectRefresh) 147b987b50fSBen Roth{ 148b987b50fSBen Roth if (_delegate) { 149b987b50fSBen Roth [_delegate homeModuleDidSelectRefresh:self]; 150b987b50fSBen Roth } 151b987b50fSBen Roth} 152b987b50fSBen Roth 153b987b50fSBen RothRCT_EXPORT_METHOD(selectCloseMenu) 154b987b50fSBen Roth{ 155b987b50fSBen Roth if (_delegate) { 156b987b50fSBen Roth [_delegate homeModuleDidSelectCloseMenu:self]; 157b987b50fSBen Roth } 158b987b50fSBen Roth} 159b987b50fSBen Roth 160b987b50fSBen RothRCT_EXPORT_METHOD(selectGoToHome) 161b987b50fSBen Roth{ 162b987b50fSBen Roth if (_delegate) { 163b987b50fSBen Roth [_delegate homeModuleDidSelectGoToHome:self]; 164b987b50fSBen Roth } 165b987b50fSBen Roth} 166b987b50fSBen Roth 1672fcba380SBen RothRCT_EXPORT_METHOD(selectQRReader) 1682fcba380SBen Roth{ 1692fcba380SBen Roth if (_delegate) { 1702fcba380SBen Roth [_delegate homeModuleDidSelectQRReader:self]; 1712fcba380SBen Roth } 1722fcba380SBen Roth} 1732fcba380SBen Roth 174*8a20a963SEric SamelsonRCT_REMAP_METHOD(getSessionAsync, 175*8a20a963SEric Samelson getSessionAsync:(RCTPromiseResolveBlock)resolve 176*8a20a963SEric Samelson rejecter:(RCTPromiseRejectBlock)reject) 1779a7f140aSEric Samelson{ 178*8a20a963SEric Samelson NSDictionary *session = [[EXSession sharedInstance] session]; 179*8a20a963SEric Samelson resolve(session); 1809a7f140aSEric Samelson} 1819a7f140aSEric Samelson 182*8a20a963SEric SamelsonRCT_REMAP_METHOD(setSessionAsync, 183*8a20a963SEric Samelson setSessionAsync:(NSDictionary *)session 184*8a20a963SEric Samelson resolver:(RCTPromiseResolveBlock)resolve 185*8a20a963SEric Samelson rejecter:(RCTPromiseRejectBlock)reject) 1869a7f140aSEric Samelson{ 187*8a20a963SEric Samelson NSError *error; 188*8a20a963SEric Samelson BOOL success = [[EXSession sharedInstance] saveSessionToKeychain:session error:&error]; 189*8a20a963SEric Samelson if (success) { 190*8a20a963SEric Samelson resolve(nil); 191*8a20a963SEric Samelson } else { 192*8a20a963SEric Samelson reject(@"ERR_SESSION_NOT_SAVED", @"Could not save session", error); 193*8a20a963SEric Samelson } 194*8a20a963SEric Samelson} 195*8a20a963SEric Samelson 196*8a20a963SEric SamelsonRCT_REMAP_METHOD(removeSessionAsync, 197*8a20a963SEric Samelson removeSessionAsync:(RCTPromiseResolveBlock)resolve 198*8a20a963SEric Samelson rejecter:(RCTPromiseRejectBlock)reject) 199*8a20a963SEric Samelson{ 200*8a20a963SEric Samelson NSError *error; 201*8a20a963SEric Samelson BOOL success = [[EXSession sharedInstance] deleteSessionFromKeychainWithError:&error]; 202*8a20a963SEric Samelson if (success) { 203*8a20a963SEric Samelson resolve(nil); 204*8a20a963SEric Samelson } else { 205*8a20a963SEric Samelson reject(@"ERR_SESSION_NOT_REMOVED", @"Could not remove session", error); 206*8a20a963SEric Samelson } 2079a7f140aSEric Samelson} 2089a7f140aSEric Samelson 209b987b50fSBen RothRCT_EXPORT_METHOD(addDevMenu) 210b987b50fSBen Roth{ 211b987b50fSBen Roth __weak typeof(self) weakSelf = self; 212b987b50fSBen Roth dispatch_async(dispatch_get_main_queue(), ^{ 213b987b50fSBen Roth if (weakSelf.delegate) { 214b987b50fSBen Roth [weakSelf.delegate homeModuleDidSelectHomeDiagnostics:self]; 215b987b50fSBen Roth } 216b987b50fSBen Roth }); 217b987b50fSBen Roth} 218b987b50fSBen Roth 21966169681SBen RothRCT_REMAP_METHOD(getIsNuxFinishedAsync, 22066169681SBen Roth getIsNuxFinishedWithResolver:(RCTPromiseResolveBlock)resolve 22166169681SBen Roth rejecter:(RCTPromiseRejectBlock)reject) 222b987b50fSBen Roth{ 22366169681SBen Roth if (_delegate) { 22466169681SBen Roth BOOL isFinished = [_delegate homeModuleShouldFinishNux:self]; 22566169681SBen Roth resolve(@(isFinished)); 22666169681SBen Roth } else { 22766169681SBen Roth resolve(@(NO)); 22866169681SBen Roth } 22966169681SBen Roth} 23066169681SBen Roth 23166169681SBen RothRCT_REMAP_METHOD(setIsNuxFinishedAsync, 23266169681SBen Roth setIsNuxFinished:(BOOL)isNuxFinished) 23366169681SBen Roth{ 23466169681SBen Roth if (_delegate) { 23566169681SBen Roth [_delegate homeModule:self didFinishNux:isNuxFinished]; 23666169681SBen Roth } 237b987b50fSBen Roth} 238b987b50fSBen Roth 239b987b50fSBen RothRCT_REMAP_METHOD(onEventSuccess, 240b987b50fSBen Roth eventId:(NSString *)eventId 241b987b50fSBen Roth body:(NSDictionary *)body) 242b987b50fSBen Roth{ 243b987b50fSBen Roth void (^success)(NSDictionary *) = [_eventSuccessBlocks objectForKey:eventId]; 244b987b50fSBen Roth if (success) { 245b987b50fSBen Roth success(body); 246b987b50fSBen Roth [_eventSuccessBlocks removeObjectForKey:eventId]; 247b987b50fSBen Roth [_eventFailureBlocks removeObjectForKey:eventId]; 248b987b50fSBen Roth } 249b987b50fSBen Roth} 250b987b50fSBen Roth 251b987b50fSBen RothRCT_REMAP_METHOD(onEventFailure, 252b987b50fSBen Roth eventId:(NSString *)eventId 253b987b50fSBen Roth message:(NSString *)message) 254b987b50fSBen Roth{ 255b987b50fSBen Roth void (^failure)(NSString *) = [_eventFailureBlocks objectForKey:eventId]; 256b987b50fSBen Roth if (failure) { 257b987b50fSBen Roth failure(message); 258b987b50fSBen Roth [_eventSuccessBlocks removeObjectForKey:eventId]; 259b987b50fSBen Roth [_eventFailureBlocks removeObjectForKey:eventId]; 260b987b50fSBen Roth } 261b987b50fSBen Roth} 262b987b50fSBen Roth 263b987b50fSBen Roth@end 264