Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ios/HingeInteraction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

typedef void (^HingesUpdateHandler)(NSArray<NSDictionary *> *hinges);

/// Returns nil when the SDK or runtime has no UIHingeInteraction.
id<UIInteraction> _Nullable HingesMakeInteraction(HingesUpdateHandler handler);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning id<UIInteraction> rather than UIHingeInteraction * keeps this header buildable on SDKs that have no UIHingeInteraction declaration, so the guard stays confined to the .mm.


NS_ASSUME_NONNULL_END
26 changes: 26 additions & 0 deletions ios/HingeInteraction.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#import "HingeInteraction.h"

id<UIInteraction> HingesMakeInteraction(HingesUpdateHandler handler)
{
#if defined(__IPHONE_27_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_27_1
if (@available(iOS 27.1, *)) {
return [[UIHingeInteraction alloc]
initWithUpdateHandler:^(UIHingeInteraction *interaction, UIHingeInteractionUpdate *update) {
UIHinge *hinge = update.hinge;
if (hinge == nil) {
handler(@[]);
return;
}
NSString *status = @"unknown";
switch (hinge.status) {
case UIHingeStatusClosed: status = @"closed"; break;
case UIHingeStatusPartiallyOpen: status = @"partiallyOpen"; break;
case UIHingeStatusFullyOpen: status = @"fullyOpen"; break;
case UIHingeStatusUnknown: break;
}
handler(@[@{@"status": status, @"angle": @(hinge.angle), @"hasAngle": @YES}]);
}];
}
#endif
return nil;
}
37 changes: 12 additions & 25 deletions ios/HingesModule.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#import "HingesModule.h"

#import "HingeInteraction.h"

#import <React/RCTFabricSurface.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfaceView.h>
Expand Down Expand Up @@ -88,35 +90,20 @@ - (void)startObserving:(double)rootTag
if (observation.interaction == nil) {
UIView *view = [self->_surfacePresenter surfaceForRootTag:tag.integerValue].view;
observation.view = view;
#if defined(__IPHONE_27_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_27_1
if (@available(iOS 27.1, *)) {
if (view != nil) {
__weak HingesModule *weakSelf = self;
__weak HingeRootObservation *weakObservation = observation;
UIHingeInteraction *interaction = [[UIHingeInteraction alloc]
initWithUpdateHandler:^(UIHingeInteraction *interaction, UIHingeInteractionUpdate *update) {
HingesModule *strongSelf = weakSelf;
HingeRootObservation *strongObservation = weakObservation;
if (strongSelf == nil || strongObservation == nil) return;
UIHinge *hinge = update.hinge;
NSArray<NSDictionary *> *hinges = @[];
if (hinge != nil) {
NSString *status = @"unknown";
switch (hinge.status) {
case UIHingeStatusClosed: status = @"closed"; break;
case UIHingeStatusPartiallyOpen: status = @"partiallyOpen"; break;
case UIHingeStatusFullyOpen: status = @"fullyOpen"; break;
case UIHingeStatusUnknown: break;
}
hinges = @[@{@"status": status, @"angle": @(hinge.angle), @"hasAngle": @YES}];
}
[strongSelf updateRoot:tag observation:strongObservation hinges:hinges];
}];
if (view != nil) {
__weak HingesModule *weakSelf = self;
__weak HingeRootObservation *weakObservation = observation;
id<UIInteraction> interaction = HingesMakeInteraction(^(NSArray<NSDictionary *> *hinges) {
HingesModule *strongSelf = weakSelf;
HingeRootObservation *strongObservation = weakObservation;
if (strongSelf == nil || strongObservation == nil) return;
[strongSelf updateRoot:tag observation:strongObservation hinges:hinges];
});
if (interaction != nil) {
observation.interaction = interaction;
[view addInteraction:interaction];
}
}
#endif
}
[self emitSnapshotForRoot:tag hinges:[self getSnapshot:rootTag][@"hinges"]];
});
Expand Down
38 changes: 15 additions & 23 deletions ios/HingesObserverView.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#import "HingesObserverView.h"

#import "HingeInteraction.h"

#import <UIKit/UIKit.h>
#import <react/renderer/components/HingesSpec/ComponentDescriptors.h>
#import <react/renderer/components/HingesSpec/EventEmitters.h>
Expand All @@ -26,31 +28,21 @@ - (instancetype)initWithFrame:(CGRect)frame
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const HingesObserverViewProps>();
_props = defaultProps;
#if defined(__IPHONE_27_1) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_27_1
if (@available(iOS 27.1, *)) {
__weak HingesObserverView *weakSelf = self;
UIHingeInteraction *interaction = [[UIHingeInteraction alloc]
initWithUpdateHandler:^(UIHingeInteraction *interaction, UIHingeInteractionUpdate *update) {
HingesObserverView *strongSelf = weakSelf;
if (strongSelf == nil) return;
HingesObserverViewEventEmitter::OnHingesChange snapshot;
UIHinge *hinge = update.hinge;
if (hinge != nil) {
std::string status = "unknown";
switch (hinge.status) {
case UIHingeStatusClosed: status = "closed"; break;
case UIHingeStatusPartiallyOpen: status = "partiallyOpen"; break;
case UIHingeStatusFullyOpen: status = "fullyOpen"; break;
case UIHingeStatusUnknown: break;
}
snapshot.hinges.push_back({status, hinge.angle, true});
}
strongSelf->_snapshot = std::move(snapshot);
[strongSelf emitSnapshot];
}];
__weak HingesObserverView *weakSelf = self;
id<UIInteraction> interaction = HingesMakeInteraction(^(NSArray<NSDictionary *> *hinges) {
HingesObserverView *strongSelf = weakSelf;
if (strongSelf == nil) return;
HingesObserverViewEventEmitter::OnHingesChange snapshot;
for (NSDictionary *hinge in hinges) {
snapshot.hinges.push_back(
{[hinge[@"status"] UTF8String], [hinge[@"angle"] doubleValue], [hinge[@"hasAngle"] boolValue]});
}
strongSelf->_snapshot = std::move(snapshot);
[strongSelf emitSnapshot];
});
if (interaction != nil) {
[self addInteraction:interaction];
}
#endif
}
return self;
}
Expand Down
Loading