@fto-consult/expo-ui 7.11.0 → 7.12.1
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
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@fto-consult/expo-ui",
|
3
|
-
"version": "7.
|
3
|
+
"version": "7.12.1",
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
5
5
|
"scripts": {
|
6
6
|
"clear-npx-cache": "npx clear-npx-cache",
|
@@ -72,7 +72,7 @@
|
|
72
72
|
"@expo/vector-icons": "^13.0.0",
|
73
73
|
"@faker-js/faker": "^8.0.2",
|
74
74
|
"@fto-consult/common": "^3.75.2",
|
75
|
-
"@fto-consult/electron-gen": "^2.
|
75
|
+
"@fto-consult/electron-gen": "^2.2.0",
|
76
76
|
"@pchmn/expo-material3-theme": "^1.3.1",
|
77
77
|
"@react-native-async-storage/async-storage": "1.18.2",
|
78
78
|
"@react-native-community/datetimepicker": "7.2.0",
|
@@ -113,7 +113,7 @@
|
|
113
113
|
"react-native-get-random-values": "~1.9.0",
|
114
114
|
"react-native-iphone-x-helper": "^1.3.1",
|
115
115
|
"react-native-mime-types": "^2.4.0",
|
116
|
-
"react-native-paper": "^
|
116
|
+
"react-native-paper": "^4.12.6",
|
117
117
|
"react-native-paper-dates": "^0.21.7",
|
118
118
|
"react-native-reanimated": "~3.3.0",
|
119
119
|
"react-native-safe-area-context": "4.6.3",
|
@@ -158,7 +158,7 @@ const ButtonComponent = React.forwardRef((prs,ref) => {
|
|
158
158
|
borderColor = Colors.isValid(style.borderColor)? style.borderColor : isCancelButton ? theme.styles.onError : Colors.isValid(borderColor)? borderColor : undefined;
|
159
159
|
}
|
160
160
|
if(theme.isDark() && !hasElevation){
|
161
|
-
textColor = white;
|
161
|
+
//textColor = white;
|
162
162
|
}
|
163
163
|
|
164
164
|
const rippleColor = Colors.setAlpha(textColor,0.32);
|
@@ -54,7 +54,7 @@ export default function ImageComponent(props){
|
|
54
54
|
options : {}
|
55
55
|
})*/
|
56
56
|
const [isDrawing,setIsDrawing] = React.useState(false);
|
57
|
-
let {disabled,onMount,defaultSource,onUnmount,label,text,labelProps,readOnly,beforeRemove,
|
57
|
+
let {disabled,onMount,defaultSource,editable,onUnmount,label,text,labelProps,readOnly,beforeRemove,
|
58
58
|
onChange,draw,round,drawText,drawLabel,rounded,defaultSrc,
|
59
59
|
createSignatureOnly,pickImageProps,width,height,cropProps,size,resizeProps,containerProps,
|
60
60
|
menuProps,pickUri,drawProps,imageProps,length,testID,...rest} = props;
|
@@ -75,6 +75,9 @@ export default function ImageComponent(props){
|
|
75
75
|
if(disabled){
|
76
76
|
readOnly = true;
|
77
77
|
}
|
78
|
+
if(editable ===false){
|
79
|
+
readOnly = true;
|
80
|
+
}
|
78
81
|
React.useEffect(()=>{
|
79
82
|
if(src == props.src) return;
|
80
83
|
setSrc(props.src);
|
@@ -308,6 +311,7 @@ ImageComponent.propTypes = {
|
|
308
311
|
menuProps : PropTypes.object, ///les props du menu d'édition du composant,
|
309
312
|
readOnly : PropTypes.bool,
|
310
313
|
disabled: PropTypes.bool,
|
314
|
+
editable : PropTypes.bool,//si la source de l'image peut être modifiée, via le menu Sélectionner une image ou prendre une photo en fonction de la plateforme
|
311
315
|
pickUri : PropTypes.bool,////si l'uri sera retournée lorsqu'on pick l'image en lieu et place du dataURL
|
312
316
|
imageProps : PropTypes.object, ///les props supplémentaires du composant Image
|
313
317
|
draw : PropTypes.bool, //si l'on peut déssiner une image
|
@@ -2,19 +2,33 @@ import * as FileSaver from "$efile-system/utils/FileSaver";
|
|
2
2
|
import {isElectron} from "$cplatform";
|
3
3
|
import notify from "$cnotify";
|
4
4
|
import Preloader from "$preloader";
|
5
|
-
import {defaultStr,isNonNullString,defaultObj,getFileExtension,isPromise} from "$cutils";
|
5
|
+
import {defaultStr,isNonNullString,defaultObj,isDataURL,getFileExtension,isPromise} from "$cutils";
|
6
6
|
import {HStack} from "$ecomponents/Stack";
|
7
7
|
import Label from "$ecomponents/Label";
|
8
8
|
import DialogProvider from "$ecomponents/Form/FormData/DialogProvider";
|
9
9
|
import session from "$session";
|
10
|
+
import Image from "$ecomponents/Image";
|
11
|
+
import View from "$ecomponents/View";
|
12
|
+
import theme from "$theme";
|
13
|
+
import APP from "$capp/instance";
|
14
|
+
import useContext from "$econtext";
|
15
|
+
import Button from "$ecomponents/Button";
|
16
|
+
import {ProgressBar} from "react-native-paper";
|
17
|
+
|
18
|
+
export const events = {
|
19
|
+
RECORDING_STARTED : "RECORDING_STARTED",
|
20
|
+
RECORDING_PAUSED : "RECORDING_PAUSED",
|
21
|
+
RECORDING_STOPED : "RECORDING_STOPRED",
|
22
|
+
RECORDING_STATUS : "RECORDING_STATUS",
|
23
|
+
}
|
24
|
+
import {useState,useEffect,useMemo,useRef} from "react";
|
10
25
|
|
11
26
|
const startSessionKey = "desktop-capturer-session";
|
12
27
|
const actionsSessionKey = "desktop-capturer-actions";
|
13
28
|
|
14
29
|
export const canRecord = x=> isElectron()? true : typeof navigator !=="undefined" && window?.navigator && (navigator?.mediaDevices) && typeof navigator?.mediaDevices?.getDisplayMedia === 'function';
|
15
30
|
|
16
|
-
export const updateSystemTray = x =>
|
17
|
-
|
31
|
+
export const updateSystemTray = x => false;
|
18
32
|
|
19
33
|
export function getUserMedia(constraints) {
|
20
34
|
// if Promise-based API is available, use it
|
@@ -123,31 +137,31 @@ function mainDesktopCapturer (){
|
|
123
137
|
}
|
124
138
|
|
125
139
|
function startRecording(opts) {
|
140
|
+
if(!canRecord()){
|
141
|
+
return Promise.reject({stauts:false,isRecording:false,msg:"unable to get user media, get user media is not a function"})
|
142
|
+
}
|
126
143
|
if(recorder){
|
127
144
|
recorder.stop();
|
128
145
|
}
|
129
146
|
recorder = undefined;
|
130
147
|
opts = defaultObj(opts)
|
131
|
-
if(!canRecord()){
|
132
|
-
return Promise.reject({stauts:false,isRecording:false,msg:"unable to get user media, get user media is not a function"})
|
133
|
-
}
|
134
148
|
if(isNonNullString(opts.mimeType)){
|
135
149
|
const mimeTypes = getSupportedMimeTypes(x=>!x.startsWith("audio/"))
|
136
150
|
if(mimeTypes.includes(opts.mimeType)){
|
137
151
|
mimeType = opts.mimeType;
|
138
152
|
}
|
139
153
|
}
|
154
|
+
const timer = typeof opts.timer =="number"? opts.timer : 0;
|
155
|
+
const cb = (e)=>{
|
156
|
+
setTimeout(()=>{
|
157
|
+
const status = desktopCapturer.getRecordingStatus();
|
158
|
+
APP.trigger(events.RECORDING_STATUS,status);
|
159
|
+
},timer*1000+1000);
|
160
|
+
}
|
140
161
|
if(typeof electronDesktopCapturer?.startRecording ==='function'){
|
141
162
|
try {
|
142
|
-
const
|
143
|
-
|
144
|
-
console.log(e," is e of recorder gettted");
|
145
|
-
if(e instanceof MediaRecorder){
|
146
|
-
recorder = e;
|
147
|
-
}
|
148
|
-
return e;
|
149
|
-
}
|
150
|
-
return Promise.resolve(e).then(cb).catch(notify.error);
|
163
|
+
const eRecorder = electronDesktopCapturer.startRecording({...opts,mimeType,updateSystemTray,handleUserMediaError})
|
164
|
+
return Promise.resolve(eRecorder).then(cb).catch(notify.error);
|
151
165
|
} catch(e){
|
152
166
|
notify.error(e);
|
153
167
|
return Promise.reject(e);
|
@@ -174,6 +188,7 @@ function mainDesktopCapturer (){
|
|
174
188
|
} else {
|
175
189
|
return getUserMediaSync({audio:false,video}).then((stream)=>{
|
176
190
|
handleStream(stream,opts);
|
191
|
+
cb();
|
177
192
|
resolve({isRecording:true})
|
178
193
|
}).catch(handleUserMediaError);
|
179
194
|
}
|
@@ -198,6 +213,10 @@ function mainDesktopCapturer (){
|
|
198
213
|
return true;
|
199
214
|
}
|
200
215
|
function stopRecording(opts) {
|
216
|
+
setTimeout(()=>{
|
217
|
+
const status = desktopCapturer.getRecordingStatus();
|
218
|
+
APP.trigger(events.RECORDING_STATUS,status);
|
219
|
+
},1000);
|
201
220
|
if(electronDesktopCapturer.stopRecording) return electronDesktopCapturer.stopRecording();
|
202
221
|
if(!recorder) return false;
|
203
222
|
let s = getRecordingStatus();
|
@@ -224,6 +243,8 @@ function mainDesktopCapturer (){
|
|
224
243
|
getAudioConstraint,
|
225
244
|
stopRecording,
|
226
245
|
getSupportedMimeTypes,
|
246
|
+
electron : electronDesktopCapturer,
|
247
|
+
isElectron : typeof electronDesktopCapturer.getRecordingStatus ==="function",
|
227
248
|
}
|
228
249
|
}
|
229
250
|
|
@@ -255,7 +276,7 @@ export const looopForTimer = (timer)=>{
|
|
255
276
|
}
|
256
277
|
const desktopCapturer = mainDesktopCapturer();
|
257
278
|
|
258
|
-
export function handleCapture(){
|
279
|
+
export async function handleCapture(){
|
259
280
|
if(!canRecord()){
|
260
281
|
const message = "Impossible de faire des enregistrements vidéo sur ce type de périférique";
|
261
282
|
notify.error(message);
|
@@ -268,8 +289,39 @@ export function handleCapture(){
|
|
268
289
|
const sKey = !isPaused && !isRecording ? startSessionKey : actionsSessionKey;
|
269
290
|
const data = Object.assign({},session.get(sKey));
|
270
291
|
if(!isPaused && !isRecording){
|
292
|
+
let sources = null;
|
293
|
+
const {electron} = desktopCapturer;
|
294
|
+
const screenAccess = typeof electron.getScreenAccess =="function" && electron.getScreenAccess() || true;
|
295
|
+
if(!screenAccess){
|
296
|
+
const msg = `Le partage d'écran n'est pas activé sur votre système, merci d'activer le partage d'écran dans les paramètres systèmes`;
|
297
|
+
notify.error(msg);
|
298
|
+
return Promise.reject({message:msg});
|
299
|
+
}
|
300
|
+
if(typeof electron.getSources =='function'){
|
301
|
+
sources = await electron.getSources();
|
302
|
+
}
|
271
303
|
title = "Effectuer une capture d'écran vidéo";
|
272
304
|
fields = {
|
305
|
+
source : Array.isArray(sources)? {
|
306
|
+
text : "Sélectionner la source de l'écran à capturer",
|
307
|
+
type : "select",
|
308
|
+
required : true,
|
309
|
+
items : sources,
|
310
|
+
itemValue : ({item,index})=>item.id,
|
311
|
+
//compare : (a,b)=> a?.id === b?.id,
|
312
|
+
listProps : {itemHeight:200},
|
313
|
+
itemHeight : 250,
|
314
|
+
renderItem : ({item,index})=>{
|
315
|
+
if(!isObj(item) || !isDataURL(item.thumbnailURL)) return null;
|
316
|
+
return <View style={[theme.styles.w100,theme.styles.alignItemsFlexStart]} testID = {`RNViewSource_${item.id}`}>
|
317
|
+
<Label textBold primary>{item.name}</Label>
|
318
|
+
<Image editable={false} width = {250} rounded = {false} src={item.thumbnailURL}/>
|
319
|
+
</View>
|
320
|
+
},
|
321
|
+
renderText : ({item,index})=>{
|
322
|
+
return `${item?.name}`;
|
323
|
+
}
|
324
|
+
} : undefined,
|
273
325
|
audio : {
|
274
326
|
text : "Enregistrer le son",
|
275
327
|
type : 'switch',
|
@@ -291,7 +343,12 @@ export function handleCapture(){
|
|
291
343
|
itemValue : ({item,index})=>item,
|
292
344
|
renderText : ({item,index}) => item,
|
293
345
|
renderItem : ({item,index}) => item,
|
294
|
-
}
|
346
|
+
},
|
347
|
+
showPreloaderOnScreenCapture : electron?.isElectron ? {
|
348
|
+
text : "Afficher la progression",
|
349
|
+
tooltip : "Afficher la progression au niveau de l'icone de l'application",
|
350
|
+
defaultValue : 1,
|
351
|
+
} : undefined
|
295
352
|
}
|
296
353
|
yes = {
|
297
354
|
text : 'Capturer',
|
@@ -360,5 +417,62 @@ export function handleCapture(){
|
|
360
417
|
});
|
361
418
|
}
|
362
419
|
|
420
|
+
export const useRecordingStatus = ()=>{
|
421
|
+
const [status,setStatus] = useState(desktopCapturer.getRecordingStatus());
|
422
|
+
const timerRef = useRef(null);
|
423
|
+
const {isPaused,isRecording,isInactive} = status;
|
424
|
+
const mRecord = canRecord();
|
425
|
+
useEffect(()=>{
|
426
|
+
if(!mRecord) return ()=>{};
|
427
|
+
if(isInactive){
|
428
|
+
clearInterval(timerRef.current);
|
429
|
+
timerRef.current = null;
|
430
|
+
} else {
|
431
|
+
timerRef.current = setInterval(()=>{
|
432
|
+
const nStatus = desktopCapturer.getRecordingStatus();
|
433
|
+
if(nStatus.isPaused !== status.isPaused || nStatus.isInactive !== status.isInactive || nStatus.isRecording !== status.isRecording){
|
434
|
+
setStatus({...nStatus});
|
435
|
+
}
|
436
|
+
},1000);
|
437
|
+
}
|
438
|
+
return ()=>{
|
439
|
+
clearInterval(timerRef.current);
|
440
|
+
timerRef.current = null;
|
441
|
+
}
|
442
|
+
},[isPaused,isRecording,isInactive]);
|
443
|
+
useEffect(()=>{
|
444
|
+
return ()=>{
|
445
|
+
clearInterval(timerRef.current);
|
446
|
+
timerRef.current = null;
|
447
|
+
}
|
448
|
+
},[]);
|
449
|
+
return status;
|
450
|
+
}
|
451
|
+
|
452
|
+
/**** le bouton permettant d'exécuter la fonction de recording de l'application */
|
453
|
+
export const RecordingButton = function({onPress,testID,...props}){
|
454
|
+
const {desktopCapturer:dParams} = useContext();
|
455
|
+
const {isRecording,isPaused,isInactive} = useRecordingStatus();
|
456
|
+
const canCaptureDesktop = !canRecord()? false : typeof dParams =="function"? !!dParams() : typeof dParams =="boolean"? dParams : true;
|
457
|
+
if(!canCaptureDesktop) return null;
|
458
|
+
testID = defaultStr(props.testID,"RNScreenRecordStatusButton")
|
459
|
+
const color = theme.Colors.setAlpha(theme.colors.text,theme.ALPHA);
|
460
|
+
const buttonContainerProps = {style:[theme.styles.w100,theme.styles.alignItemsFlexStart]}
|
461
|
+
return <View testID={testID+"_Container"} {...buttonContainerProps}>
|
462
|
+
<Button containerProps = {buttonContainerProps} {...props} style={[{color},buttonContainerProps.style,props.style]} upperCase={false} onPress = {(...args)=>{
|
463
|
+
if(onPress && onPress(...args) === false) return;
|
464
|
+
handleCapture();
|
465
|
+
}}
|
466
|
+
icon={isPaused ? "material-pause-presentation":isRecording ? "record-rec":"record"} iconProps={{color}} testID={testID}
|
467
|
+
>
|
468
|
+
{isPaused ? "Capture vidéo en pause" : isRecording ? "Capture vidéo en cours ..." :"Faire une capture vidéo" }
|
469
|
+
</Button>
|
470
|
+
{isPaused || isRecording ? <ProgressBar
|
471
|
+
indeterminate = {isRecording || undefined}
|
472
|
+
color = {theme.colors.primary}
|
473
|
+
progress = {isPaused ? 50 : undefined}
|
474
|
+
/> : null}
|
475
|
+
</View>
|
476
|
+
}
|
363
477
|
|
364
478
|
export default desktopCapturer;
|
@@ -7,7 +7,7 @@ import {defaultObj,sortBy,defaultStr,isObj} from "$cutils";
|
|
7
7
|
import appConfig from "$capp/config";
|
8
8
|
import useContext from "$econtext/hooks";
|
9
9
|
import {useMemo,useEffect,useRef} from "react";
|
10
|
-
import
|
10
|
+
import {RecordingButton} from "$expo-ui/desktopCapturer";
|
11
11
|
///les items du drawer
|
12
12
|
import { screenName as aboutScreenName} from "$escreens/Help/About";
|
13
13
|
import theme from "$theme";
|
@@ -17,7 +17,7 @@ import Auth,{useIsSignedIn,tableDataPerms} from "$cauth";
|
|
17
17
|
import {getTableDataListRouteName} from "$enavigation/utils";
|
18
18
|
import {isValidElement,usePrevious} from "$react";
|
19
19
|
const useGetItems = (options)=>{
|
20
|
-
const {navigation:{drawerItems,drawerSections,drawerItemsMutator},
|
20
|
+
const {navigation:{drawerItems,drawerSections,drawerItemsMutator},tablesData} = useContext();
|
21
21
|
options = defaultObj(options);
|
22
22
|
const {refresh,force} = options;
|
23
23
|
const showProfilOnDrawer = theme.showProfilAvatarOnDrawer;
|
@@ -96,22 +96,6 @@ const useGetItems = (options)=>{
|
|
96
96
|
items[item.drawerSection.trim()].items.push(item);
|
97
97
|
}
|
98
98
|
});
|
99
|
-
const canCaptureDesktop = !eDesktopCapturer.canRecord()? false : typeof desktopCapturer =="function"? !!desktopCapturer() : typeof desktopCapturer =="boolean"? desktopCapturer : true;
|
100
|
-
const captureSide = canCaptureDesktop ? {
|
101
|
-
text : 'Capture d\'écran vidéo',
|
102
|
-
icon : "record",
|
103
|
-
onPress :()=>{
|
104
|
-
return handleCapture();
|
105
|
-
}
|
106
|
-
}:{};
|
107
|
-
let hasCapture = canCaptureDesktop ? false : true;
|
108
|
-
if(!hasCapture){
|
109
|
-
if(isObj(items.admin) && Array.isArray(items.admin.items)){
|
110
|
-
items.admin = Object.clone(items.admin);
|
111
|
-
items.admin.items.push(captureSide);
|
112
|
-
hasCapture = true;
|
113
|
-
}
|
114
|
-
}
|
115
99
|
if(handleHelp){
|
116
100
|
const dHelp = isObj(items.help)? Object.clone(items.help) : {};
|
117
101
|
items.help = {
|
@@ -122,10 +106,6 @@ const useGetItems = (options)=>{
|
|
122
106
|
...dHelp,
|
123
107
|
items : Array.isArray(dHelp.items)? dHelp.items : [],
|
124
108
|
};
|
125
|
-
if(!hasCapture){
|
126
|
-
items.help.items.push(captureSide);
|
127
|
-
hasCapture = true;
|
128
|
-
}
|
129
109
|
items.help.items.push({
|
130
110
|
icon : 'help',
|
131
111
|
label : 'A propos de '+APP.getName(),
|
@@ -154,6 +134,17 @@ const useGetItems = (options)=>{
|
|
154
134
|
delete items[section];
|
155
135
|
}
|
156
136
|
});
|
137
|
+
const captureSide = {
|
138
|
+
label : <RecordingButton/>,
|
139
|
+
style : [theme.styles.noPadding],
|
140
|
+
labelProps : {style : [{flexShrink : 1},theme.styles.alignItemsFlexStart,theme.styles.w100]}
|
141
|
+
};
|
142
|
+
if(isObj(items.help) && Array.isArray(items.help.items)){
|
143
|
+
items.help = Object.clone(items.help);
|
144
|
+
items.help.items.push(captureSide);
|
145
|
+
} else {
|
146
|
+
items.desktopCapturer = captureSide;
|
147
|
+
}
|
157
148
|
return items;
|
158
149
|
},[showProfilOnDrawer,handleHelp,theme.name,theme.colors.primary,theme.colors.secondary,refreshItemsRef.current,force,isSignedIn])
|
159
150
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module.exports = {
|
2
2
|
"@fto-consult/expo-ui": {
|
3
3
|
"name": "@fto-consult/expo-ui",
|
4
|
-
"version": "7.
|
4
|
+
"version": "7.11.0",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
7
7
|
"url": "git+https://github.com/borispipo/expo-ui.git"
|
@@ -54,7 +54,7 @@ module.exports = {
|
|
54
54
|
"license": "ISC"
|
55
55
|
},
|
56
56
|
"@fto-consult/electron-gen": {
|
57
|
-
"version": "
|
57
|
+
"version": "2.2.0",
|
58
58
|
"license": "ISC"
|
59
59
|
},
|
60
60
|
"@pchmn/expo-material3-theme": {
|
@@ -253,6 +253,11 @@ module.exports = {
|
|
253
253
|
"version": "1.9.0",
|
254
254
|
"license": "MIT"
|
255
255
|
},
|
256
|
+
"react-native-indicators": {
|
257
|
+
"version": "0.17.0",
|
258
|
+
"url": "git://github.com/n4kz/react-native-indicators.git",
|
259
|
+
"license": "BSD-3-Clause"
|
260
|
+
},
|
256
261
|
"react-native-iphone-x-helper": {
|
257
262
|
"version": "1.3.1",
|
258
263
|
"url": "https://github.com/ptelad/react-native-iphone-x-helper#readme",
|
@@ -263,7 +268,7 @@ module.exports = {
|
|
263
268
|
"license": "MIT"
|
264
269
|
},
|
265
270
|
"react-native-paper": {
|
266
|
-
"version": "
|
271
|
+
"version": "4.12.6",
|
267
272
|
"url": "https://callstack.github.io/react-native-paper",
|
268
273
|
"license": "MIT"
|
269
274
|
},
|