@hexar/biometric-identity-sdk-react-native 1.1.25 → 1.1.27
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ProfilePictureCapture.d.ts","sourceRoot":"","sources":["../../src/components/ProfilePictureCapture.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAUxE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAmC,cAAc,EAAsB,MAAM,oCAAoC,CAAC;AAGzJ,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,UAAU,EAAE,CAAC,MAAM,EAAE,8BAA8B,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAkUtE,CAAC;AAsEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -44,6 +44,10 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
44
44
|
const [isValidating, setIsValidating] = (0, react_1.useState)(false);
|
|
45
45
|
const [currentChallenges, setCurrentChallenges] = (0, react_1.useState)([]);
|
|
46
46
|
const [isLoadingChallenges, setIsLoadingChallenges] = (0, react_1.useState)(false);
|
|
47
|
+
const animatedProgress = (0, react_1.useRef)(new react_native_1.Animated.Value(0)).current;
|
|
48
|
+
const [displayProgress, setDisplayProgress] = (0, react_1.useState)(0);
|
|
49
|
+
const animationRef = (0, react_1.useRef)(null);
|
|
50
|
+
const hasStartedAnimation = (0, react_1.useRef)(false);
|
|
47
51
|
const handleFetchChallenges = (0, react_1.useCallback)(async () => {
|
|
48
52
|
return await fetchChallenges('active');
|
|
49
53
|
}, [fetchChallenges]);
|
|
@@ -139,6 +143,40 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
139
143
|
throw error;
|
|
140
144
|
}
|
|
141
145
|
}, [isInitialized, isUsingBackend, sdk]);
|
|
146
|
+
// Handle progress animation during validation
|
|
147
|
+
(0, react_1.useEffect)(() => {
|
|
148
|
+
if (isValidating && !hasStartedAnimation.current) {
|
|
149
|
+
hasStartedAnimation.current = true;
|
|
150
|
+
animatedProgress.setValue(0);
|
|
151
|
+
setDisplayProgress(0);
|
|
152
|
+
// Start animation to 90% over 60 seconds
|
|
153
|
+
animationRef.current = react_native_1.Animated.timing(animatedProgress, {
|
|
154
|
+
toValue: 90,
|
|
155
|
+
duration: 60000, // 60 seconds
|
|
156
|
+
useNativeDriver: false,
|
|
157
|
+
});
|
|
158
|
+
animationRef.current.start();
|
|
159
|
+
// Update display value
|
|
160
|
+
const listener = animatedProgress.addListener(({ value }) => {
|
|
161
|
+
setDisplayProgress(Math.round(value));
|
|
162
|
+
});
|
|
163
|
+
return () => {
|
|
164
|
+
animatedProgress.removeListener(listener);
|
|
165
|
+
if (animationRef.current) {
|
|
166
|
+
animationRef.current.stop();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
else if (!isValidating && hasStartedAnimation.current) {
|
|
171
|
+
// Reset when validation ends
|
|
172
|
+
hasStartedAnimation.current = false;
|
|
173
|
+
if (animationRef.current) {
|
|
174
|
+
animationRef.current.stop();
|
|
175
|
+
}
|
|
176
|
+
animatedProgress.setValue(0);
|
|
177
|
+
setDisplayProgress(0);
|
|
178
|
+
}
|
|
179
|
+
}, [isValidating, animatedProgress]);
|
|
142
180
|
const handleVideoComplete = (0, react_1.useCallback)(async (videoResult) => {
|
|
143
181
|
biometric_identity_sdk_core_1.logger.info('ProfilePictureCapture: Video recording completed', {
|
|
144
182
|
framesCount: videoResult.frames?.length || 0,
|
|
@@ -150,7 +188,22 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
150
188
|
setIsValidating(true);
|
|
151
189
|
try {
|
|
152
190
|
const result = await validateWithBackend(videoResult);
|
|
191
|
+
if (animationRef.current) {
|
|
192
|
+
animationRef.current.stop();
|
|
193
|
+
}
|
|
194
|
+
react_native_1.Animated.timing(animatedProgress, {
|
|
195
|
+
toValue: 100,
|
|
196
|
+
duration: 500,
|
|
197
|
+
useNativeDriver: false,
|
|
198
|
+
}).start(() => {
|
|
199
|
+
setDisplayProgress(100);
|
|
200
|
+
});
|
|
201
|
+
// Small delay to show 100% before completing
|
|
202
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
153
203
|
if (!result.isValid) {
|
|
204
|
+
if (animationRef.current) {
|
|
205
|
+
animationRef.current.stop();
|
|
206
|
+
}
|
|
154
207
|
setIsValidating(false);
|
|
155
208
|
const livenessError = {
|
|
156
209
|
name: 'BiometricError',
|
|
@@ -164,6 +217,10 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
164
217
|
onComplete(result);
|
|
165
218
|
}
|
|
166
219
|
catch (error) {
|
|
220
|
+
// Stop animation on error
|
|
221
|
+
if (animationRef.current) {
|
|
222
|
+
animationRef.current.stop();
|
|
223
|
+
}
|
|
167
224
|
setIsValidating(false);
|
|
168
225
|
if (error && typeof error === 'object' && 'code' in error) {
|
|
169
226
|
onError(error);
|
|
@@ -190,18 +247,36 @@ const ProfilePictureCapture = ({ onComplete, onError, onCancel, theme, language,
|
|
|
190
247
|
};
|
|
191
248
|
onError(biometricError);
|
|
192
249
|
}
|
|
193
|
-
}, [validateWithBackend, onComplete, onError, strings, language, currentChallenges]);
|
|
250
|
+
}, [validateWithBackend, onComplete, onError, strings, language, currentChallenges, animatedProgress]);
|
|
194
251
|
const handleVideoCancel = (0, react_1.useCallback)(() => {
|
|
195
252
|
if (onCancel) {
|
|
196
253
|
onCancel();
|
|
197
254
|
}
|
|
198
255
|
}, [onCancel]);
|
|
199
256
|
if (isValidating) {
|
|
257
|
+
const progressWidth = animatedProgress.interpolate({
|
|
258
|
+
inputRange: [0, 100],
|
|
259
|
+
outputRange: ['0%', '100%'],
|
|
260
|
+
extrapolate: 'clamp',
|
|
261
|
+
});
|
|
200
262
|
return (react_1.default.createElement(react_native_1.SafeAreaView, { style: [styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }] },
|
|
201
|
-
react_1.default.createElement(react_native_1.View, { style: styles.
|
|
263
|
+
react_1.default.createElement(react_native_1.View, { style: styles.progressContainer },
|
|
202
264
|
react_1.default.createElement(react_native_1.ActivityIndicator, { size: "large", color: theme?.primaryColor || '#4f46e5' }),
|
|
203
|
-
react_1.default.createElement(react_native_1.Text, { style: [styles.
|
|
204
|
-
react_1.default.createElement(react_native_1.Text, { style: [styles.
|
|
265
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.progressTitle, { color: theme?.textColor || '#1e1b4b' }] }, strings.validation.title || strings.liveness.processing || strings.validation.checkingLiveness || 'Validating Profile Picture'),
|
|
266
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.progressStatusText, { color: theme?.secondaryTextColor || '#64748b' }] }, strings.validation.validatingFace || strings.liveness.processing || 'Validando rostro...'),
|
|
267
|
+
react_1.default.createElement(react_native_1.View, { style: styles.progressBarContainer },
|
|
268
|
+
react_1.default.createElement(react_native_1.View, { style: styles.progressBar },
|
|
269
|
+
react_1.default.createElement(react_native_1.Animated.View, { style: [
|
|
270
|
+
styles.progressFill,
|
|
271
|
+
{
|
|
272
|
+
width: progressWidth,
|
|
273
|
+
backgroundColor: theme?.primaryColor || '#4f46e5',
|
|
274
|
+
},
|
|
275
|
+
] })),
|
|
276
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.progressText, { color: theme?.textColor || '#1e1b4b' }] },
|
|
277
|
+
displayProgress,
|
|
278
|
+
"%")),
|
|
279
|
+
react_1.default.createElement(react_native_1.Text, { style: [styles.progressBottomText, { color: theme?.secondaryTextColor || '#64748b' }] }, strings.validation.almostDone || strings.common.loading || 'Esto puede tardar unos segundos...'))));
|
|
205
280
|
}
|
|
206
281
|
// Wait for initialization and challenge loading before showing VideoRecorder
|
|
207
282
|
if (!isInitialized || (isUsingBackend && isLoadingChallenges)) {
|
|
@@ -233,5 +308,51 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
233
308
|
fontSize: 14,
|
|
234
309
|
marginTop: 8,
|
|
235
310
|
},
|
|
311
|
+
progressContainer: {
|
|
312
|
+
flex: 1,
|
|
313
|
+
justifyContent: 'center',
|
|
314
|
+
alignItems: 'center',
|
|
315
|
+
padding: 24,
|
|
316
|
+
width: '85%',
|
|
317
|
+
alignSelf: 'center',
|
|
318
|
+
},
|
|
319
|
+
progressTitle: {
|
|
320
|
+
fontSize: 24,
|
|
321
|
+
fontWeight: 'bold',
|
|
322
|
+
marginTop: 24,
|
|
323
|
+
marginBottom: 8,
|
|
324
|
+
textAlign: 'center',
|
|
325
|
+
},
|
|
326
|
+
progressStatusText: {
|
|
327
|
+
fontSize: 16,
|
|
328
|
+
marginBottom: 32,
|
|
329
|
+
textAlign: 'center',
|
|
330
|
+
},
|
|
331
|
+
progressBarContainer: {
|
|
332
|
+
width: '100%',
|
|
333
|
+
marginBottom: 24,
|
|
334
|
+
},
|
|
335
|
+
progressBar: {
|
|
336
|
+
width: '100%',
|
|
337
|
+
height: 8,
|
|
338
|
+
backgroundColor: '#E5E7EB',
|
|
339
|
+
borderRadius: 4,
|
|
340
|
+
overflow: 'hidden',
|
|
341
|
+
marginBottom: 8,
|
|
342
|
+
},
|
|
343
|
+
progressFill: {
|
|
344
|
+
height: '100%',
|
|
345
|
+
borderRadius: 4,
|
|
346
|
+
},
|
|
347
|
+
progressText: {
|
|
348
|
+
fontSize: 14,
|
|
349
|
+
fontWeight: '600',
|
|
350
|
+
textAlign: 'center',
|
|
351
|
+
},
|
|
352
|
+
progressBottomText: {
|
|
353
|
+
fontSize: 14,
|
|
354
|
+
textAlign: 'center',
|
|
355
|
+
marginTop: 16,
|
|
356
|
+
},
|
|
236
357
|
});
|
|
237
358
|
exports.default = exports.ProfilePictureCapture;
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
StyleSheet,
|
|
6
6
|
ActivityIndicator,
|
|
7
7
|
SafeAreaView,
|
|
8
|
+
Animated,
|
|
8
9
|
} from 'react-native';
|
|
9
10
|
import { VideoRecorder, VideoRecordingResult } from './VideoRecorder';
|
|
10
11
|
import { ThemeConfig, SupportedLanguage, getStrings, setLanguage, logger, BiometricError, BiometricErrorCode } from '@hexar/biometric-identity-sdk-core';
|
|
@@ -44,6 +45,10 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
44
45
|
const [isValidating, setIsValidating] = useState(false);
|
|
45
46
|
const [currentChallenges, setCurrentChallenges] = useState<any[]>([]);
|
|
46
47
|
const [isLoadingChallenges, setIsLoadingChallenges] = useState(false);
|
|
48
|
+
const animatedProgress = useRef(new Animated.Value(0)).current;
|
|
49
|
+
const [displayProgress, setDisplayProgress] = useState(0);
|
|
50
|
+
const animationRef = useRef<Animated.CompositeAnimation | null>(null);
|
|
51
|
+
const hasStartedAnimation = useRef(false);
|
|
47
52
|
|
|
48
53
|
const handleFetchChallenges = useCallback(async () => {
|
|
49
54
|
return await fetchChallenges('active');
|
|
@@ -149,6 +154,44 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
149
154
|
}
|
|
150
155
|
}, [isInitialized, isUsingBackend, sdk]);
|
|
151
156
|
|
|
157
|
+
// Handle progress animation during validation
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
if (isValidating && !hasStartedAnimation.current) {
|
|
160
|
+
hasStartedAnimation.current = true;
|
|
161
|
+
animatedProgress.setValue(0);
|
|
162
|
+
setDisplayProgress(0);
|
|
163
|
+
|
|
164
|
+
// Start animation to 90% over 60 seconds
|
|
165
|
+
animationRef.current = Animated.timing(animatedProgress, {
|
|
166
|
+
toValue: 90,
|
|
167
|
+
duration: 60000, // 60 seconds
|
|
168
|
+
useNativeDriver: false,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
animationRef.current.start();
|
|
172
|
+
|
|
173
|
+
// Update display value
|
|
174
|
+
const listener = animatedProgress.addListener(({ value }) => {
|
|
175
|
+
setDisplayProgress(Math.round(value));
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return () => {
|
|
179
|
+
animatedProgress.removeListener(listener);
|
|
180
|
+
if (animationRef.current) {
|
|
181
|
+
animationRef.current.stop();
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
} else if (!isValidating && hasStartedAnimation.current) {
|
|
185
|
+
// Reset when validation ends
|
|
186
|
+
hasStartedAnimation.current = false;
|
|
187
|
+
if (animationRef.current) {
|
|
188
|
+
animationRef.current.stop();
|
|
189
|
+
}
|
|
190
|
+
animatedProgress.setValue(0);
|
|
191
|
+
setDisplayProgress(0);
|
|
192
|
+
}
|
|
193
|
+
}, [isValidating, animatedProgress]);
|
|
194
|
+
|
|
152
195
|
const handleVideoComplete = useCallback(async (videoResult: VideoRecordingResult) => {
|
|
153
196
|
logger.info('ProfilePictureCapture: Video recording completed', {
|
|
154
197
|
framesCount: videoResult.frames?.length || 0,
|
|
@@ -163,7 +206,24 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
163
206
|
try {
|
|
164
207
|
const result = await validateWithBackend(videoResult);
|
|
165
208
|
|
|
209
|
+
if (animationRef.current) {
|
|
210
|
+
animationRef.current.stop();
|
|
211
|
+
}
|
|
212
|
+
Animated.timing(animatedProgress, {
|
|
213
|
+
toValue: 100,
|
|
214
|
+
duration: 500,
|
|
215
|
+
useNativeDriver: false,
|
|
216
|
+
}).start(() => {
|
|
217
|
+
setDisplayProgress(100);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Small delay to show 100% before completing
|
|
221
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
222
|
+
|
|
166
223
|
if (!result.isValid) {
|
|
224
|
+
if (animationRef.current) {
|
|
225
|
+
animationRef.current.stop();
|
|
226
|
+
}
|
|
167
227
|
setIsValidating(false);
|
|
168
228
|
const livenessError: BiometricError = {
|
|
169
229
|
name: 'BiometricError',
|
|
@@ -177,6 +237,10 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
177
237
|
setIsValidating(false);
|
|
178
238
|
onComplete(result);
|
|
179
239
|
} catch (error: any) {
|
|
240
|
+
// Stop animation on error
|
|
241
|
+
if (animationRef.current) {
|
|
242
|
+
animationRef.current.stop();
|
|
243
|
+
}
|
|
180
244
|
setIsValidating(false);
|
|
181
245
|
|
|
182
246
|
if (error && typeof error === 'object' && 'code' in error) {
|
|
@@ -205,7 +269,7 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
205
269
|
} as BiometricError;
|
|
206
270
|
onError(biometricError);
|
|
207
271
|
}
|
|
208
|
-
}, [validateWithBackend, onComplete, onError, strings, language, currentChallenges]);
|
|
272
|
+
}, [validateWithBackend, onComplete, onError, strings, language, currentChallenges, animatedProgress]);
|
|
209
273
|
|
|
210
274
|
const handleVideoCancel = useCallback(() => {
|
|
211
275
|
if (onCancel) {
|
|
@@ -214,15 +278,45 @@ export const ProfilePictureCapture: React.FC<ProfilePictureCaptureProps> = ({
|
|
|
214
278
|
}, [onCancel]);
|
|
215
279
|
|
|
216
280
|
if (isValidating) {
|
|
281
|
+
const progressWidth = animatedProgress.interpolate({
|
|
282
|
+
inputRange: [0, 100],
|
|
283
|
+
outputRange: ['0%', '100%'],
|
|
284
|
+
extrapolate: 'clamp',
|
|
285
|
+
});
|
|
286
|
+
|
|
217
287
|
return (
|
|
218
288
|
<SafeAreaView style={[styles.container, { backgroundColor: theme?.backgroundColor || '#FFFFFF' }]}>
|
|
219
|
-
<View style={styles.
|
|
289
|
+
<View style={styles.progressContainer}>
|
|
220
290
|
<ActivityIndicator size="large" color={theme?.primaryColor || '#4f46e5'} />
|
|
221
|
-
|
|
222
|
-
|
|
291
|
+
|
|
292
|
+
<Text style={[styles.progressTitle, { color: theme?.textColor || '#1e1b4b' }]}>
|
|
293
|
+
{strings.validation.title || strings.liveness.processing || strings.validation.checkingLiveness || 'Validating Profile Picture'}
|
|
294
|
+
</Text>
|
|
295
|
+
|
|
296
|
+
<Text style={[styles.progressStatusText, { color: theme?.secondaryTextColor || '#64748b' }]}>
|
|
297
|
+
{(strings.validation as any).validatingFace || strings.liveness.processing || 'Validando rostro...'}
|
|
223
298
|
</Text>
|
|
224
|
-
|
|
225
|
-
|
|
299
|
+
|
|
300
|
+
{/* Progress Bar */}
|
|
301
|
+
<View style={styles.progressBarContainer}>
|
|
302
|
+
<View style={styles.progressBar}>
|
|
303
|
+
<Animated.View
|
|
304
|
+
style={[
|
|
305
|
+
styles.progressFill,
|
|
306
|
+
{
|
|
307
|
+
width: progressWidth,
|
|
308
|
+
backgroundColor: theme?.primaryColor || '#4f46e5',
|
|
309
|
+
},
|
|
310
|
+
]}
|
|
311
|
+
/>
|
|
312
|
+
</View>
|
|
313
|
+
<Text style={[styles.progressText, { color: theme?.textColor || '#1e1b4b' }]}>
|
|
314
|
+
{displayProgress}%
|
|
315
|
+
</Text>
|
|
316
|
+
</View>
|
|
317
|
+
|
|
318
|
+
<Text style={[styles.progressBottomText, { color: theme?.secondaryTextColor || '#64748b' }]}>
|
|
319
|
+
{strings.validation.almostDone || strings.common.loading || 'Esto puede tardar unos segundos...'}
|
|
226
320
|
</Text>
|
|
227
321
|
</View>
|
|
228
322
|
</SafeAreaView>
|
|
@@ -277,6 +371,52 @@ const styles = StyleSheet.create({
|
|
|
277
371
|
fontSize: 14,
|
|
278
372
|
marginTop: 8,
|
|
279
373
|
},
|
|
374
|
+
progressContainer: {
|
|
375
|
+
flex: 1,
|
|
376
|
+
justifyContent: 'center',
|
|
377
|
+
alignItems: 'center',
|
|
378
|
+
padding: 24,
|
|
379
|
+
width: '85%',
|
|
380
|
+
alignSelf: 'center',
|
|
381
|
+
},
|
|
382
|
+
progressTitle: {
|
|
383
|
+
fontSize: 24,
|
|
384
|
+
fontWeight: 'bold',
|
|
385
|
+
marginTop: 24,
|
|
386
|
+
marginBottom: 8,
|
|
387
|
+
textAlign: 'center',
|
|
388
|
+
},
|
|
389
|
+
progressStatusText: {
|
|
390
|
+
fontSize: 16,
|
|
391
|
+
marginBottom: 32,
|
|
392
|
+
textAlign: 'center',
|
|
393
|
+
},
|
|
394
|
+
progressBarContainer: {
|
|
395
|
+
width: '100%',
|
|
396
|
+
marginBottom: 24,
|
|
397
|
+
},
|
|
398
|
+
progressBar: {
|
|
399
|
+
width: '100%',
|
|
400
|
+
height: 8,
|
|
401
|
+
backgroundColor: '#E5E7EB',
|
|
402
|
+
borderRadius: 4,
|
|
403
|
+
overflow: 'hidden',
|
|
404
|
+
marginBottom: 8,
|
|
405
|
+
},
|
|
406
|
+
progressFill: {
|
|
407
|
+
height: '100%',
|
|
408
|
+
borderRadius: 4,
|
|
409
|
+
},
|
|
410
|
+
progressText: {
|
|
411
|
+
fontSize: 14,
|
|
412
|
+
fontWeight: '600',
|
|
413
|
+
textAlign: 'center',
|
|
414
|
+
},
|
|
415
|
+
progressBottomText: {
|
|
416
|
+
fontSize: 14,
|
|
417
|
+
textAlign: 'center',
|
|
418
|
+
marginTop: 16,
|
|
419
|
+
},
|
|
280
420
|
});
|
|
281
421
|
|
|
282
422
|
export default ProfilePictureCapture;
|