1// Copyright 2015-present 650 Industries. All rights reserved. 2 3#import <React/RCTUtils.h> 4 5#import "EXDevMenuGestureInterceptor.h" 6#import "EXDevMenuGestureRecognizer.h" 7 8@import UIKit; 9 10static BOOL isInstalled = NO; 11static EXDevMenuGestureRecognizer *gestureRecognizerInstance; 12 13@implementation UIWindow (EXDevMenuGestureInterceptor) 14 15- (NSArray<__kindof UIGestureRecognizer *> *)EX_gestureRecognizers 16{ 17 // Just for thread safety, someone may uninstall the interceptor in the meantime and we would fall into recursive loop. 18 if (!isInstalled) { 19 return [self gestureRecognizers]; 20 } 21 22 // Check for the case where singleton instance of gesture recognizer is not created yet or is attached to different window. 23 if (!gestureRecognizerInstance || gestureRecognizerInstance.view != self) { 24 // Create gesture recognizer if not created yet. 25 static dispatch_once_t onceToken; 26 dispatch_once(&onceToken, ^{ 27 gestureRecognizerInstance = [EXDevMenuGestureRecognizer new]; 28 }); 29 30 // Remove it from the window it's attached to. 31 [gestureRecognizerInstance.view removeGestureRecognizer:gestureRecognizerInstance]; 32 33 // Attach to this window. 34 [self addGestureRecognizer:gestureRecognizerInstance]; 35 } 36 37 // `EX_gestureRecognizers` implementation has been swapped with `gestureRecognizers` - it might be confusing that we call it recursively, but we don't. 38 return [self EX_gestureRecognizers]; 39} 40 41@end 42 43@implementation EXDevMenuGestureInterceptor 44 45+ (void)install 46{ 47 if (!isInstalled) { 48 // Capture touch gesture from any window by swapping default implementation from UIWindow. 49 RCTSwapInstanceMethods([UIWindow class], @selector(gestureRecognizers), @selector(EX_gestureRecognizers)); 50 isInstalled = YES; 51 52 // Make sure gesture recognizer is enabled. 53 [gestureRecognizerInstance setEnabled:YES]; 54 } 55} 56 57+ (void)uninstall 58{ 59 if (isInstalled) { 60 // Bring back the original method. 61 RCTSwapInstanceMethods([UIWindow class], @selector(gestureRecognizers), @selector(EX_gestureRecognizers)); 62 isInstalled = NO; 63 64 // Cancel recognized gestures and disable it entirely. 65 [gestureRecognizerInstance setEnabled:NO]; 66 } 67} 68 69+ (BOOL)isInstalled 70{ 71 return isInstalled; 72} 73 74@end 75