react-native-biometric-verifier 0.0.10 → 0.0.11
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.
- package/package.json +1 -1
- package/src/components/Loader.js +108 -53
- package/src/components/styles.js +18 -0
- package/src/index.js +7 -6
- package/src/components/StateIndicator.js +0 -109
package/package.json
CHANGED
package/src/components/Loader.js
CHANGED
|
@@ -1,58 +1,113 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { Animated, Easing, View } from 'react-native';
|
|
3
|
+
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
4
|
+
import { ANIMATION_STATES, COLORS } from '../utils/constants';
|
|
5
|
+
import { styles } from './styles';
|
|
6
|
+
import FastImage from 'react-native-fast-image';
|
|
7
|
+
|
|
8
|
+
export const Loader = ({ state, source, isLoading = false }) => {
|
|
9
|
+
const spinValue = useRef(new Animated.Value(0)).current;
|
|
10
|
+
const pulseValue = useRef(new Animated.Value(1)).current;
|
|
11
|
+
const spinAnimation = useRef(null);
|
|
12
|
+
const pulseAnimation = useRef(null);
|
|
13
|
+
|
|
14
|
+
const size = 120; // Define the size constant
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
// Stop ongoing animations when state changes
|
|
18
|
+
spinAnimation.current?.stop();
|
|
19
|
+
pulseAnimation.current?.stop();
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
state === ANIMATION_STATES.PROCESSING ||
|
|
23
|
+
state === ANIMATION_STATES.FACE_SCAN ||
|
|
24
|
+
state === ANIMATION_STATES.QR_SCAN
|
|
25
|
+
) {
|
|
26
|
+
spinAnimation.current = Animated.loop(
|
|
27
|
+
Animated.timing(spinValue, {
|
|
28
|
+
toValue: 1,
|
|
29
|
+
duration: 1500,
|
|
30
|
+
easing: Easing.linear,
|
|
31
|
+
useNativeDriver: true,
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
spinAnimation.current.start();
|
|
35
|
+
}
|
|
36
|
+
else if (
|
|
37
|
+
state === ANIMATION_STATES.SUCCESS ||
|
|
38
|
+
state === ANIMATION_STATES.ERROR
|
|
39
|
+
) {
|
|
40
|
+
pulseAnimation.current = Animated.loop(
|
|
41
|
+
Animated.sequence([
|
|
42
|
+
Animated.timing(pulseValue, {
|
|
43
|
+
toValue: 1.1,
|
|
44
|
+
duration: 500,
|
|
45
|
+
useNativeDriver: true,
|
|
46
|
+
}),
|
|
47
|
+
Animated.timing(pulseValue, {
|
|
48
|
+
toValue: 1,
|
|
49
|
+
duration: 500,
|
|
50
|
+
useNativeDriver: true,
|
|
51
|
+
}),
|
|
52
|
+
]),
|
|
53
|
+
{ iterations: 2 }
|
|
54
|
+
);
|
|
55
|
+
pulseAnimation.current.start();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
spinValue.setValue(0);
|
|
59
|
+
pulseValue.setValue(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return () => {
|
|
63
|
+
spinAnimation.current?.stop();
|
|
64
|
+
pulseAnimation.current?.stop();
|
|
65
|
+
};
|
|
66
|
+
}, [state, spinValue, pulseValue]);
|
|
67
|
+
|
|
68
|
+
const getIcon = () => {
|
|
69
|
+
switch (state) {
|
|
70
|
+
case ANIMATION_STATES.FACE_SCAN:
|
|
71
|
+
return <Icon name="face" size={size * 0.5} color={COLORS.primary} />;
|
|
72
|
+
case ANIMATION_STATES.QR_SCAN:
|
|
73
|
+
return <Icon name="qr-code-scanner" size={size * 0.5} color={COLORS.primary} />;
|
|
74
|
+
case ANIMATION_STATES.PROCESSING:
|
|
75
|
+
return <Icon name="settings" size={size * 0.5} color={COLORS.info} />;
|
|
76
|
+
case ANIMATION_STATES.SUCCESS:
|
|
77
|
+
return <Icon name="check-circle" size={size * 0.5} color={COLORS.success} />;
|
|
78
|
+
case ANIMATION_STATES.ERROR:
|
|
79
|
+
return <Icon name="error" size={size * 0.5} color={COLORS.error} />;
|
|
80
|
+
default:
|
|
81
|
+
return <Icon name="hourglass-empty" size={size * 0.5} color={COLORS.gray} />;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
11
85
|
return (
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
86
|
+
<View style={styles.indicatorWrapper}>
|
|
87
|
+
<Animated.View
|
|
88
|
+
style={[
|
|
89
|
+
styles.indicatorContainer,
|
|
90
|
+
{
|
|
91
|
+
width: size,
|
|
92
|
+
height: size,
|
|
93
|
+
transform: [
|
|
94
|
+
{ scale: pulseValue },
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
]}
|
|
98
|
+
>
|
|
99
|
+
{isLoading && source ? (
|
|
20
100
|
<FastImage
|
|
21
|
-
style={styles.icon}
|
|
101
|
+
style={[styles.icon, { width: size * 0.8, height: size * 0.8 }]}
|
|
22
102
|
source={source}
|
|
103
|
+
resizeMode={FastImage.resizeMode.contain}
|
|
23
104
|
/>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
105
|
+
) : (
|
|
106
|
+
getIcon()
|
|
107
|
+
)}
|
|
108
|
+
</Animated.View>
|
|
109
|
+
</View>
|
|
27
110
|
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const styles = StyleSheet.create({
|
|
33
|
-
container: {
|
|
34
|
-
justifyContent: "center",
|
|
35
|
-
alignItems: "center",
|
|
36
|
-
height,
|
|
37
|
-
width,
|
|
38
|
-
backgroundColor: "rgba(0,0,0,0.3)", // semi-transparent backdrop
|
|
39
|
-
},
|
|
40
|
-
loaderBox: {
|
|
41
|
-
borderRadius: normalize(20),
|
|
42
|
-
padding: 10,
|
|
43
|
-
backgroundColor: "white",
|
|
44
|
-
borderWidth: 1,
|
|
45
|
-
borderColor: "lightblue",
|
|
46
|
-
elevation: 5, // shadow on Android
|
|
47
|
-
shadowColor: "#000", // shadow on iOS
|
|
48
|
-
shadowOpacity: 0.2,
|
|
49
|
-
shadowOffset: { width: 0, height: 2 },
|
|
50
|
-
shadowRadius: 4,
|
|
51
|
-
},
|
|
52
|
-
icon: {
|
|
53
|
-
height: normalize(70),
|
|
54
|
-
width: normalize(70),
|
|
55
|
-
justifyContent: "center",
|
|
56
|
-
alignItems: "center",
|
|
57
|
-
},
|
|
58
|
-
});
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export default Loader;
|
package/src/components/styles.js
CHANGED
|
@@ -179,4 +179,22 @@ export const styles = StyleSheet.create({
|
|
|
179
179
|
opacity: 0.8,
|
|
180
180
|
fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
|
|
181
181
|
},
|
|
182
|
+
capturedImageContainer: {
|
|
183
|
+
marginVertical: 15,
|
|
184
|
+
alignItems: 'center',
|
|
185
|
+
justifyContent: 'center',
|
|
186
|
+
},
|
|
187
|
+
capturedImage: {
|
|
188
|
+
width: 120,
|
|
189
|
+
height: 120,
|
|
190
|
+
borderRadius: 10,
|
|
191
|
+
borderWidth: 2,
|
|
192
|
+
borderColor: COLORS.primary,
|
|
193
|
+
},
|
|
194
|
+
capturedImageText: {
|
|
195
|
+
marginTop: 8,
|
|
196
|
+
fontSize: 14,
|
|
197
|
+
color: COLORS.light,
|
|
198
|
+
textAlign: 'center',
|
|
199
|
+
},
|
|
182
200
|
});
|
package/src/index.js
CHANGED
|
@@ -28,7 +28,6 @@ import Loader from "./components/Loader";
|
|
|
28
28
|
import { CountdownTimer } from "./components/CountdownTimer";
|
|
29
29
|
import { EmployeeCard } from "./components/EmployeeCard";
|
|
30
30
|
import { Notification } from "./components/Notification";
|
|
31
|
-
import { StateIndicator } from "./components/StateIndicator";
|
|
32
31
|
import { styles } from "./components/styles";
|
|
33
32
|
import { useNavigation } from "@react-navigation/native";
|
|
34
33
|
import networkServiceCall from "./utils/NetworkServiceCall";
|
|
@@ -342,8 +341,6 @@ const BiometricVerificationModal = React.memo(
|
|
|
342
341
|
<Text style={styles.title}>Biometric Verification</Text>
|
|
343
342
|
<Text style={styles.subTitle}>{state.currentStep}</Text>
|
|
344
343
|
|
|
345
|
-
<StateIndicator state={state.animationState} size={120} />
|
|
346
|
-
|
|
347
344
|
{state.employeeData && (
|
|
348
345
|
<EmployeeCard
|
|
349
346
|
employeeData={state.employeeData}
|
|
@@ -361,8 +358,12 @@ const BiometricVerificationModal = React.memo(
|
|
|
361
358
|
duration={COUNTDOWN_DURATION}
|
|
362
359
|
currentTime={countdown}
|
|
363
360
|
/>
|
|
364
|
-
|
|
365
|
-
|
|
361
|
+
|
|
362
|
+
<Loader
|
|
363
|
+
state={state.animationState}
|
|
364
|
+
source={loaderSource}
|
|
365
|
+
isLoading={state.isLoading}
|
|
366
|
+
/>
|
|
366
367
|
</View>
|
|
367
368
|
</Modal>
|
|
368
369
|
)}
|
|
@@ -371,4 +372,4 @@ const BiometricVerificationModal = React.memo(
|
|
|
371
372
|
}
|
|
372
373
|
);
|
|
373
374
|
|
|
374
|
-
export default BiometricVerificationModal;
|
|
375
|
+
export default BiometricVerificationModal;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { Animated, Easing } from 'react-native';
|
|
3
|
-
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
4
|
-
import { ANIMATION_STATES, COLORS } from '../utils/constants';
|
|
5
|
-
import { styles } from './styles';
|
|
6
|
-
|
|
7
|
-
export const StateIndicator = ({ state, size = 100 }) => {
|
|
8
|
-
const spinValue = useRef(new Animated.Value(0)).current;
|
|
9
|
-
const pulseValue = useRef(new Animated.Value(1)).current;
|
|
10
|
-
const spinAnimation = useRef(null);
|
|
11
|
-
const pulseAnimation = useRef(null);
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
// Stop ongoing animations when state changes
|
|
15
|
-
spinValue.stopAnimation();
|
|
16
|
-
pulseValue.stopAnimation();
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
state === ANIMATION_STATES.PROCESSING ||
|
|
20
|
-
state === ANIMATION_STATES.FACE_SCAN ||
|
|
21
|
-
state === ANIMATION_STATES.QR_SCAN
|
|
22
|
-
) {
|
|
23
|
-
spinAnimation.current = Animated.loop(
|
|
24
|
-
Animated.timing(spinValue, {
|
|
25
|
-
toValue: 1,
|
|
26
|
-
duration: 1500,
|
|
27
|
-
easing: Easing.linear,
|
|
28
|
-
useNativeDriver: true,
|
|
29
|
-
})
|
|
30
|
-
);
|
|
31
|
-
spinAnimation.current.start();
|
|
32
|
-
}
|
|
33
|
-
else if (
|
|
34
|
-
state === ANIMATION_STATES.SUCCESS ||
|
|
35
|
-
state === ANIMATION_STATES.ERROR
|
|
36
|
-
) {
|
|
37
|
-
pulseAnimation.current = Animated.loop(
|
|
38
|
-
Animated.sequence([
|
|
39
|
-
Animated.timing(pulseValue, {
|
|
40
|
-
toValue: 1.1,
|
|
41
|
-
duration: 500,
|
|
42
|
-
useNativeDriver: true,
|
|
43
|
-
}),
|
|
44
|
-
Animated.timing(pulseValue, {
|
|
45
|
-
toValue: 1,
|
|
46
|
-
duration: 500,
|
|
47
|
-
useNativeDriver: true,
|
|
48
|
-
}),
|
|
49
|
-
]),
|
|
50
|
-
{ iterations: 2 }
|
|
51
|
-
);
|
|
52
|
-
pulseAnimation.current.start();
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
spinValue.setValue(0);
|
|
56
|
-
pulseValue.setValue(1);
|
|
57
|
-
}
|
|
58
|
-
}, [state, spinValue, pulseValue]);
|
|
59
|
-
|
|
60
|
-
const spin = spinValue.interpolate({
|
|
61
|
-
inputRange: [0, 1],
|
|
62
|
-
outputRange: ['0deg', '360deg'],
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const getIcon = () => {
|
|
66
|
-
switch (state) {
|
|
67
|
-
case ANIMATION_STATES.FACE_SCAN:
|
|
68
|
-
return <Icon name="face" size={size * 0.5} color={COLORS.primary} />;
|
|
69
|
-
case ANIMATION_STATES.QR_SCAN:
|
|
70
|
-
return <Icon name="qr-code-scanner" size={size * 0.5} color={COLORS.primary} />;
|
|
71
|
-
case ANIMATION_STATES.PROCESSING:
|
|
72
|
-
return <Icon name="settings" size={size * 0.5} color={COLORS.info} />;
|
|
73
|
-
case ANIMATION_STATES.SUCCESS:
|
|
74
|
-
return <Icon name="check-circle" size={size * 0.5} color={COLORS.success} />;
|
|
75
|
-
case ANIMATION_STATES.ERROR:
|
|
76
|
-
return <Icon name="error" size={size * 0.5} color={COLORS.error} />;
|
|
77
|
-
default:
|
|
78
|
-
return <Icon name="hourglass-empty" size={size * 0.5} color={COLORS.gray} />;
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<Animated.View
|
|
84
|
-
style={[
|
|
85
|
-
styles.indicatorContainer,
|
|
86
|
-
{
|
|
87
|
-
width: size,
|
|
88
|
-
height: size,
|
|
89
|
-
transform: [
|
|
90
|
-
{ scale: pulseValue },
|
|
91
|
-
...(state === ANIMATION_STATES.PROCESSING ||
|
|
92
|
-
state === ANIMATION_STATES.FACE_SCAN ||
|
|
93
|
-
state === ANIMATION_STATES.QR_SCAN
|
|
94
|
-
? [{ rotate: spin }]
|
|
95
|
-
: []),
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
]}
|
|
99
|
-
>
|
|
100
|
-
{(state === ANIMATION_STATES.PROCESSING ||
|
|
101
|
-
state === ANIMATION_STATES.FACE_SCAN ||
|
|
102
|
-
state === ANIMATION_STATES.QR_SCAN) ? (
|
|
103
|
-
null
|
|
104
|
-
) : (
|
|
105
|
-
getIcon()
|
|
106
|
-
)}
|
|
107
|
-
</Animated.View>
|
|
108
|
-
);
|
|
109
|
-
};
|