omnipay-reactnative-sdk 1.2.3-beta.8 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +42 -102
  2. package/android/build.gradle +4 -15
  3. package/android/src/main/java/com/omniretail/omnipay/OmnipayActivityPackage.java +0 -5
  4. package/lib/commonjs/components/OmnipayProvider.js +91 -18
  5. package/lib/commonjs/components/OmnipayProvider.js.map +1 -1
  6. package/lib/module/components/OmnipayProvider.js +92 -19
  7. package/lib/module/components/OmnipayProvider.js.map +1 -1
  8. package/lib/module/components/OmnipayView.js.map +1 -1
  9. package/lib/module/components/views/BvnVerification.js.map +1 -1
  10. package/lib/module/components/views/PaylaterAgreement.js.map +1 -1
  11. package/lib/module/components/views/Registration.js.map +1 -1
  12. package/lib/typescript/components/OmnipayProvider.d.ts +3 -2
  13. package/lib/typescript/components/OmnipayProvider.d.ts.map +1 -1
  14. package/lib/typescript/hooks/useOmnipay.d.ts +2 -1
  15. package/lib/typescript/hooks/useOmnipay.d.ts.map +1 -1
  16. package/package.json +12 -29
  17. package/src/components/OmnipayProvider.tsx +133 -21
  18. package/src/components/OmnipayView.tsx +1 -1
  19. package/src/components/views/BvnVerification.tsx +1 -1
  20. package/src/components/views/PaylaterAgreement.tsx +1 -1
  21. package/src/components/views/Registration.tsx +1 -1
  22. package/src/hooks/useOmnipay.tsx +1 -1
  23. package/android/src/main/java/com/omniretail/omnipay/FaceVerificationFrameProcessor.kt +0 -111
  24. package/ios/FaceVerificationFrameProcessor.swift +0 -138
  25. package/ios/FaceVerificationFrameProcessorPlugin.m +0 -10
  26. package/ios/OmnipayReactnativeSdk.m +0 -5
  27. package/ios/OmnipayReactnativeSdk.swift +0 -10
  28. package/ios/omnipay-reactnative-sdk-Bridging-Header.h +0 -8
  29. package/ios/omnipay_reactnative_sdk.h +0 -6
  30. package/lib/commonjs/components/Button.js +0 -68
  31. package/lib/commonjs/components/Button.js.map +0 -1
  32. package/lib/commonjs/components/biometrics/FaceVerification.js +0 -380
  33. package/lib/commonjs/components/biometrics/FaceVerification.js.map +0 -1
  34. package/lib/commonjs/components/biometrics/useFaceVerification.js +0 -85
  35. package/lib/commonjs/components/biometrics/useFaceVerification.js.map +0 -1
  36. package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js +0 -157
  37. package/lib/commonjs/components/biometrics/useFaceVerificationFlow.js.map +0 -1
  38. package/lib/module/components/Button.js +0 -61
  39. package/lib/module/components/Button.js.map +0 -1
  40. package/lib/module/components/biometrics/FaceVerification.js +0 -372
  41. package/lib/module/components/biometrics/FaceVerification.js.map +0 -1
  42. package/lib/module/components/biometrics/useFaceVerification.js +0 -78
  43. package/lib/module/components/biometrics/useFaceVerification.js.map +0 -1
  44. package/lib/module/components/biometrics/useFaceVerificationFlow.js +0 -150
  45. package/lib/module/components/biometrics/useFaceVerificationFlow.js.map +0 -1
  46. package/lib/typescript/components/Button.d.ts +0 -17
  47. package/lib/typescript/components/Button.d.ts.map +0 -1
  48. package/lib/typescript/components/biometrics/FaceVerification.d.ts +0 -9
  49. package/lib/typescript/components/biometrics/FaceVerification.d.ts.map +0 -1
  50. package/lib/typescript/components/biometrics/useFaceVerification.d.ts +0 -38
  51. package/lib/typescript/components/biometrics/useFaceVerification.d.ts.map +0 -1
  52. package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts +0 -29
  53. package/lib/typescript/components/biometrics/useFaceVerificationFlow.d.ts.map +0 -1
  54. package/omnipay_reactnative_sdk.podspec +0 -50
  55. package/src/components/Button.tsx +0 -86
  56. package/src/components/biometrics/FaceVerification.tsx +0 -429
  57. package/src/components/biometrics/useFaceVerification.ts +0 -120
  58. package/src/components/biometrics/useFaceVerificationFlow.ts +0 -224
@@ -12,12 +12,15 @@ import {
12
12
  Image,
13
13
  TouchableWithoutFeedback,
14
14
  Text,
15
+ NativeModules,
16
+ NativeEventEmitter,
15
17
  } from 'react-native';
16
- import WebView, { WebViewMessageEvent } from 'react-native-webview';
18
+ import WebView, { type WebViewMessageEvent } from 'react-native-webview';
17
19
  import { getContact } from '../functions';
18
20
  import Share from 'react-native-share';
19
- import FaceVerification from './biometrics/FaceVerification';
20
- import Button from './Button';
21
+ import AsyncStorage from '@react-native-async-storage/async-storage';
22
+
23
+ const OmnipayActivity = NativeModules.OmnipayActivity || {};
21
24
 
22
25
  type OmnipayProviderProps = {
23
26
  publicKey: string;
@@ -26,6 +29,16 @@ type OmnipayProviderProps = {
26
29
  children: React.ReactElement | React.ReactElement[];
27
30
  };
28
31
 
32
+ type PosTransactionType = {
33
+ amount: number;
34
+ purchaseType: 'PURCHASE' | 'KEY EXCHANGE';
35
+ color: string;
36
+ print: boolean;
37
+ rrn: string;
38
+ stan: string;
39
+ terminalId: string;
40
+ };
41
+
29
42
  type PostMessage = {
30
43
  [key: string]: unknown;
31
44
  };
@@ -57,6 +70,7 @@ type InitiateWalletType = {
57
70
  sessionId?: string;
58
71
  kycStatus?: 'verified' | 'unverified';
59
72
  launchPage?: string;
73
+ promoName?: string;
60
74
  };
61
75
 
62
76
  export type OmnipayContextType = {
@@ -81,6 +95,7 @@ export type OmnipayContextType = {
81
95
  sessionId,
82
96
  launchPage,
83
97
  kycStatus,
98
+ promoName,
84
99
  }: InitiateWalletType) => void;
85
100
  };
86
101
 
@@ -110,18 +125,99 @@ export const OmnipayProvider = ({
110
125
  const isValidEnv = ['prod', 'dev'].includes(env);
111
126
  const isValidColor = color.length > 2;
112
127
  const onCloseRef = useRef<(() => void) | undefined>(undefined);
113
- const [showFaceVerification, setShowFaceVerification] = useState(false);
128
+ const [canUsePos, setCanUsePos] = useState(false);
114
129
 
115
130
  useEffect(() => {
116
- setTimeout(() => {
117
- setShowFaceVerification(true);
118
- }, 1000);
131
+ checkPaymentApp();
119
132
  }, []);
120
133
 
121
134
  useEffect(() => {
122
135
  visibilityRef.current = isVisible;
123
136
  }, [isVisible]);
124
137
 
138
+ useEffect(() => {
139
+ if (canUsePos) {
140
+ const eventEmitter = new NativeEventEmitter(OmnipayActivity);
141
+ eventEmitter.addListener('OmnipayEvent', (event) => {
142
+ console.log('native event', event);
143
+ });
144
+ }
145
+ }, [canUsePos]);
146
+
147
+ async function checkPaymentApp() {
148
+ try {
149
+ if (Platform.OS === 'android') {
150
+ const isInstalled = await OmnipayActivity.isPackageInstalled(
151
+ 'com.horizonpay.sample'
152
+ );
153
+ if (isInstalled) {
154
+ setCanUsePos(true);
155
+ }
156
+ }
157
+ } catch (error) {}
158
+ }
159
+
160
+ async function startPosTransaction({
161
+ amount,
162
+ purchaseType,
163
+ print,
164
+ rrn,
165
+ stan,
166
+ terminalId,
167
+ }: PosTransactionType) {
168
+ try {
169
+ if (Platform.OS === 'android') {
170
+ let result = '';
171
+
172
+ if (purchaseType === 'KEY EXCHANGE') {
173
+ const isKeyExchanged = await AsyncStorage.getItem('isKeyExchanged');
174
+ if (!isKeyExchanged) {
175
+ result = await OmnipayActivity.initiateHorizonTransaction(
176
+ amount,
177
+ purchaseType,
178
+ color,
179
+ print,
180
+ rrn,
181
+ stan,
182
+ terminalId
183
+ );
184
+ if (
185
+ terminalId &&
186
+ result &&
187
+ result.toLowerCase().includes('-message-success')
188
+ ) {
189
+ await AsyncStorage.setItem('isKeyExchanged', terminalId);
190
+ }
191
+ postMessage({
192
+ dataKey: 'onPosKeyExchanged',
193
+ dataValue: result,
194
+ });
195
+ }
196
+ } else {
197
+ result = await OmnipayActivity.initiateHorizonTransaction(
198
+ amount,
199
+ purchaseType,
200
+ color,
201
+ print,
202
+ rrn,
203
+ stan,
204
+ terminalId
205
+ );
206
+ postMessage({
207
+ dataKey: 'onPosTransactionSuccess',
208
+ dataValue: result,
209
+ });
210
+ }
211
+ }
212
+ } catch (error) {
213
+ console.log(error);
214
+ postMessage({
215
+ dataKey: 'onPosTransactionFailure',
216
+ dataValue: '',
217
+ });
218
+ }
219
+ }
220
+
125
221
  function getWebviewStyle() {
126
222
  if (!showWebview) {
127
223
  return { opacity: 0, height: 0, width: 0, flex: 0 };
@@ -181,6 +277,9 @@ export const OmnipayProvider = ({
181
277
  if (dataKey === 'shareReceipt') {
182
278
  shareReceipt(dataValue);
183
279
  }
280
+ if (dataKey === 'startPosTransaction') {
281
+ startPosTransaction(JSON.parse(dataValue));
282
+ }
184
283
  }
185
284
  } catch (error) {}
186
285
  }
@@ -228,6 +327,7 @@ export const OmnipayProvider = ({
228
327
  sessionId = '',
229
328
  kycStatus,
230
329
  launchPage = 'wallet',
330
+ promoName = '',
231
331
  }: InitiateWalletType) => {
232
332
  //prevent opening if it's already open
233
333
  if (visibilityRef.current) {
@@ -239,9 +339,9 @@ export const OmnipayProvider = ({
239
339
  const usesNativeShare = true;
240
340
 
241
341
  if (isPhoneNumberValid || isValidCustomerRef || isValidUserRef) {
242
- const webUrl = `${webHost}?theme=${color}&view=wallet&publicKey=${publicKey}&phoneNumber=${phoneNumber}&usesPaylater=${usesPaylater}&usesPromo=${usesPromo}&usesAirtimeData=${usesAirtimeData}&usesTransfer=${usesTransfer}&usesBills=${usesBills}&usesPos=${usesPos}&customerRef=${customerRef}&userRef=${userRef}&promoBalanceOffset=${promoBalanceOffset}&deviceId=${deviceId}&deviceName=${deviceName}&hideWalletTransfer=${hideWalletTransfer}&bvnRequired=${isBvnValidationRequired}&usesNativeShare=${usesNativeShare}&walletTab=${walletTab}&sessionId=${sessionId}&kycStatus=${
342
+ const webUrl = `${webHost}?theme=${color}&view=wallet&publicKey=${publicKey}&phoneNumber=${phoneNumber}&usesPaylater=${usesPaylater}&usesPromo=${usesPromo}&usesAirtimeData=${usesAirtimeData}&usesTransfer=${usesTransfer}&usesBills=${usesBills}&usesPos=${usesPos}&customerRef=${customerRef}&userRef=${userRef}&promoBalanceOffset=${promoBalanceOffset}&deviceId=${deviceId}&deviceName=${deviceName}&hideWalletTransfer=${hideWalletTransfer}&bvnRequired=${isBvnValidationRequired}&usesNativeShare=${usesNativeShare}&isPosEnabled=${canUsePos}&walletTab=${walletTab}&sessionId=${sessionId}&kycStatus=${
243
343
  kycStatus || ''
244
- }&launchPage=${launchPage}`;
344
+ }&launchPage=${launchPage}&promoName=${promoName}`;
245
345
  setWebviewUrl(webUrl);
246
346
  setIsVisible(true);
247
347
  onCloseRef.current = onClose;
@@ -317,6 +417,7 @@ export const OmnipayProvider = ({
317
417
  }}
318
418
  domStorageEnabled={true}
319
419
  originWhitelist={['*']}
420
+ allowsInlineMediaPlayback={true}
320
421
  onLoadEnd={() => setWebviewStatus('success')}
321
422
  renderError={() => (
322
423
  <View style={StyleSheet.absoluteFillObject}>
@@ -324,12 +425,21 @@ export const OmnipayProvider = ({
324
425
  <Text style={styles.errorSubtitle}>
325
426
  Unable to open your wallet. Please try again
326
427
  </Text>
327
- <Button
328
- title="Retry"
428
+ <TouchableOpacity
429
+ activeOpacity={0.8}
329
430
  onPress={reloadWebview}
330
- backgroundColor={color}
331
- borderColor={color}
332
- />
431
+ style={[
432
+ styles.button,
433
+ {
434
+ backgroundColor: color,
435
+ borderColor: color,
436
+ },
437
+ ]}
438
+ >
439
+ <>
440
+ <Text style={styles.buttonText}>Retry</Text>
441
+ </>
442
+ </TouchableOpacity>
333
443
  </View>
334
444
  </View>
335
445
  )}
@@ -350,13 +460,6 @@ export const OmnipayProvider = ({
350
460
  </>
351
461
  )}
352
462
  {children}
353
- {showFaceVerification && (
354
- <FaceVerification
355
- onClose={() => setShowFaceVerification(false)}
356
- onSuccess={() => setShowFaceVerification(false)}
357
- primaryColor={color}
358
- />
359
- )}
360
463
  </OmnipayContext.Provider>
361
464
  );
362
465
  };
@@ -467,4 +570,13 @@ const styles = StyleSheet.create({
467
570
  minWidth: 160,
468
571
  marginHorizontal: 'auto',
469
572
  },
573
+ button: {
574
+ borderRadius: 6,
575
+ paddingHorizontal: 12,
576
+ paddingVertical: 14,
577
+ borderWidth: 1,
578
+ alignItems: 'center',
579
+ justifyContent: 'center',
580
+ },
581
+ buttonText: { color: 'white', fontSize: 16, paddingHorizontal: 30 },
470
582
  });
@@ -7,7 +7,7 @@ import {
7
7
  Text,
8
8
  Linking,
9
9
  } from 'react-native';
10
- import { WebView, WebViewMessageEvent } from 'react-native-webview';
10
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
11
11
  import { clientSdkBaseUrl, serverSdkBaseUrl } from '../lib/config';
12
12
  import { getContact } from '../functions';
13
13
  import { Registration } from './views/Registration';
@@ -6,7 +6,7 @@ import {
6
6
  Text,
7
7
  View,
8
8
  } from 'react-native';
9
- import { WebView, WebViewMessageEvent } from 'react-native-webview';
9
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
10
10
  import { serverSdkBaseUrl } from '../../lib/config';
11
11
 
12
12
  type OmnipayProps = {
@@ -6,7 +6,7 @@ import {
6
6
  Text,
7
7
  View,
8
8
  } from 'react-native';
9
- import { WebView, WebViewMessageEvent } from 'react-native-webview';
9
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
10
10
  import { serverSdkBaseUrl } from '../../lib/config';
11
11
 
12
12
  type AgreementSubmittedType = {
@@ -6,7 +6,7 @@ import {
6
6
  Text,
7
7
  View,
8
8
  } from 'react-native';
9
- import { WebView, WebViewMessageEvent } from 'react-native-webview';
9
+ import { WebView, type WebViewMessageEvent } from 'react-native-webview';
10
10
  import { serverSdkBaseUrl } from '../../lib/config';
11
11
 
12
12
  type RegisterSuccessType = {
@@ -1,7 +1,7 @@
1
1
  import { useContext } from 'react';
2
2
  import {
3
3
  OmnipayContext,
4
- OmnipayContextType,
4
+ type OmnipayContextType,
5
5
  } from '../components/OmnipayProvider';
6
6
 
7
7
  export function useOmnipay() {
@@ -1,111 +0,0 @@
1
- package com.omniretail.omnipay
2
-
3
- import android.util.Log
4
- import com.google.mlkit.vision.common.InputImage
5
- import com.google.mlkit.vision.face.FaceDetection
6
- import com.google.mlkit.vision.face.FaceDetectorOptions
7
- import com.google.mlkit.vision.face.Face
8
- import com.mrousavy.camera.core.FrameInvalidError
9
- import com.mrousavy.camera.frameprocessor.Frame
10
- import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin
11
- import com.mrousavy.camera.frameprocessor.VisionCameraProxy
12
-
13
- class FaceVerificationFrameProcessor(proxy: VisionCameraProxy, options: Map<String, Any>?) : FrameProcessorPlugin() {
14
-
15
- private val faceDetector = FaceDetection.getClient(
16
- FaceDetectorOptions.Builder()
17
- .setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
18
- .setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
19
- .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
20
- .setMinFaceSize(0.15f)
21
- .enableTracking()
22
- .build()
23
- )
24
-
25
- override fun callback(frame: Frame, arguments: Map<String, Any>?): Any {
26
- return try {
27
- val results = mutableMapOf<String, Any>()
28
-
29
- // Convert frame to InputImage
30
- val image = InputImage.fromMediaImage(frame.image, frame.imageRotationDegrees)
31
-
32
- // Process face detection synchronously
33
- val task = faceDetector.process(image)
34
-
35
- // Wait for result (this blocks the thread but that's OK for frame processors)
36
- val faces = try {
37
- // For simplicity, we'll use a blocking approach
38
- // In production, you might want to handle this differently
39
- while (!task.isComplete && !task.isCanceled) {
40
- Thread.sleep(1)
41
- }
42
-
43
- if (task.isSuccessful) {
44
- task.result
45
- } else {
46
- emptyList()
47
- }
48
- } catch (e: Exception) {
49
- Log.e("FaceVerification", "Face detection failed: ${e.message}")
50
- results["error"] = e.message ?: "Face detection failed"
51
- return results
52
- }
53
-
54
- if (faces.isEmpty()) {
55
- results["faceDetected"] = false
56
- return results
57
- }
58
-
59
- // Process first detected face
60
- val face = faces[0]
61
- results["faceDetected"] = true
62
-
63
- // Face bounding box
64
- results["boundingBox"] = mapOf(
65
- "left" to face.boundingBox.left,
66
- "top" to face.boundingBox.top,
67
- "right" to face.boundingBox.right,
68
- "bottom" to face.boundingBox.bottom
69
- )
70
-
71
- // Smile detection
72
- face.smilingProbability?.let { smilingProbability ->
73
- results["isSmiling"] = smilingProbability > 0.7f
74
- results["smileProbability"] = smilingProbability
75
- }
76
-
77
- // Eye detection (for blinking)
78
- val leftEyeOpenProbability = face.leftEyeOpenProbability
79
- val rightEyeOpenProbability = face.rightEyeOpenProbability
80
-
81
- if (leftEyeOpenProbability != null && rightEyeOpenProbability != null) {
82
- val leftEyeClosed = leftEyeOpenProbability < 0.3f
83
- val rightEyeClosed = rightEyeOpenProbability < 0.3f
84
-
85
- results["leftEyeClosed"] = leftEyeClosed
86
- results["rightEyeClosed"] = rightEyeClosed
87
- results["isBlinking"] = leftEyeClosed && rightEyeClosed
88
- results["leftEyeOpenProbability"] = leftEyeOpenProbability
89
- results["rightEyeOpenProbability"] = rightEyeOpenProbability
90
- }
91
-
92
- // Head pose detection
93
- results["headPose"] = mapOf(
94
- "yaw" to face.headEulerAngleY, // Left-right movement
95
- "pitch" to face.headEulerAngleX, // Up-down movement
96
- "roll" to face.headEulerAngleZ // Tilt movement
97
- )
98
-
99
- // Face tracking ID (useful for consistency across frames)
100
- face.trackingId?.let { trackingId ->
101
- results["trackingId"] = trackingId
102
- }
103
-
104
- results
105
-
106
- } catch (e: Exception) {
107
- Log.e("FaceVerification", "Unexpected error: ${e.message}")
108
- mapOf("error" to (e.message ?: "Unknown error occurred"))
109
- }
110
- }
111
- }
@@ -1,138 +0,0 @@
1
- import VisionCamera
2
- import Vision
3
- import AVFoundation
4
-
5
- @objc(FaceVerificationFrameProcessor)
6
- public class FaceVerificationFrameProcessor: FrameProcessorPlugin {
7
-
8
- public override init(proxy: VisionCameraProxyHolder, options: [AnyHashable : Any]! = [:]) {
9
- super.init(proxy: proxy, options: options)
10
- }
11
-
12
- public override func callback(_ frame: Frame, withArguments arguments: [AnyHashable : Any]?) -> Any {
13
- let buffer = frame.buffer
14
- guard let imageBuffer = CMSampleBufferGetImageBuffer(buffer) else {
15
- return ["error": "Failed to get image buffer"]
16
- }
17
-
18
- return performFaceDetection(on: imageBuffer)
19
- }
20
-
21
- private func performFaceDetection(on imageBuffer: CVImageBuffer) -> [String: Any] {
22
- let request = VNDetectFaceLandmarksRequest()
23
- let handler = VNImageRequestHandler(cvPixelBuffer: imageBuffer, options: [:])
24
-
25
- do {
26
- try handler.perform([request])
27
-
28
- guard let observations = request.results as? [VNFaceObservation],
29
- let face = observations.first else {
30
- return ["faceDetected": false]
31
- }
32
-
33
- var results: [String: Any] = [
34
- "faceDetected": true,
35
- "boundingBox": [
36
- "x": face.boundingBox.origin.x,
37
- "y": face.boundingBox.origin.y,
38
- "width": face.boundingBox.size.width,
39
- "height": face.boundingBox.size.height
40
- ]
41
- ]
42
-
43
- // Analyze facial features
44
- if let landmarks = face.landmarks {
45
- results = analyzeFacialFeatures(landmarks: landmarks, results: results)
46
- }
47
-
48
- // Calculate head pose
49
- if let pose = calculateHeadPose(face: face) {
50
- results["headPose"] = pose
51
- }
52
-
53
- return results
54
-
55
- } catch {
56
- return ["error": error.localizedDescription]
57
- }
58
- }
59
-
60
- private func analyzeFacialFeatures(landmarks: VNFaceLandmarks2D, results: [String: Any]) -> [String: Any] {
61
- var updatedResults = results
62
-
63
- // Detect smile
64
- if let mouth = landmarks.outerLips {
65
- let isSmiling = detectSmile(mouthPoints: mouth.normalizedPoints)
66
- updatedResults["isSmiling"] = isSmiling
67
- }
68
-
69
- // Detect blinks
70
- if let leftEye = landmarks.leftEye, let rightEye = landmarks.rightEye {
71
- let leftEyeClosed = detectEyeClosure(eyePoints: leftEye.normalizedPoints)
72
- let rightEyeClosed = detectEyeClosure(eyePoints: rightEye.normalizedPoints)
73
-
74
- updatedResults["leftEyeClosed"] = leftEyeClosed
75
- updatedResults["rightEyeClosed"] = rightEyeClosed
76
- updatedResults["isBlinking"] = leftEyeClosed && rightEyeClosed
77
- }
78
-
79
- return updatedResults
80
- }
81
-
82
- private func detectSmile(mouthPoints: [CGPoint]) -> Bool {
83
- guard mouthPoints.count >= 6 else { return false }
84
-
85
- // Calculate mouth corner heights vs center
86
- let leftCorner = mouthPoints[0]
87
- let rightCorner = mouthPoints[3]
88
- let topCenter = mouthPoints[1]
89
- let bottomCenter = mouthPoints[4]
90
-
91
- let cornerHeight = (leftCorner.y + rightCorner.y) / 2
92
- let centerHeight = (topCenter.y + bottomCenter.y) / 2
93
-
94
- // Smile detection: corners higher than center
95
- return cornerHeight < centerHeight - 0.01
96
- }
97
-
98
- private func detectEyeClosure(eyePoints: [CGPoint]) -> Bool {
99
- guard eyePoints.count >= 6 else { return false }
100
-
101
- // Calculate eye aspect ratio
102
- let topPoints = Array(eyePoints[1...2])
103
- let bottomPoints = Array(eyePoints[4...5])
104
- let leftPoint = eyePoints[0]
105
- let rightPoint = eyePoints[3]
106
-
107
- let verticalDist1 = distance(topPoints[0], bottomPoints[0])
108
- let verticalDist2 = distance(topPoints[1], bottomPoints[1])
109
- let horizontalDist = distance(leftPoint, rightPoint)
110
-
111
- let eyeAspectRatio = (verticalDist1 + verticalDist2) / (2.0 * horizontalDist)
112
-
113
- // Eye is closed if aspect ratio is below threshold
114
- return eyeAspectRatio < 0.2
115
- }
116
-
117
- private func calculateHeadPose(face: VNFaceObservation) -> [String: Double]? {
118
- guard let yaw = face.yaw, let pitch = face.pitch, let roll = face.roll else {
119
- return nil
120
- }
121
-
122
- let yawDegrees = Double(truncating: yaw) * 180.0 / Double.pi
123
- let pitchDegrees = Double(truncating: pitch) * 180.0 / Double.pi
124
- let rollDegrees = Double(truncating: roll) * 180.0 / Double.pi
125
-
126
- return [
127
- "yaw": yawDegrees, // Left-right head movement
128
- "pitch": pitchDegrees, // Up-down head movement
129
- "roll": rollDegrees // Head tilt
130
- ]
131
- }
132
-
133
- private func distance(_ point1: CGPoint, _ point2: CGPoint) -> Double {
134
- let dx = point1.x - point2.x
135
- let dy = point1.y - point2.y
136
- return sqrt(Double(dx * dx + dy * dy))
137
- }
138
- }
@@ -1,10 +0,0 @@
1
- #import <VisionCamera/FrameProcessorPlugin.h>
2
- #import <VisionCamera/FrameProcessorPluginRegistry.h>
3
-
4
- #if __has_include("omnipay_reactnative_sdk/omnipay_reactnative_sdk-Swift.h")
5
- #import "omnipay_reactnative_sdk/omnipay_reactnative_sdk-Swift.h"
6
- #else
7
- #import "omnipay_reactnative_sdk-Swift.h"
8
- #endif
9
-
10
- VISION_EXPORT_SWIFT_FRAME_PROCESSOR(FaceVerificationFrameProcessor, detectFaces)
@@ -1,5 +0,0 @@
1
- #import <React/RCTBridgeModule.h>
2
-
3
- @interface RCT_EXTERN_MODULE(OmnipayReactnativeSdk, NSObject)
4
-
5
- @end
@@ -1,10 +0,0 @@
1
- import Foundation
2
-
3
- @objc(OmnipayReactnativeSdk)
4
- class OmnipayReactnativeSdk: NSObject {
5
-
6
- @objc static func requiresMainQueueSetup() -> Bool {
7
- return false
8
- }
9
-
10
- }
@@ -1,8 +0,0 @@
1
- //
2
- // Use this file to import your target's public headers that you would like to expose to Swift.
3
- //
4
-
5
- #import <React/RCTBridgeModule.h>
6
- #import <VisionCamera/FrameProcessorPlugin.h>
7
- #import <VisionCamera/FrameProcessorPluginRegistry.h>
8
- #import <VisionCamera/Frame.h>
@@ -1,6 +0,0 @@
1
- #ifndef omnipay_reactnative_sdk_h
2
- #define omnipay_reactnative_sdk_h
3
-
4
- #import <React/RCTBridgeModule.h>
5
-
6
- #endif /* omnipay_reactnative_sdk_h */
@@ -1,68 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
8
- var _reactNative = require("react-native");
9
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
- const Button = ({
11
- title,
12
- onPress,
13
- backgroundColor = '#007AFF',
14
- borderColor,
15
- textColor = 'white',
16
- disabled = false,
17
- loading = false,
18
- style,
19
- textStyle,
20
- activeOpacity = 0.8
21
- }) => {
22
- const buttonStyle = {
23
- ...styles.button,
24
- backgroundColor: disabled ? '#cccccc' : backgroundColor,
25
- borderColor: disabled ? '#cccccc' : borderColor || backgroundColor,
26
- ...style
27
- };
28
- const finalTextStyle = {
29
- ...styles.buttonText,
30
- color: disabled ? '#666666' : textColor,
31
- ...textStyle
32
- };
33
- return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
34
- style: buttonStyle,
35
- onPress: onPress,
36
- disabled: disabled || loading,
37
- activeOpacity: activeOpacity,
38
- accessibilityRole: "button",
39
- accessibilityLabel: title,
40
- accessibilityState: {
41
- disabled: disabled || loading
42
- }
43
- }, loading ? /*#__PURE__*/_react.default.createElement(_reactNative.ActivityIndicator, {
44
- color: textColor,
45
- size: "small"
46
- }) : /*#__PURE__*/_react.default.createElement(_reactNative.Text, {
47
- style: finalTextStyle
48
- }, title));
49
- };
50
- const styles = _reactNative.StyleSheet.create({
51
- button: {
52
- borderRadius: 6,
53
- paddingHorizontal: 12,
54
- paddingVertical: 14,
55
- borderWidth: 1,
56
- alignItems: 'center',
57
- justifyContent: 'center',
58
- minHeight: 48
59
- },
60
- buttonText: {
61
- color: 'white',
62
- fontSize: 16,
63
- fontWeight: '600',
64
- paddingHorizontal: 30
65
- }
66
- });
67
- var _default = exports.default = Button;
68
- //# sourceMappingURL=Button.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","Button","title","onPress","backgroundColor","borderColor","textColor","disabled","loading","style","textStyle","activeOpacity","buttonStyle","styles","button","finalTextStyle","buttonText","color","createElement","TouchableOpacity","accessibilityRole","accessibilityLabel","accessibilityState","ActivityIndicator","size","Text","StyleSheet","create","borderRadius","paddingHorizontal","paddingVertical","borderWidth","alignItems","justifyContent","minHeight","fontSize","fontWeight","_default","exports"],"sourceRoot":"../../../src","sources":["components/Button.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAOsB,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAetB,MAAMG,MAA6B,GAAGA,CAAC;EACrCC,KAAK;EACLC,OAAO;EACPC,eAAe,GAAG,SAAS;EAC3BC,WAAW;EACXC,SAAS,GAAG,OAAO;EACnBC,QAAQ,GAAG,KAAK;EAChBC,OAAO,GAAG,KAAK;EACfC,KAAK;EACLC,SAAS;EACTC,aAAa,GAAG;AAClB,CAAC,KAAK;EACJ,MAAMC,WAAsB,GAAG;IAC7B,GAAGC,MAAM,CAACC,MAAM;IAChBV,eAAe,EAAEG,QAAQ,GAAG,SAAS,GAAGH,eAAe;IACvDC,WAAW,EAAEE,QAAQ,GAAG,SAAS,GAAGF,WAAW,IAAID,eAAe;IAClE,GAAGK;EACL,CAAC;EAED,MAAMM,cAAyB,GAAG;IAChC,GAAGF,MAAM,CAACG,UAAU;IACpBC,KAAK,EAAEV,QAAQ,GAAG,SAAS,GAAGD,SAAS;IACvC,GAAGI;EACL,CAAC;EAED,oBACEhB,MAAA,CAAAM,OAAA,CAAAkB,aAAA,CAACrB,YAAA,CAAAsB,gBAAgB;IACfV,KAAK,EAAEG,WAAY;IACnBT,OAAO,EAAEA,OAAQ;IACjBI,QAAQ,EAAEA,QAAQ,IAAIC,OAAQ;IAC9BG,aAAa,EAAEA,aAAc;IAC7BS,iBAAiB,EAAC,QAAQ;IAC1BC,kBAAkB,EAAEnB,KAAM;IAC1BoB,kBAAkB,EAAE;MAAEf,QAAQ,EAAEA,QAAQ,IAAIC;IAAQ;EAAE,GAErDA,OAAO,gBACNd,MAAA,CAAAM,OAAA,CAAAkB,aAAA,CAACrB,YAAA,CAAA0B,iBAAiB;IAACN,KAAK,EAAEX,SAAU;IAACkB,IAAI,EAAC;EAAO,CAAE,CAAC,gBAEpD9B,MAAA,CAAAM,OAAA,CAAAkB,aAAA,CAACrB,YAAA,CAAA4B,IAAI;IAAChB,KAAK,EAAEM;EAAe,GAAEb,KAAY,CAE5B,CAAC;AAEvB,CAAC;AAED,MAAMW,MAAM,GAAGa,uBAAU,CAACC,MAAM,CAAC;EAC/Bb,MAAM,EAAE;IACNc,YAAY,EAAE,CAAC;IACfC,iBAAiB,EAAE,EAAE;IACrBC,eAAe,EAAE,EAAE;IACnBC,WAAW,EAAE,CAAC;IACdC,UAAU,EAAE,QAAQ;IACpBC,cAAc,EAAE,QAAQ;IACxBC,SAAS,EAAE;EACb,CAAC;EACDlB,UAAU,EAAE;IACVC,KAAK,EAAE,OAAO;IACdkB,QAAQ,EAAE,EAAE;IACZC,UAAU,EAAE,KAAK;IACjBP,iBAAiB,EAAE;EACrB;AACF,CAAC,CAAC;AAAC,IAAAQ,QAAA,GAAAC,OAAA,CAAAtC,OAAA,GAEYC,MAAM","ignoreList":[]}