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/ios fragmentview support #71

Merged
merged 1 commit into from
Aug 26, 2024
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
2 changes: 1 addition & 1 deletion hyper-sdk-react.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'

hyper_sdk_version = "2.1.39"
hyper_sdk_version = "2.2.1.4"

begin
package_json_path = File.expand_path(File.join(__dir__, "../../package.json"))
Expand Down
4 changes: 4 additions & 0 deletions ios/HyperSdkReact.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import <React/RCTEventEmitter.h>
#import <HyperSDK/HyperSDK.h>
#import <React/RCTRootView.h>
#import <React/RCTViewManager.h>

@interface HyperSdkReact : RCTEventEmitter <RCTBridgeModule>

Expand All @@ -34,3 +35,6 @@
@property (nonatomic, strong) NSLayoutConstraint *trailing;

@end

@interface HyperFragmentViewManagerIOS : RCTViewManager
@end
106 changes: 84 additions & 22 deletions ios/HyperSdkReact.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#import <HyperSDK/HyperSDK.h>

__weak static HyperServices *_hyperServicesReference;

// Overriding the RCTRootView to add contraints to align with the views superview
@implementation SDKRootView

Expand All @@ -31,7 +33,7 @@ -(void)didMoveToSuperview {
if (self.trailing.isActive) {
self.trailing.active = @NO;
}

//Checking superview just to be sure that it is not nil
if(self.superview) {
// Create contraints to replicate wrapcontent
Expand Down Expand Up @@ -70,12 +72,12 @@ - (void) setHeight: (NSNumber*)height forTag: (NSString * _Nonnull)tag {
// Update the latest value of the height holder for the given tag
// This will be used to set the height of view if view is created at a later point
[self.heightHolder setObject: height forKey:tag];

// Fetch previous height constraint so that it can be set to inactive
NSLayoutConstraint *heightConstraint = [self.heightConstraintHolder objectForKey:tag];
// Fetch rootview to update set constraints if view is already created
UIView *rootView = [self.rootHolder objectForKey:tag];

// Check if view is already present
if (rootView && [rootView isKindOfClass: [UIView class]]) {
// If present set earlier constraint to inactive
Expand All @@ -96,7 +98,7 @@ - (void) setHeight: (NSNumber*)height forTag: (NSString * _Nonnull)tag {
Use bridge to share the same JS VM
*/
- (UIView * _Nullable)merchantViewForViewType:(NSString * _Nonnull)viewType {

// Create a SDKRootView so that we can attach width constraints once it is attached to it's parent
RCTRootView *rrv = [SDKRootView alloc];
NSString *moduleName = @"JP_003";
Expand All @@ -109,23 +111,23 @@ - (UIView * _Nullable)merchantViewForViewType:(NSString * _Nonnull)viewType {
} else if ([viewType isEqual:@"FOOTER_ATTACHED"] && [registeredComponents containsObject:@"JuspayFooterAttached"]) {
moduleName = @"JuspayFooterAttached";
}

// Save a reference of the react root view
// This will be used to update height constraint if a newer value is sent by the merchant
[self.rootHolder setObject:rrv forKey:moduleName];


rrv = [rrv initWithBridge: self.bridge
moduleName:moduleName
initialProperties:nil
];

moduleName:moduleName
initialProperties:nil
];
// Remove background colour. Default colour white is getting applied to the merchant view
rrv.backgroundColor = UIColor.clearColor ;

// Remove height 0, width 0 constraints added by default.
rrv.translatesAutoresizingMaskIntoConstraints = false;

// If height is available set the height
NSNumber *height = [self.heightHolder objectForKey:moduleName];
if (height && [height isKindOfClass:[NSNumber class]]) {
Expand Down Expand Up @@ -166,12 +168,12 @@ + (BOOL)requiresMainQueueSetup{

- (NSDictionary *)constantsToExport
{
return @{ HYPER_EVENT: HYPER_EVENT
, JUSPAY_HEADER : JUSPAY_HEADER
, JUSPAY_HEADER_ATTACHED : JUSPAY_HEADER_ATTACHED
, JUSPAY_FOOTER : JUSPAY_FOOTER
, JUSPAY_FOOTER_ATTACHED : JUSPAY_FOOTER_ATTACHED
};
return @{ HYPER_EVENT: HYPER_EVENT
, JUSPAY_HEADER : JUSPAY_HEADER
, JUSPAY_HEADER_ATTACHED : JUSPAY_HEADER_ATTACHED
, JUSPAY_FOOTER : JUSPAY_FOOTER
, JUSPAY_FOOTER_ATTACHED : JUSPAY_FOOTER_ATTACHED
};
}

// Will be called when this module's first listener is added.
Expand All @@ -191,7 +193,7 @@ -(void)stopObserving {
if (jsonData && [jsonData isKindOfClass:[NSDictionary class]] && jsonData.allKeys.count>0) {
[HyperServices preFetch:jsonData];
} else {

}
} @catch (NSException *exception) {
//Parsing failure.
Expand All @@ -202,6 +204,7 @@ -(void)stopObserving {
RCT_EXPORT_METHOD(createHyperServices) {
if (self.hyperInstance == NULL) {
self.hyperInstance = [HyperServices new];
_hyperServicesReference = self.hyperInstance;
}
}

Expand All @@ -210,7 +213,7 @@ -(void)stopObserving {
@try {
NSDictionary *jsonData = [HyperSdkReact stringToDictionary:data];
if (jsonData && [jsonData isKindOfClass:[NSDictionary class]] && jsonData.allKeys.count>0) {

UIViewController *baseViewController = RCTPresentedViewController();
__weak HyperSdkReact *weakSelf = self;
self.delegate = [[SdkDelegate alloc] initWithBridge:self.bridge];
Expand Down Expand Up @@ -240,7 +243,7 @@ -(void)stopObserving {
if (self.hyperInstance.baseViewController == nil || self.hyperInstance.baseViewController.view.window == nil) {
// Getting topViewController
id baseViewController = RCTPresentedViewController();

// Set the presenting ViewController as baseViewController if the topViewController is RCTModalHostViewController.
if ([baseViewController isMemberOfClass:RCTModalHostViewController.class] && [baseViewController presentingViewController]) {
[self.hyperInstance setBaseViewController:[baseViewController presentingViewController]];
Expand Down Expand Up @@ -318,3 +321,62 @@ + (NSString*)dictionaryToString:(id)dict{
}

@end

@implementation HyperFragmentViewManagerIOS
RCT_EXPORT_MODULE()

- (dispatch_queue_t)methodQueue{
return dispatch_get_main_queue();
}

+ (BOOL)requiresMainQueueSetup{
return YES;
}

- (UIView *)view
{
return [[UIView alloc] init];
}

RCT_EXPORT_METHOD(process:(nonnull NSNumber *)viewTag nameSpace:(NSString *)nameSpace payload:(NSString *)payload)
{
HyperServices *hyperServicesInstance = _hyperServicesReference;
if (payload && payload.length>0) {
@try {
NSDictionary *jsonData = [HyperSdkReact stringToDictionary:payload];
if (jsonData && [jsonData isKindOfClass:[NSDictionary class]] && jsonData.allKeys.count>0) {
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
if (hyperServicesInstance.baseViewController == nil || hyperServicesInstance.baseViewController.view.window == nil) {
id baseViewController = RCTPresentedViewController();
if ([baseViewController isMemberOfClass:RCTModalHostViewController.class] && [baseViewController presentingViewController]) {
[hyperServicesInstance setBaseViewController:[baseViewController presentingViewController]];
} else {
[hyperServicesInstance setBaseViewController:baseViewController];
}
}
UIView *view = viewRegistry[viewTag];
[self manuallyLayoutChildren:view];
if (!view || ![view isKindOfClass:[UIView class]]) {
RCTLogError(@"Cannot find NativeViewManager with tag #%@", viewTag);
return;
}
NSMutableDictionary *nestedPayload = [jsonData[@"payload"] mutableCopy];
NSDictionary *fragmentViewGroup = @{nameSpace: view};
nestedPayload[@"fragmentViewGroups"] = fragmentViewGroup;
NSMutableDictionary *updatedJsonData = [jsonData mutableCopy];
updatedJsonData[@"payload"] = nestedPayload;
[hyperServicesInstance process:[updatedJsonData copy]];
}];
} else {}
} @catch (NSException *exception) {}
} else {}
}

- (void)manuallyLayoutChildren:(UIView *)view {
UIView *parent = view.superview;
if (!parent) return;

view.frame = parent.bounds;
}

@end
36 changes: 25 additions & 11 deletions src/HyperFragmentView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,31 @@ var HyperFragmentViewManager: any;

if (Platform.OS === 'android') {
HyperFragmentViewManager = requireNativeComponent('HyperFragmentViewManager');
} else {
HyperFragmentViewManager = requireNativeComponent(
'HyperFragmentViewManagerIOS'
);
}

const createFragment = (viewId: number, namespace: string, payload: string) => {
UIManager.dispatchViewManagerCommand(
viewId,
//@ts-ignore
UIManager.HyperFragmentViewManager.Commands.process.toString(),
[viewId, namespace, payload]
);
if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
viewId,
//@ts-ignore
UIManager.HyperFragmentViewManager.Commands.process.toString(),
[viewId, namespace, payload]
);
} else {
const commandId = UIManager.getViewManagerConfig(
'HyperFragmentViewManagerIOS'
harshgarg18 marked this conversation as resolved.
Show resolved Hide resolved
).Commands.process;
if (typeof commandId !== 'undefined') {
UIManager.dispatchViewManagerCommand(viewId, commandId, [
namespace,
payload,
]);
}
}
};

const HyperFragmentView: React.FC<HyperFragmentViewProps> = ({
Expand All @@ -43,11 +59,9 @@ const HyperFragmentView: React.FC<HyperFragmentViewProps> = ({
}) => {
const ref = React.useRef<View | null>(null);
React.useEffect(() => {
if (Platform.OS === 'android') {
const viewId = findNodeHandle(ref.current);
if (viewId) {
createFragment(viewId, namespace, payload);
}
const viewId = findNodeHandle(ref.current);
if (viewId) {
createFragment(viewId, namespace, payload);
}
}, [namespace, payload]);

Expand Down
Loading