@fto-consult/expo-ui 8.6.0 → 8.7.0
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/bin/create-app/dependencies.js +1 -0
- package/bin/create-app.js +11 -3
- package/package.json +1 -1
- package/src/components/BarcodeScanner/index.js +148 -0
- package/src/components/BarcodeScanner/index.web.js +3 -0
- package/src/components/Image/index.js +5 -3
- package/src/layouts/ProfilAvatar/index.js +1 -0
- package/src/media/index.js +2 -2
- package/src/media/utils.js +1 -1
package/bin/create-app.js
CHANGED
@@ -116,10 +116,13 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
|
|
116
116
|
"cameraPermission" : `Autoriser $(PRODUCT_NAME) à accéder à votre camera`
|
117
117
|
}, cameraPluginsOptions = {
|
118
118
|
"cameraPermission" : `Autoriser $(PRODUCT_NAME) à accéder à votre camera`
|
119
|
+
}, barCodePermission = {
|
120
|
+
"cameraPermission": "Autoriser $(PRODUCT_NAME) à accéder à la caméra."
|
119
121
|
};
|
120
122
|
const plugins = [
|
121
123
|
["expo-image-picker",imagePluginOptions],
|
122
|
-
["expo-camera",cameraPluginsOptions]
|
124
|
+
["expo-camera",cameraPluginsOptions],
|
125
|
+
["expo-barcode-scanner",barCodePermission]
|
123
126
|
];
|
124
127
|
appSheme = name? sanitizeFileName(name).replace(/ /g, '') : null;
|
125
128
|
const appJSONPath = path.join(projectRoot,"app.json");
|
@@ -176,14 +179,16 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
|
|
176
179
|
if(!Array.isArray(appPlugins)){
|
177
180
|
appPlugins = plugins;
|
178
181
|
} else {
|
179
|
-
let hasFoundCamera = false, hasFoundImagePicker = false;
|
182
|
+
let hasFoundCamera = false, hasFoundImagePicker = false,hasFoundBarCode = false;
|
180
183
|
appPlugins.map(pl=>{
|
181
184
|
if(Array.isArray(pl)){
|
182
185
|
if(typeof pl[0] ==="expo-image-picker"){
|
183
186
|
hasFoundImagePicker = true;
|
184
187
|
} else if(pl[0] === "expo-camera"){
|
185
188
|
hasFoundCamera = true;
|
186
|
-
}
|
189
|
+
} else if(pl[0] =="expo-barcode-scanner"){
|
190
|
+
hasFoundBarCode = true;
|
191
|
+
}
|
187
192
|
}
|
188
193
|
});
|
189
194
|
if(!hasFoundImagePicker){
|
@@ -192,6 +197,9 @@ const createAPPJSONFile = (projectRoot,{name,version})=>{
|
|
192
197
|
if(!hasFoundCamera){
|
193
198
|
appPlugins.push(plugins[1]);
|
194
199
|
}
|
200
|
+
if(!hasFoundBarCode){
|
201
|
+
appPlugins.push(plugins[2]);
|
202
|
+
}
|
195
203
|
}
|
196
204
|
appJSONManager.set({
|
197
205
|
expo : {plugins:appPlugins}
|
package/package.json
CHANGED
@@ -0,0 +1,148 @@
|
|
1
|
+
import React, { useState, useEffect,useMemo } from '$react';
|
2
|
+
import { View, StyleSheet} from 'react-native';
|
3
|
+
import { BarCodeScanner } from 'expo-barcode-scanner';
|
4
|
+
import theme from "$theme";
|
5
|
+
import ActivityIndicator from "$ecomponents/ActivityIndicator";
|
6
|
+
import Label from "$ecomponents/Label";
|
7
|
+
import PropTypes from "prop-types";
|
8
|
+
import { isNonNullString,defaultStr } from '$cutils';
|
9
|
+
import Button from "$ecomponents/Button";
|
10
|
+
import Dialog from "$ecomponents/Dialog";
|
11
|
+
|
12
|
+
export const scannerTypes = {back:"back",front:"front"};
|
13
|
+
|
14
|
+
/***@see : https://docs.expo.dev/versions/latest/sdk/bar-code-scanner/ */
|
15
|
+
export default function App({onScan,onGrantAccess,testID,onDenyAccess,scannerProps,onCancel,dialogProps}) {
|
16
|
+
testID = defaultStr(testID,"RN_BarCodeScanner");
|
17
|
+
const [hasPermission, setHasPermission] = useState(null);
|
18
|
+
const [visible,setVisible] = useState(true);
|
19
|
+
dialogProps = Object.assign({},dialogProps);
|
20
|
+
scannerProps = Object.assign({},scannerProps);
|
21
|
+
const prevVisible = React.usePrevious(visible);
|
22
|
+
const cancelRef = React.useRef(false);
|
23
|
+
const cancel = ()=>{
|
24
|
+
cancelRef.current = true;
|
25
|
+
setVisible(false);
|
26
|
+
}
|
27
|
+
const getCameraType = ()=>{
|
28
|
+
let {type} = scannerProps;
|
29
|
+
if(isNonNullString(type)){
|
30
|
+
type = type.toLowerCase().trim();
|
31
|
+
} else type = scannerTypes.back;
|
32
|
+
if(!scannerTypes[type]){
|
33
|
+
type = scannerTypes.back;
|
34
|
+
}
|
35
|
+
return type;
|
36
|
+
}
|
37
|
+
const sType = useMemo(()=>{
|
38
|
+
return getCameraType();
|
39
|
+
},[scannerProps.type]);
|
40
|
+
const [scannerType,setScannerType] = useState(sType);
|
41
|
+
useEffect(()=>{
|
42
|
+
const type = getCameraType();
|
43
|
+
if(type !== scannerType){
|
44
|
+
setScannerType(type);
|
45
|
+
}
|
46
|
+
},scannerProps.type)
|
47
|
+
const isBack = scannerType === scannerTypes.back;
|
48
|
+
useEffect(() => {
|
49
|
+
const getBarCodeScannerPermissions = async () => {
|
50
|
+
const { status } = await BarCodeScanner.requestPermissionsAsync();
|
51
|
+
setHasPermission(status === 'granted');
|
52
|
+
};
|
53
|
+
|
54
|
+
getBarCodeScannerPermissions();
|
55
|
+
}, []);
|
56
|
+
|
57
|
+
const handleBarCodeScanned = ({ type, data,...rest }) => {
|
58
|
+
//setScanned(true);
|
59
|
+
if(typeof onScan =="function"){
|
60
|
+
onScan({type,data,code:data,barCode:data,...rest});
|
61
|
+
}
|
62
|
+
setVisible(false);
|
63
|
+
};
|
64
|
+
useEffect(()=>{
|
65
|
+
if(hasPermission ===false){
|
66
|
+
if(typeof onDenyAccess =="function"){
|
67
|
+
return onDenyAccess();
|
68
|
+
}
|
69
|
+
} else if(hasPermission !== null){
|
70
|
+
if(typeof onGrantAccess =="function"){
|
71
|
+
onGrantAccess();
|
72
|
+
}
|
73
|
+
}
|
74
|
+
},[hasPermission]);
|
75
|
+
useEffect(()=>{
|
76
|
+
if(prevVisible === visible) return;
|
77
|
+
if(prevVisible && !visible && cancelRef.current && typeof onCancel =="function"){
|
78
|
+
onCancel();
|
79
|
+
}
|
80
|
+
cancelRef.current = false;
|
81
|
+
},[visible]);
|
82
|
+
const switchCameraBtn = {
|
83
|
+
text : "Pivoter la camera",
|
84
|
+
icon : "camera-flip",
|
85
|
+
tooltip : `Cliquez pour basculer à la camera ${isBack ? "frontable":"arrière"}`,
|
86
|
+
onPress : ()=>{
|
87
|
+
setScannerType(isBack ? scannerTypes.front : scannerTypes.back);
|
88
|
+
}
|
89
|
+
};
|
90
|
+
return <Dialog
|
91
|
+
fullPage
|
92
|
+
actions={[switchCameraBtn]}
|
93
|
+
title = {`Scanner un code barre`}
|
94
|
+
{...dialogProps}
|
95
|
+
onBackActionPress={cancel}
|
96
|
+
visible = {visible}
|
97
|
+
>
|
98
|
+
{hasPermission === null || hasPermission === false ? <View style={[styles.center]}>
|
99
|
+
{hasPermission === false ? <Label fontSize={18} error textBold>Accès à la camera refusée. Vous devez autoriser l'accès à la camera.</Label> :
|
100
|
+
<View style={[styles.row]}>
|
101
|
+
<Label fontSize={18} warning textBold>Demande d'autorisation pour l'accès à la camera...</Label>
|
102
|
+
<ActivityIndicator size={'large'}/>
|
103
|
+
</View>}
|
104
|
+
</View> : <View style={[theme.styles.flex1]} testID={testID}>
|
105
|
+
<BarCodeScanner
|
106
|
+
ratio='16:9'
|
107
|
+
testID={testID+"_ScannerContent"}
|
108
|
+
{...scannerProps}
|
109
|
+
type={scannerType}
|
110
|
+
style={[theme.styles.flex1,{width:"100%",height:"100%"},scannerProps.style]}
|
111
|
+
onBarCodeScanned={handleBarCodeScanned}
|
112
|
+
/>
|
113
|
+
<View style={[styles.row,theme.styles.w100]}>
|
114
|
+
<Button
|
115
|
+
primary
|
116
|
+
{...switchCameraBtn}
|
117
|
+
style={[theme.styles.p1]}
|
118
|
+
/>
|
119
|
+
<Button
|
120
|
+
error
|
121
|
+
children = {"Annuler"}
|
122
|
+
icon = "camera-off"
|
123
|
+
title = {"Cliquez pour annuler l'opération"}
|
124
|
+
onPress = {cancel}
|
125
|
+
/>
|
126
|
+
</View>
|
127
|
+
</View>}
|
128
|
+
</Dialog>;
|
129
|
+
}
|
130
|
+
const styles = StyleSheet.create({
|
131
|
+
center : {
|
132
|
+
justifyContent : "center",
|
133
|
+
alignItems : "center",
|
134
|
+
flexDirection : "column",
|
135
|
+
flex : 1,
|
136
|
+
},
|
137
|
+
row : {
|
138
|
+
flexDirection : "row",
|
139
|
+
justifyContent : "center",
|
140
|
+
alignItems : "center",
|
141
|
+
flexWrap :"wrap",
|
142
|
+
}
|
143
|
+
});
|
144
|
+
BarCodeScanner.propTypes = {
|
145
|
+
onScan : PropTypes.func,
|
146
|
+
onGrantAccess : PropTypes.func, //lorsque la permission est allouée
|
147
|
+
onDenyAccess : PropTypes.func, //lorsque la permission est refusée
|
148
|
+
}
|
@@ -174,8 +174,8 @@ export default function ImageComponent(props){
|
|
174
174
|
setEditorProps({...editorProps,visible:true,...props})
|
175
175
|
})
|
176
176
|
},
|
177
|
-
pickImage : (
|
178
|
-
opts = getCropProps(
|
177
|
+
pickImage : ()=>{
|
178
|
+
const opts = getCropProps(defaultObj(pickImageProps));
|
179
179
|
opts.base64 = true;
|
180
180
|
return pickImage(opts).then((image)=>handlePickedImage(image,opts));
|
181
181
|
},
|
@@ -229,7 +229,9 @@ export default function ImageComponent(props){
|
|
229
229
|
label : 'Enregistrer une photo',
|
230
230
|
icon : 'camera',
|
231
231
|
onPress : (a)=>{
|
232
|
-
|
232
|
+
const opts = getCropProps(defaultObj(pickImageProps));
|
233
|
+
opts.base64 = true;
|
234
|
+
takePhoto(opts).then(handlePickedImage);
|
233
235
|
}
|
234
236
|
})
|
235
237
|
}
|
@@ -113,6 +113,7 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,chevronIconProps
|
|
113
113
|
if(!withLabel){
|
114
114
|
return <View testID={"RNProfilAvatar_AvatarContainer"} style={[theme.styles.row,theme.styles.alignItemsCenter]}>
|
115
115
|
<Image
|
116
|
+
pickImageProps = {{quality:0.4}}
|
116
117
|
{...props}
|
117
118
|
{...aProps}
|
118
119
|
size={size}
|
package/src/media/index.js
CHANGED
@@ -65,7 +65,7 @@ export const pickImageOrVideo = (options)=>{
|
|
65
65
|
return checkPermission().then(()=>{
|
66
66
|
return new Promise((resolve,reject)=>{
|
67
67
|
ImagePicker.launchImageLibraryAsync(getFilePickerOptions(options)).then((result)=>{
|
68
|
-
if(!result.cancelled) {
|
68
|
+
if(!result.cancelled && !result.canceled) {
|
69
69
|
resolve(prepareImageResult(result));
|
70
70
|
} else {
|
71
71
|
notify.warning("Opération annulée par l'utilisateur");
|
@@ -116,7 +116,7 @@ export const takePhoto = (options)=>{
|
|
116
116
|
return checkPermission(ImagePicker.requestCameraPermissionsAsync).then((perm)=>{
|
117
117
|
options = {base64:true,...Object.assign({},options)}
|
118
118
|
return ImagePicker.launchCameraAsync({...getFilePickerOptions(options)}).then((result)=>{
|
119
|
-
if(!result.cancelled) {
|
119
|
+
if(!result.cancelled && !result.canceled) {
|
120
120
|
resolve(prepareImageResult(result));
|
121
121
|
} else {
|
122
122
|
notify.warning("Opération annulée par l'utilisateur");
|
package/src/media/utils.js
CHANGED
@@ -9,7 +9,7 @@ export const getFilePickerOptions = (options)=>{
|
|
9
9
|
base64 : false, //Whether to also include the image data in Base64 format.
|
10
10
|
exif : false, //Whether to also include the EXIF data for the image. On iOS the EXIF data does not include GPS tags in the camera case.
|
11
11
|
mediaTypes : ImagePicker.MediaTypeOptions.All, //@see : https://docs.expo.dev/versions/latest/sdk/imagepicker/#mediatypeoptions
|
12
|
-
quality :
|
12
|
+
quality : 0.5, //Specify the quality of compression, from 0 to 1. 0 means compress for small size, 1 means compress for maximum quality.
|
13
13
|
},options);
|
14
14
|
}
|
15
15
|
/*** retourne les ooptions pour la capture d'une photo
|