Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: coalesced event #592

Merged
merged 12 commits into from
Feb 27, 2025
12 changes: 12 additions & 0 deletions ios/RNCOnInsetsChangeEvent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
#import <React/RCTEventDispatcherProtocol.h>

@interface RNCOnInsetsChangeEvent : NSObject <RCTEvent>

- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
insets:(UIEdgeInsets)insets
frame:(CGRect)frame
coalescingKey:(uint16_t)coalescingKey NS_DESIGNATED_INITIALIZER;

@end
79 changes: 79 additions & 0 deletions ios/RNCOnInsetsChangeEvent.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#import "RNCOnInsetsChangeEvent.h"
#import <React/RCTAssert.h>

@implementation RNCOnInsetsChangeEvent {
UIEdgeInsets _insets;
CGRect _frame;
uint16_t _coalescingKey;
}

@synthesize eventName = _eventName;
@synthesize viewTag = _viewTag;

- (instancetype)initWithEventName:(NSString *)eventName
reactTag:(NSNumber *)reactTag
insets:(UIEdgeInsets)insets
frame:(CGRect)frame
coalescingKey:(uint16_t)coalescingKey
{
RCTAssertParam(reactTag);

if ((self = [super init])) {
_eventName = [eventName copy];
_viewTag = reactTag;
_frame = frame;
_insets = insets;
_coalescingKey = coalescingKey;
}

return self;
}

RCT_NOT_IMPLEMENTED(-(instancetype)init)

- (uint16_t)coalescingKey
{
return _coalescingKey;
}

- (NSDictionary *)body
{
NSDictionary *body = @{
@"insets" : @{
@"top" : @(_insets.top),
@"right" : @(_insets.right),
@"bottom" : @(_insets.bottom),
@"left" : @(_insets.left),
},
@"frame" : @{
@"x" : @(_frame.origin.x),
@"y" : @(_frame.origin.y),
@"width" : @(_frame.size.width),
@"height" : @(_frame.size.height),
},
};

return body;
}

- (BOOL)canCoalesce
{
return YES;
}

- (RNCOnInsetsChangeEvent *)coalesceWithEvent:(RNCOnInsetsChangeEvent *)newEvent
{
return newEvent;
}

+ (NSString *)moduleDotMethod
{
return @"RCTEventEmitter.receiveEvent";
}

- (NSArray *)arguments
{
return @[ self.viewTag, RCTNormalizeInputEventName(self.eventName), [self body] ];
}

@end
6 changes: 6 additions & 0 deletions ios/RNCSafeAreaProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
#import <AppKit/AppKit.h>
#endif

#import <React/RCTEventDispatcherProtocol.h>
#import <React/RCTView.h>

NS_ASSUME_NONNULL_BEGIN

@interface RNCSafeAreaProvider : RCTView

- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher NS_DESIGNATED_INITIALIZER;

// NOTE: currently these event props are only declared so we can export the
// event names to JS - we don't call the blocks directly because events
// need to be coalesced before sending, for performance reasons.
@property (nonatomic, copy) RCTBubblingEventBlock onInsetsChange;

@end
Expand Down
48 changes: 31 additions & 17 deletions ios/RNCSafeAreaProvider.m
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
#import "RNCSafeAreaProvider.h"

#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUIManager.h>
#import "RCTUIManagerObserverCoordinator.h"
#import "RNCOnInsetsChangeEvent.h"
#import "RNCSafeAreaUtils.h"

@interface RNCSafeAreaProvider () <RCTUIManagerObserver>

@end

@implementation RNCSafeAreaProvider {
id<RCTEventDispatcherProtocol> _eventDispatcher;
UIEdgeInsets _currentSafeAreaInsets;
CGRect _currentFrame;
BOOL _initialInsetsSent;
}

- (instancetype)init
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
{
if ((self = [super init])) {
RCTAssertParam(eventDispatcher);

if ((self = [super initWithFrame:CGRectZero])) {
#if !TARGET_OS_TV && !TARGET_OS_OSX

_eventDispatcher = eventDispatcher;

[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(invalidateSafeAreaInsets)
name:UIKeyboardDidShowNotification
Expand Down Expand Up @@ -58,6 +71,7 @@ - (void)invalidateSafeAreaInsets
safeAreaInsets = NSEdgeInsetsZero;
}
#endif

CGRect frame = [self convertRect:self.bounds toView:RNCParentViewController(self).view];

if (_initialInsetsSent &&
Expand All @@ -69,27 +83,19 @@ - (void)invalidateSafeAreaInsets
CGRectEqualToRect(frame, _currentFrame)) {
return;
}

_initialInsetsSent = YES;
_currentSafeAreaInsets = safeAreaInsets;
_currentFrame = frame;

[NSNotificationCenter.defaultCenter postNotificationName:RNCSafeAreaDidChange object:self userInfo:nil];

self.onInsetsChange(@{
@"insets" : @{
@"top" : @(safeAreaInsets.top),
@"right" : @(safeAreaInsets.right),
@"bottom" : @(safeAreaInsets.bottom),
@"left" : @(safeAreaInsets.left),
},
@"frame" : @{
@"x" : @(frame.origin.x),
@"y" : @(frame.origin.y),
@"width" : @(frame.size.width),
@"height" : @(frame.size.height),
},
});
RNCOnInsetsChangeEvent *onInsetsChangeEvent = [[RNCOnInsetsChangeEvent alloc] initWithEventName:@"onInsetsChange"
reactTag:self.reactTag
insets:safeAreaInsets
frame:frame
coalescingKey:0];

[_eventDispatcher sendEvent:onInsetsChangeEvent];
}

- (void)layoutSubviews
Expand All @@ -99,4 +105,12 @@ - (void)layoutSubviews
[self invalidateSafeAreaInsets];
}

RCT_NOT_IMPLEMENTED(-(instancetype)initWithFrame : (CGRect)frame)
RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)

- (void)dealloc
{
[_eventDispatcher.bridge.uiManager.observerCoordinator removeObserver:self];
}

@end
2 changes: 1 addition & 1 deletion ios/RNCSafeAreaProviderManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ - (UIView *)view
- (NSView *)view
#endif
{
return [RNCSafeAreaProvider new];
return [[RNCSafeAreaProvider alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
}

@end
6 changes: 6 additions & 0 deletions ios/RNSafeAreaContext.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
0C7844F027C02D03001807FB /* RNCSafeAreaProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C7844ED27C02D03001807FB /* RNCSafeAreaProvider.m */; };
AA53A9EE2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m in Sources */ = {isa = PBXBuildFile; fileRef = AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */; };
C923EDBC220C2C1A00D3100F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */; };
D697AA982D6F1D0A009C6433 /* RNCChangeEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -59,6 +60,8 @@
AA53A9EC2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCSafeAreaViewEdgeModes.h; sourceTree = "<group>"; };
AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCSafeAreaViewEdgeModes.m; sourceTree = "<group>"; };
C923EDBB220C2C1A00D3100F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
D697AA962D6F1CE5009C6433 /* RNCChangeEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCChangeEvent.h; sourceTree = "<group>"; };
D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCChangeEvent.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -84,6 +87,8 @@
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
D697AA972D6F1D08009C6433 /* RNCChangeEvent.m */,
D697AA962D6F1CE5009C6433 /* RNCChangeEvent.h */,
AA53A9EC2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.h */,
AA53A9ED2A321C01009AB3B2 /* RNCSafeAreaViewEdgeModes.m */,
0C7844EE27C02D03001807FB /* Fabric */,
Expand Down Expand Up @@ -183,6 +188,7 @@
0C7844E827C02CEE001807FB /* RNCSafeAreaView.m in Sources */,
0C7844E627C02CEE001807FB /* RNCSafeAreaViewEdges.m in Sources */,
0C7844E527C02CEE001807FB /* RNCSafeAreaViewManager.m in Sources */,
D697AA982D6F1D0A009C6433 /* RNCChangeEvent.m in Sources */,
0C7844EF27C02D03001807FB /* RNCSafeAreaContext.mm in Sources */,
0C7844E127C02CEE001807FB /* RNCSafeAreaViewLocalData.m in Sources */,
0C7844E227C02CEE001807FB /* RNCSafeAreaViewMode.m in Sources */,
Expand Down