yeet
This commit is contained in:
6
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactFontManager.h
generated
vendored
Normal file
6
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactFontManager.h
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMCore/UMInternalModule.h>
|
||||
|
||||
@interface UMReactFontManager : NSObject <UMInternalModule>
|
||||
@end
|
104
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactFontManager.m
generated
vendored
Normal file
104
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactFontManager.m
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMReactNativeAdapter/UMReactFontManager.h>
|
||||
#import <UMFontInterface/UMFontProcessorInterface.h>
|
||||
#import <React/RCTFont.h>
|
||||
#import <UMFontInterface/UMFontManagerInterface.h>
|
||||
#import <UMCore/UMAppLifecycleService.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
static dispatch_once_t initializeCurrentFontProcessorsOnce;
|
||||
|
||||
static NSPointerArray *currentFontProcessors;
|
||||
|
||||
@implementation RCTFont (UMReactFontManager)
|
||||
|
||||
+ (UIFont *)UMUpdateFont:(UIFont *)uiFont
|
||||
withFamily:(NSString *)family
|
||||
size:(NSNumber *)size
|
||||
weight:(NSString *)weight
|
||||
style:(NSString *)style
|
||||
variant:(NSArray<NSDictionary *> *)variant
|
||||
scaleMultiplier:(CGFloat)scaleMultiplier
|
||||
{
|
||||
UIFont *font;
|
||||
for (id<UMFontProcessorInterface> fontProcessor in currentFontProcessors) {
|
||||
font = [fontProcessor updateFont:uiFont withFamily:family size:size weight:weight style:style variant:variant scaleMultiplier:scaleMultiplier];
|
||||
if (font) {
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
return [self UMUpdateFont:uiFont withFamily:family size:size weight:weight style:style variant:variant scaleMultiplier:scaleMultiplier];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
* This class is responsible for allowing other modules to register as font processors in React Native.
|
||||
*
|
||||
* A font processor is an object conforming to UMFontProcessorInterface and is capable of
|
||||
* providing an instance of UIFont for given (family, size, weight, style, variant, scaleMultiplier).
|
||||
*
|
||||
* To be able to hook into React Native's way of processing fonts we:
|
||||
* - add a new class method to RCTFont, `UMUpdateFont:withFamily:size:weight:style:variant:scaleMultiplier`
|
||||
* with UMReactFontManager category.
|
||||
* - add a new static variable `currentFontProcessors` holding an array of... font processors. This variable
|
||||
* is shared between the RCTFont's category and UMReactFontManager class.
|
||||
* - when UMReactFontManager is initialized, we exchange implementations of RCTFont.updateFont...
|
||||
* and RCTFont.UMUpdateFont... After the class initialized, which happens only once, calling `RCTFont updateFont`
|
||||
* calls in fact implementation we've defined up here and calling `RCTFont UMUpdateFont` falls back
|
||||
* to the default implementation. (This is why we call `[self UMUpdateFont]` at the end of that function,
|
||||
* though it seems like an endless loop, in fact we dispatch to another implementation.)
|
||||
* - When some module adds a font processor using UMFontManagerInterface, UMReactFontManager adds a weak pointer to it
|
||||
* to currentFontProcessors array.
|
||||
* - Implementation logic of `RCTFont.UMUpdateFont` uses current value of currentFontProcessors when processing arguments.
|
||||
*/
|
||||
|
||||
@interface UMReactFontManager ()
|
||||
|
||||
@property (nonatomic, strong) NSMutableSet *fontProcessors;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UMReactFontManager
|
||||
|
||||
UM_REGISTER_MODULE();
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_fontProcessors = [NSMutableSet set];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (const NSArray<Protocol *> *)exportedInterfaces
|
||||
{
|
||||
return @[@protocol(UMFontManagerInterface)];
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
dispatch_once(&initializeCurrentFontProcessorsOnce, ^{
|
||||
currentFontProcessors = [NSPointerArray weakObjectsPointerArray];
|
||||
});
|
||||
|
||||
Class rtcClass = [RCTFont class];
|
||||
SEL rtcUpdate = @selector(updateFont:withFamily:size:weight:style:variant:scaleMultiplier:);
|
||||
SEL exUpdate = @selector(UMUpdateFont:withFamily:size:weight:style:variant:scaleMultiplier:);
|
||||
|
||||
method_exchangeImplementations(class_getClassMethod(rtcClass, rtcUpdate),
|
||||
class_getClassMethod(rtcClass, exUpdate));
|
||||
}
|
||||
|
||||
# pragma mark - UMFontManager
|
||||
|
||||
- (void)addFontProcessor:(id<UMFontProcessorInterface>)processor
|
||||
{
|
||||
[_fontProcessors addObject:processor];
|
||||
[currentFontProcessors compact];
|
||||
[currentFontProcessors addPointer:(__bridge void * _Nullable)(processor)];
|
||||
}
|
||||
|
||||
@end
|
8
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactLogHandler.h
generated
vendored
Normal file
8
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactLogHandler.h
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMCore/UMSingletonModule.h>
|
||||
#import <UMCore/UMLogHandler.h>
|
||||
|
||||
@interface UMReactLogHandler : UMSingletonModule <UMLogHandler>
|
||||
|
||||
@end
|
27
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactLogHandler.m
generated
vendored
Normal file
27
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactLogHandler.m
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMReactNativeAdapter/UMReactLogHandler.h>
|
||||
#import <UMCore/UMDefines.h>
|
||||
#import <React/RCTLog.h>
|
||||
|
||||
@implementation UMReactLogHandler
|
||||
|
||||
UM_REGISTER_SINGLETON_MODULE(ReactLogHandler);
|
||||
|
||||
- (void)error:(NSString *)message {
|
||||
RCTLogError(@"%@", message);
|
||||
}
|
||||
|
||||
- (void)fatal:(NSError *)error {
|
||||
RCTFatal(error);
|
||||
}
|
||||
|
||||
- (void)info:(NSString *)message {
|
||||
RCTLogInfo(@"%@", message);
|
||||
}
|
||||
|
||||
- (void)warn:(NSString *)message {
|
||||
RCTLogWarn(@"%@", message);
|
||||
}
|
||||
|
||||
@end
|
13
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeAdapter.h
generated
vendored
Normal file
13
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeAdapter.h
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMCore/UMUIManager.h>
|
||||
#import <UMCore/UMInternalModule.h>
|
||||
#import <UMCore/UMAppLifecycleService.h>
|
||||
#import <UMCore/UMAppLifecycleListener.h>
|
||||
#import <UMCore/UMModuleRegistryConsumer.h>
|
||||
#import <UMCore/UMJavaScriptContextProvider.h>
|
||||
#import <UMReactNativeAdapter/UMBridgeModule.h>
|
||||
|
||||
@interface UMReactNativeAdapter : NSObject <UMInternalModule, UMBridgeModule, UMAppLifecycleService, UMUIManager, UMJavaScriptContextProvider, UMModuleRegistryConsumer>
|
||||
|
||||
@end
|
302
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeAdapter.m
generated
vendored
Normal file
302
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeAdapter.m
generated
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import <UMReactNativeAdapter/UMReactNativeAdapter.h>
|
||||
#import <React/RCTUIManager.h>
|
||||
#import <React/RCTBridge+Private.h>
|
||||
#import <React/RCTAppState.h>
|
||||
#import <React/RCTImageLoader.h>
|
||||
|
||||
@interface UMReactNativeAdapter ()
|
||||
|
||||
@property (nonatomic, weak) RCTBridge *bridge;
|
||||
@property (nonatomic, assign) BOOL isForegrounded;
|
||||
@property (nonatomic, strong) NSPointerArray *lifecycleListeners;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTBridge ()
|
||||
|
||||
- (JSGlobalContextRef)jsContextRef;
|
||||
- (void *)runtime;
|
||||
- (void)dispatchBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UMReactNativeAdapter
|
||||
|
||||
UM_REGISTER_MODULE();
|
||||
|
||||
+ (NSString *)moduleName
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
+ (const NSArray<Protocol *> *)exportedInterfaces
|
||||
{
|
||||
return @[@protocol(UMAppLifecycleService), @protocol(UMUIManager), @protocol(UMJavaScriptContextProvider)];
|
||||
}
|
||||
|
||||
# pragma mark - Lifecycle methods
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_isForegrounded = false;
|
||||
_lifecycleListeners = [NSPointerArray weakObjectsPointerArray];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
|
||||
{
|
||||
if (moduleRegistry) {
|
||||
[self startObserving];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self stopObserving];
|
||||
}
|
||||
|
||||
# pragma mark - Public API
|
||||
|
||||
- (void)addUIBlock:(void (^)(NSDictionary<id, UIView *> *))block
|
||||
{
|
||||
__weak UMReactNativeAdapter *weakSelf = self;
|
||||
dispatch_async(_bridge.uiManager.methodQueue, ^{
|
||||
__strong UMReactNativeAdapter *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
block(viewRegistry);
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)addUIBlock:(void (^)(id))block forView:(id)viewId ofClass:(Class)klass
|
||||
{
|
||||
[self addUIBlock:^(UIView *view) {
|
||||
if (![view isKindOfClass:klass]) {
|
||||
block(nil);
|
||||
} else {
|
||||
block(view);
|
||||
}
|
||||
} forView:viewId];
|
||||
}
|
||||
|
||||
- (void)addUIBlock:(void (^)(id))block forView:(id)viewId implementingProtocol:(Protocol *)protocol
|
||||
{
|
||||
[self addUIBlock:^(UIView *view) {
|
||||
if (![view.class conformsToProtocol:protocol]) {
|
||||
block(nil);
|
||||
} else {
|
||||
block(view);
|
||||
}
|
||||
} forView:viewId];
|
||||
}
|
||||
|
||||
- (void)dispatchOnClientThread:(dispatch_block_t)block
|
||||
{
|
||||
[self.bridge dispatchBlock:block queue:RCTJSThread];
|
||||
}
|
||||
|
||||
- (void)executeUIBlock:(void (^)(NSDictionary<id,UIView *> *))block {
|
||||
__weak UMReactNativeAdapter *weakSelf = self;
|
||||
dispatch_async(_bridge.uiManager.methodQueue, ^{
|
||||
__strong UMReactNativeAdapter *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
block(viewRegistry);
|
||||
}];
|
||||
[strongSelf.bridge.uiManager setNeedsLayout];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
- (void)executeUIBlock:(void (^)(id))block forView:(id)viewId implementingProtocol:(Protocol *)protocol {
|
||||
[self executeUIBlock:^(UIView *view) {
|
||||
if (![view.class conformsToProtocol:protocol]) {
|
||||
block(nil);
|
||||
} else {
|
||||
block(view);
|
||||
}
|
||||
} forView:viewId];
|
||||
}
|
||||
|
||||
|
||||
- (void)executeUIBlock:(void (^)(id))block forView:(id)viewId ofClass:(Class)klass {
|
||||
[self executeUIBlock:^(UIView *view) {
|
||||
if (![view isKindOfClass:klass]) {
|
||||
block(nil);
|
||||
} else {
|
||||
block(view);
|
||||
}
|
||||
} forView:viewId];
|
||||
}
|
||||
|
||||
|
||||
- (void)setBridge:(RCTBridge *)bridge
|
||||
{
|
||||
_bridge = bridge;
|
||||
}
|
||||
|
||||
- (void)registerAppLifecycleListener:(id<UMAppLifecycleListener>)listener
|
||||
{
|
||||
[_lifecycleListeners addPointer:(__bridge void * _Nullable)(listener)];
|
||||
}
|
||||
|
||||
- (void)unregisterAppLifecycleListener:(id<UMAppLifecycleListener>)listener
|
||||
{
|
||||
for (int i = 0; i < _lifecycleListeners.count; i++) {
|
||||
id pointer = [_lifecycleListeners pointerAtIndex:i];
|
||||
if (pointer == (__bridge void * _Nullable)(listener) || !pointer) {
|
||||
[_lifecycleListeners removePointerAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
// -(void)compact doesn't work, that's why we have this `|| !pointer` above
|
||||
// http://www.openradar.me/15396578
|
||||
[_lifecycleListeners compact];
|
||||
}
|
||||
|
||||
# pragma mark - UMJavaScriptContextProvider
|
||||
|
||||
- (JSGlobalContextRef)javaScriptContextRef
|
||||
{
|
||||
if ([_bridge respondsToSelector:@selector(jsContextRef)]) {
|
||||
return _bridge.jsContextRef;
|
||||
} else if (_bridge.runtime) {
|
||||
// In react-native 0.59 vm is abstracted by JSI and all JSC specific references are removed
|
||||
// To access jsc context we are extracting specific offset in jsi::Runtime, JSGlobalContextRef
|
||||
// is first field inside Runtime class and in memory it's preceded only by pointer to virtual method table.
|
||||
// WARNING: This is temporary solution that may break with new react-native releases.
|
||||
return *(((JSGlobalContextRef *)(_bridge.runtime)) + 1);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void *)javaScriptRuntimePointer
|
||||
{
|
||||
if ([_bridge respondsToSelector:@selector(runtime)]) {
|
||||
return _bridge.runtime;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark - App state observing
|
||||
|
||||
- (void)startObserving
|
||||
{
|
||||
for (NSString *name in @[UIApplicationDidBecomeActiveNotification,
|
||||
UIApplicationDidEnterBackgroundNotification,
|
||||
UIApplicationDidFinishLaunchingNotification,
|
||||
UIApplicationWillResignActiveNotification,
|
||||
UIApplicationWillEnterForegroundNotification,
|
||||
RCTContentDidAppearNotification,
|
||||
RCTBridgeWillReloadNotification]) {
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(handleAppStateDidChange:)
|
||||
name:name
|
||||
object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleAppStateDidChange:(NSNotification *)notification
|
||||
{
|
||||
if ([notification.name isEqualToString:RCTContentDidAppearNotification]) {
|
||||
[self notifyAboutContentDidAppear];
|
||||
} else if ([notification.name isEqualToString:RCTBridgeWillReloadNotification]) {
|
||||
[self notifyAboutContentWillReload];
|
||||
} else if (
|
||||
_isForegrounded && (
|
||||
[notification.name isEqualToString:UIApplicationWillResignActiveNotification] ||
|
||||
[notification.name isEqualToString:UIApplicationWillEnterForegroundNotification] ||
|
||||
RCTSharedApplication().applicationState == UIApplicationStateBackground
|
||||
)
|
||||
) {
|
||||
[self setAppStateToBackground];
|
||||
} else if (!_isForegrounded && RCTSharedApplication().applicationState == UIApplicationStateActive) {
|
||||
[self setAppStateToForeground];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAppStateToBackground
|
||||
{
|
||||
if (_isForegrounded) {
|
||||
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj onAppBackgrounded];
|
||||
}];
|
||||
_isForegrounded = false;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAppStateToForeground
|
||||
{
|
||||
if (!_isForegrounded) {
|
||||
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[obj onAppForegrounded];
|
||||
}];
|
||||
_isForegrounded = true;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyAboutContentDidAppear
|
||||
{
|
||||
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj respondsToSelector:@selector(onAppContentDidAppear)]) {
|
||||
[obj performSelector:@selector(onAppContentDidAppear)];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)notifyAboutContentWillReload
|
||||
{
|
||||
[[_lifecycleListeners allObjects] enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
if ([obj respondsToSelector:@selector(onAppContentWillReload)]) {
|
||||
[obj performSelector:@selector(onAppContentWillReload)];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopObserving
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
# pragma mark - Internal methods
|
||||
|
||||
- (void)addUIBlock:(void (^)(UIView *view))block forView:(id)viewId
|
||||
{
|
||||
__weak UMReactNativeAdapter *weakSelf = self;
|
||||
dispatch_async(_bridge.uiManager.methodQueue, ^{
|
||||
__strong UMReactNativeAdapter *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
UIView *view = viewRegistry[viewId];
|
||||
block(view);
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)executeUIBlock:(void (^)(UIView *view))block forView:(id)viewId
|
||||
{
|
||||
__weak UMReactNativeAdapter *weakSelf = self;
|
||||
dispatch_async(_bridge.uiManager.methodQueue, ^{
|
||||
__strong UMReactNativeAdapter *strongSelf = weakSelf;
|
||||
if (strongSelf) {
|
||||
[strongSelf.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
UIView *view = viewRegistry[viewId];
|
||||
block(view);
|
||||
}];
|
||||
[strongSelf.bridge.uiManager setNeedsLayout];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
11
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.h
generated
vendored
Normal file
11
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.h
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMCore/UMInternalModule.h>
|
||||
#import <UMCore/UMEventEmitterService.h>
|
||||
#import <UMCore/UMModuleRegistryConsumer.h>
|
||||
#import <UMReactNativeAdapter/UMBridgeModule.h>
|
||||
#import <React/RCTEventEmitter.h>
|
||||
|
||||
@interface UMReactNativeEventEmitter : RCTEventEmitter <UMInternalModule, UMBridgeModule, UMModuleRegistryConsumer, UMEventEmitterService>
|
||||
|
||||
@end
|
145
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m
generated
vendored
Normal file
145
node_modules/@unimodules/react-native-adapter/ios/UMReactNativeAdapter/Services/UMReactNativeEventEmitter.m
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <UMReactNativeAdapter/UMReactNativeEventEmitter.h>
|
||||
#import <UMCore/UMEventEmitter.h>
|
||||
#import <UMCore/UMExportedModule.h>
|
||||
#import <UMCore/UMModuleRegistry.h>
|
||||
|
||||
@interface UMReactNativeEventEmitter ()
|
||||
|
||||
@property (nonatomic, assign) int listenersCount;
|
||||
@property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *modulesListenersCounts;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UMReactNativeEventEmitter
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_listenersCount = 0;
|
||||
_modulesListenersCounts = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
UM_REGISTER_MODULE();
|
||||
|
||||
+ (NSString *)moduleName
|
||||
{
|
||||
return @"UMReactNativeEventEmitter";
|
||||
}
|
||||
|
||||
+ (const NSArray<Protocol *> *)exportedInterfaces
|
||||
{
|
||||
return @[@protocol(UMEventEmitterService)];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents
|
||||
{
|
||||
NSMutableSet<NSString *> *eventsAccumulator = [NSMutableSet set];
|
||||
for (UMExportedModule *exportedModule in [_moduleRegistry getAllExportedModules]) {
|
||||
if ([exportedModule conformsToProtocol:@protocol(UMEventEmitter)]) {
|
||||
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)exportedModule;
|
||||
[eventsAccumulator addObjectsFromArray:[eventEmitter supportedEvents]];
|
||||
}
|
||||
}
|
||||
return [eventsAccumulator allObjects];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(addProxiedListener:(NSString *)moduleName eventName:(NSString *)eventName)
|
||||
{
|
||||
[self addListener:eventName];
|
||||
// Validate module
|
||||
UMExportedModule *module = [_moduleRegistry getExportedModuleForName:moduleName];
|
||||
|
||||
if (RCT_DEBUG && module == nil) {
|
||||
UMLogError(@"Module for name `%@` has not been found.", moduleName);
|
||||
return;
|
||||
} else if (RCT_DEBUG && ![module conformsToProtocol:@protocol(UMEventEmitter)]) {
|
||||
UMLogError(@"Module `%@` is not an UMEventEmitter, thus it cannot be subscribed to.", moduleName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate eventEmitter
|
||||
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)module;
|
||||
|
||||
if (RCT_DEBUG && ![[eventEmitter supportedEvents] containsObject:eventName]) {
|
||||
UMLogError(@"`%@` is not a supported event type for %@. Supported events are: `%@`",
|
||||
eventName, moduleName, [[eventEmitter supportedEvents] componentsJoinedByString:@"`, `"]);
|
||||
}
|
||||
|
||||
// Global observing state
|
||||
_listenersCount += 1;
|
||||
if (_listenersCount == 1) {
|
||||
[self startObserving];
|
||||
}
|
||||
|
||||
// Per-module observing state
|
||||
int newModuleListenersCount = [self moduleListenersCountFor:moduleName] + 1;
|
||||
if (newModuleListenersCount == 1) {
|
||||
[eventEmitter startObserving];
|
||||
}
|
||||
_modulesListenersCounts[moduleName] = [NSNumber numberWithInt:newModuleListenersCount];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(removeProxiedListeners:(NSString *)moduleName count:(double)count)
|
||||
{
|
||||
[self removeListeners:count];
|
||||
// Validate module
|
||||
UMExportedModule *module = [_moduleRegistry getExportedModuleForName:moduleName];
|
||||
|
||||
if (RCT_DEBUG && module == nil) {
|
||||
UMLogError(@"Module for name `%@` has not been found.", moduleName);
|
||||
return;
|
||||
} else if (RCT_DEBUG && ![module conformsToProtocol:@protocol(UMEventEmitter)]) {
|
||||
UMLogError(@"Module `%@` is not an UMEventEmitter, thus it cannot be subscribed to.", moduleName);
|
||||
return;
|
||||
}
|
||||
|
||||
id<UMEventEmitter> eventEmitter = (id<UMEventEmitter>)module;
|
||||
|
||||
// Per-module observing state
|
||||
int newModuleListenersCount = [self moduleListenersCountFor:moduleName] - count;
|
||||
if (newModuleListenersCount == 0) {
|
||||
[eventEmitter stopObserving];
|
||||
} else if (newModuleListenersCount < 0) {
|
||||
UMLogError(@"Attempted to remove more `%@` listeners than added", moduleName);
|
||||
newModuleListenersCount = 0;
|
||||
}
|
||||
_modulesListenersCounts[moduleName] = [NSNumber numberWithInt:newModuleListenersCount];
|
||||
|
||||
// Global observing state
|
||||
if (_listenersCount - count < 0) {
|
||||
UMLogError(@"Attempted to remove more proxied event emitter listeners than added");
|
||||
_listenersCount = 0;
|
||||
} else {
|
||||
_listenersCount -= count;
|
||||
}
|
||||
|
||||
if (_listenersCount == 0) {
|
||||
[self stopObserving];
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark Utilities
|
||||
|
||||
- (int)moduleListenersCountFor:(NSString *)moduleName
|
||||
{
|
||||
NSNumber *moduleListenersCountNumber = _modulesListenersCounts[moduleName];
|
||||
int moduleListenersCount = 0;
|
||||
if (moduleListenersCountNumber != nil) {
|
||||
moduleListenersCount = [moduleListenersCountNumber intValue];
|
||||
}
|
||||
return moduleListenersCount;
|
||||
}
|
||||
|
||||
# pragma mark - UMModuleRegistryConsumer
|
||||
|
||||
- (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
|
||||
{
|
||||
_moduleRegistry = moduleRegistry;
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user