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

chore: React Native Widget #19

Closed
wants to merge 2 commits into from
Closed
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
20 changes: 20 additions & 0 deletions android/src/main/java/in/juspay/hypersdkreact/CustomView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package in.juspay.hypersdkreact;
import android.content.Context;
import android.graphics.Color;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;

public class CustomView extends FrameLayout {
public CustomView(@NonNull Context context) {
super(context);
this.setPadding(16,16,16,16);
this.setBackgroundColor(Color.parseColor("#5FD3F3"));

TextView text = new TextView(context);
text.setText("Welcome to Android Fragments with React Native.");
this.addView(text);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext r
@Override
@SuppressWarnings("rawtypes")
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
return Collections.singletonList(
new MyViewManager(reactContext)
);
}
}
49 changes: 49 additions & 0 deletions android/src/main/java/in/juspay/hypersdkreact/MyFragment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package in.juspay.hypersdkreact;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;


public class MyFragment extends Fragment {
CustomView customView;

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
super.onCreateView(inflater, parent, savedInstanceState);
customView = new CustomView(this.requireContext());
return customView; // this CustomView could be any view that you want to render
}

@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// do any logic that should happen in an `onCreate` method, e.g:
// customView.onCreate(savedInstanceState);
}

@Override
public void onPause() {
super.onPause();
// do any logic that should happen in an `onPause` method
// e.g.: customView.onPause();
}

@Override
public void onResume() {
super.onResume();
// do any logic that should happen in an `onResume` method
// e.g.: customView.onResume();
}

@Override
public void onDestroy() {
super.onDestroy();
// do any logic that should happen in an `onDestroy` method
// e.g.: customView.onDestroy();
}
}
127 changes: 127 additions & 0 deletions android/src/main/java/in/juspay/hypersdkreact/MyViewManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package in.juspay.hypersdkreact;

import android.graphics.Color;
import android.util.Log;
import android.view.Choreographer;
import android.view.View;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ThemedReactContext;

import java.util.Map;
import android.view.ViewGroup;

public class MyViewManager extends ViewGroupManager<FrameLayout> {

public static final String REACT_CLASS = "MyViewManager";
public final int COMMAND_CREATE = 1;
private int propWidth;
private int propHeight;

ReactApplicationContext reactContext;

public MyViewManager(ReactApplicationContext reactContext) {
this.reactContext = reactContext;
}

@Override
public String getName() {
return REACT_CLASS;
}

/**
* Return a FrameLayout which will later hold the Fragment
*/
@Override
public FrameLayout createViewInstance(ThemedReactContext reactContext) {
return new FrameLayout(reactContext);
}

/**
* Map the "create" command to an integer
*/
@Nullable
@Override
public Map<String, Integer> getCommandsMap() {
return MapBuilder.of("create", COMMAND_CREATE);
}

/**
* Handle "create" command (called from JS) and call createFragment method
*/
@Override
public void receiveCommand(
@NonNull FrameLayout root,
String commandId,
@Nullable ReadableArray args
) {
super.receiveCommand(root, commandId, args);
assert args != null;
int reactNativeViewId = args.getInt(0);
int commandIdInt = Integer.parseInt(commandId);

if (commandIdInt == COMMAND_CREATE) {
createFragment(root, reactNativeViewId);
}
}

@ReactPropGroup(names = {"width", "height"}, customType = "Style")
public void setStyle(FrameLayout view, int index, Integer value) {
if (index == 0) {
propWidth = value;
}

if (index == 1) {
propHeight = value;
}
}

/**
* Replace your React Native view with a custom fragment
*/
public void createFragment(FrameLayout root, int reactNativeViewId) {
ViewGroup parentView = root.findViewById(reactNativeViewId);
setupLayout(parentView);

final MyFragment myFragment = new MyFragment();
FragmentActivity activity = (FragmentActivity) reactContext.getCurrentActivity();
activity.getSupportFragmentManager()
.beginTransaction()
.replace(reactNativeViewId, myFragment, String.valueOf(reactNativeViewId))
.commit();
}

public void setupLayout(View view) {
Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
manuallyLayoutChildren(view);
view.getViewTreeObserver().dispatchOnGlobalLayout();
Choreographer.getInstance().postFrameCallback(this);
}
});
}

/**
* Layout all children properly
*/
public void manuallyLayoutChildren(View view) {
int width = propWidth>0 ? propWidth: View.MeasureSpec.getSize(ViewGroup.LayoutParams.WRAP_CONTENT);
int height = propHeight>0 ? propHeight: View.MeasureSpec.getSize(ViewGroup.LayoutParams.WRAP_CONTENT);

view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));

view.layout(0, 0, width, height);
}
}
1 change: 1 addition & 0 deletions example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ buildscript {
allprojects {
repositories {
maven { url "https://maven.juspay.in/jp-build-packages/hyper-sdk/" }
maven { url "https://sdk.getsimpl.com/" }
}
}
6 changes: 5 additions & 1 deletion example/src/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
ScrollView,
} from 'react-native';
import HyperAPIUtils from './API';
import HyperSdkReact from 'hyper-sdk-react';
import HyperSdkReact, { MyView } from 'hyper-sdk-react';
import HyperUtils from './Utils';
import merchantConfig from './merchant_config.json';
import customerConfig from './customer_config.json';
Expand Down Expand Up @@ -389,6 +389,10 @@ class HomeScreen extends React.Component {
</Animated.View>
</View>
</Animated.View>
<View style={{ backgroundColor: 'red', flexDirection: 'row' }}>
<Text>Amount: Rs.10 </Text>
<MyView height={40} /* width={80} */ />
</View>
</>
);
}
Expand Down
4 changes: 4 additions & 0 deletions ios/MyViewManagerManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

#import <React/RCTBridgeModule.h>
@interface MyViewManagerManager : NSObject <RCTBridgeModule>
@end
38 changes: 38 additions & 0 deletions ios/MyViewManagerManager.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#import <React/RCTViewManager.h>
#import <React/RCTConvert.h>
#import <React/RCTUIManager.h>
#import <React/RCTView.h>

@interface MyViewManagerManager : RCTViewManager

@end

@implementation MyViewManagerManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
UIView *myView = [[UIView alloc] init];
UILabel *label = [[UILabel alloc] init];
label.text = @"Welcome to IOS UIView with React Native.";
label.textAlignment = NSTextAlignmentLeft;
label.backgroundColor = UIColor.blueColor;
label.textColor = UIColor.whiteColor;
[label sizeToFit];
[myView addSubview:label];

return myView;
}

RCT_CUSTOM_VIEW_PROPERTY(width, float, UIView)
{
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, [RCTConvert CGFloat:json], view.frame.size.height);
}

RCT_CUSTOM_VIEW_PROPERTY(height, float, UIView)
{
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, [RCTConvert CGFloat:json]);
}

@end
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@
},
"eslintIgnore": [
"node_modules/",
"lib/"
"lib/",
"src/MyView.tsx"
],
"prettier": {
"quoteProps": "consistent",
Expand All @@ -163,4 +164,4 @@
]
]
}
}
}
53 changes: 53 additions & 0 deletions src/MyView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import * as React from 'react';
import {
View,
PixelRatio,
UIManager,
findNodeHandle,
requireNativeComponent,
Platform
} from 'react-native';

export interface MyViewProps {
height?: number;
width?: number;
}

export const MyViewManager =
requireNativeComponent('MyViewManager');

const createFragment = (viewId: number) => {
UIManager.dispatchViewManagerCommand(
viewId,
//@ts-ignore
UIManager.MyViewManager.Commands.create.toString(),
[viewId],
);
}

const MyView: React.FC<MyViewProps> = ({ height, width }) => {
const ref = React.useRef<View | null>(null);
React.useEffect(() => {
if (Platform.OS == 'android') {
const viewId = findNodeHandle(ref.current);
if (viewId) {
createFragment(viewId);
}
}
}, [height, width]);

return (
<View style={{ height: height, width: width }}>
<MyViewManager
//@ts-ignore
style={{
height: PixelRatio.getPixelSizeForLayoutSize(height || 0),
width: PixelRatio.getPixelSizeForLayoutSize(width || 0),
}}
ref={ref}
/>
</View>
)
}

export default MyView;
3 changes: 3 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import { NativeModules, Platform } from 'react-native';

// @ts-ignore
export { default as MyView } from './MyView';

const LINKING_ERROR =
`The package 'hyper-sdk-react' doesn't seem to be linked. Make sure: \n\n` +
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
Expand Down