@fto-consult/expo-ui 6.35.5 → 6.37.2
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/.env.readMe.txt +11 -11
- package/App.js +1 -0
- package/app.config.json +10 -10
- package/app.json +11 -11
- package/bin/create-app/App.js +40 -0
- package/bin/create-app.js +2 -0
- package/electron/utils/env.js +79 -79
- package/env.js +10 -10
- package/index.js +1 -68
- package/package.json +131 -130
- package/src/App.js +18 -173
- package/src/AppEntry/App.js +320 -0
- package/src/AppEntry/index.js +177 -0
- package/src/app.config.json +30 -30
- package/src/components/Chart/appexChart/appexChart.html +23 -23
- package/src/context/Provider.js +4 -2
- package/src/index.js +2 -320
- package/src/screens/Help/openLibraries.js +1 -1
- package/%ProgramData%/Microsoft/Windows/UUS/State/_active.uusver +0 -1
- package/bin/create-app/registerApp.js +0 -40
@@ -0,0 +1,320 @@
|
|
1
|
+
import React from "$react"
|
2
|
+
import { AppState} from "react-native";
|
3
|
+
import BackHandler from "$ecomponents/BackHandler";
|
4
|
+
import * as Linking from 'expo-linking';
|
5
|
+
import APP from "$capp";
|
6
|
+
import {AppStateService,trackIDLE,stop as stopIDLE} from "$capp/idle";
|
7
|
+
import { NavigationContainer} from '@react-navigation/native';
|
8
|
+
import {navigationRef} from "$cnavigation"
|
9
|
+
import NetInfo from '$cutils/NetInfo';
|
10
|
+
import Auth from "$cauth";
|
11
|
+
import {isNativeMobile,isElectron} from "$cplatform";
|
12
|
+
import Navigation from "../navigation";
|
13
|
+
import {set as setSession,get as getSession} from "$session";
|
14
|
+
import { showConfirm } from "$ecomponents/Dialog";
|
15
|
+
import {close as closePreloader, isVisible as isPreloaderVisible} from "$epreloader";
|
16
|
+
import SplashScreen from "$ecomponents/SplashScreen";
|
17
|
+
import {decycle} from "$cutils/json";
|
18
|
+
import init from "$capp/init";
|
19
|
+
import { setIsInitialized} from "$capp/utils";
|
20
|
+
import {isObj,isNonNullString,isPromise,defaultObj,defaultStr} from "$cutils";
|
21
|
+
import {loadFonts} from "$ecomponents/Icon/Font";
|
22
|
+
import appConfig from "$capp/config";
|
23
|
+
import Preloader from "$preloader";
|
24
|
+
import {PreloaderProvider} from "$epreloader";
|
25
|
+
import BottomSheetProvider from "$ecomponents/BottomSheet/Provider";
|
26
|
+
import DialogProvider from "$ecomponents/Dialog/Provider";
|
27
|
+
import SimpleSelect from '$ecomponents/SimpleSelect';
|
28
|
+
import {Provider as AlertProvider} from '$ecomponents/Dialog/confirm/Alert';
|
29
|
+
import { DialogProvider as FormDataDialogProvider } from '$eform/FormData';
|
30
|
+
import ErrorBoundaryProvider from "$ecomponents/ErrorBoundary/Provider";
|
31
|
+
import notify, {notificationRef} from "$notify";
|
32
|
+
import DropdownAlert from '$ecomponents/Dialog/DropdownAlert';
|
33
|
+
import {AuthProvider} from '$cauth';
|
34
|
+
import { PreferencesContext } from '../Preferences';
|
35
|
+
import ErrorBoundary from "$ecomponents/ErrorBoundary";
|
36
|
+
import {updateTheme,defaultTheme} from "$theme";
|
37
|
+
import StatusBar from "$ecomponents/StatusBar";
|
38
|
+
import {Provider as PaperProvider,Portal } from 'react-native-paper';
|
39
|
+
import FontIcon from "$ecomponents/Icon/Font";
|
40
|
+
import useContext from "$econtext/hooks";
|
41
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
42
|
+
import { StyleSheet } from "react-native";
|
43
|
+
import Logo from "$ecomponents/Logo";
|
44
|
+
|
45
|
+
|
46
|
+
let MAX_BACK_COUNT = 1;
|
47
|
+
let countBack = 0;
|
48
|
+
let isBackConfirmShowing = false;
|
49
|
+
|
50
|
+
const resetExitCounter = ()=>{
|
51
|
+
countBack = 0
|
52
|
+
isBackConfirmShowing = false;
|
53
|
+
};
|
54
|
+
|
55
|
+
const NAVIGATION_PERSISTENCE_KEY = 'NAVIGATION_STATE';
|
56
|
+
|
57
|
+
/****
|
58
|
+
* init {function}: ()=>Promise<{}> est la fonction d'initialisation de l'application
|
59
|
+
* initialRouteName : la route initiale par défaut
|
60
|
+
* getStartedRouteName : la route par défaut de getStarted lorsque l'application est en mode getStarted, c'est à dire lorsque la fonction init renvoie une erreur (reject)
|
61
|
+
*/
|
62
|
+
function App({init:initApp,initialRouteName:appInitialRouteName,render,onMount}) {
|
63
|
+
AppStateService.init();
|
64
|
+
const {FontsIconsFilter,beforeExit,preferences:appPreferences,navigation,getStartedRouteName} = useContext();
|
65
|
+
const {containerProps} = navigation;
|
66
|
+
const [initialState, setInitialState] = React.useState(undefined);
|
67
|
+
const appReadyRef = React.useRef(true);
|
68
|
+
const [state,setState] = React.useState({
|
69
|
+
isLoading : true,
|
70
|
+
isInitialized:false,
|
71
|
+
});
|
72
|
+
React.useEffect(() => {
|
73
|
+
const loadResources = ()=>{
|
74
|
+
return new Promise((resolve)=>{
|
75
|
+
loadFonts(FontsIconsFilter).catch((e)=>{
|
76
|
+
console.warn(e," ierror loading app resources fonts");
|
77
|
+
}).finally(()=>{
|
78
|
+
resolve(true);
|
79
|
+
});
|
80
|
+
})
|
81
|
+
}
|
82
|
+
const restoreState = () => {
|
83
|
+
return new Promise((resolve,reject)=>{
|
84
|
+
(async ()=>{
|
85
|
+
try {
|
86
|
+
const initialUrl = await Linking.getInitialURL();
|
87
|
+
if (isNativeMobile() || initialUrl === null) {
|
88
|
+
const savedState = getSession(NAVIGATION_PERSISTENCE_KEY);
|
89
|
+
if (isObj(savedState)) {
|
90
|
+
setInitialState(savedState);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
} catch(e){ console.log(e," is state error")}
|
94
|
+
finally {
|
95
|
+
appReadyRef.current = true;
|
96
|
+
resolve({});
|
97
|
+
}
|
98
|
+
})();
|
99
|
+
});
|
100
|
+
};
|
101
|
+
const subscription = AppState.addEventListener('change', AppStateService.getInstance().handleAppStateChange);
|
102
|
+
const beforeExitApp = (cb)=>{
|
103
|
+
return new Promise((resolve,reject)=>{
|
104
|
+
Preloader.closeAll();
|
105
|
+
showConfirm({
|
106
|
+
title : "Quitter l'application",
|
107
|
+
message : 'Voulez vous vraiment quitter l\'application?',
|
108
|
+
yes : 'Oui',
|
109
|
+
no : 'Non',
|
110
|
+
onSuccess : ()=>{
|
111
|
+
const foreceExit = ()=>{
|
112
|
+
BackHandler.exitApp();
|
113
|
+
if(isElectron() && window.ELECTRON && typeof ELECTRON.exitApp =='function'){
|
114
|
+
ELECTRON.exitApp({APP});
|
115
|
+
}
|
116
|
+
}
|
117
|
+
const exit = ()=>{
|
118
|
+
if(typeof beforeExit =='function'){
|
119
|
+
const r2 = beforeExit()
|
120
|
+
if(!isPromise(r2)){
|
121
|
+
throw {message:'La fonction before exit du contexte doit retourner une promesse',returnedResult:r2}
|
122
|
+
}
|
123
|
+
return r2.then(foreceExit).catch(reject);
|
124
|
+
}
|
125
|
+
foreceExit();
|
126
|
+
}
|
127
|
+
const r = {APP,exit};
|
128
|
+
APP.trigger(APP.EVENTS.BEFORE_EXIT,exit,(result)=>{
|
129
|
+
if(isObj(result) || Array.isArray(result)){
|
130
|
+
for(let ik in result){
|
131
|
+
if(result[ik] === false) return reject({message:'EXIT APP DENIED BY BEFORE EXIT EVENT HANDLER AT POSITON {0}'.sprintf(ik)});
|
132
|
+
}
|
133
|
+
}
|
134
|
+
resolve(r);
|
135
|
+
if(typeof cb =='function'){
|
136
|
+
cb(r);
|
137
|
+
}
|
138
|
+
});
|
139
|
+
},
|
140
|
+
onCancel : reject
|
141
|
+
})
|
142
|
+
})
|
143
|
+
}
|
144
|
+
/**** onBeforeExit prend en paramètre la fonction de rappel CB, qui lorsque la demande de sortie d'application est acceptée, alors elle est exécutée */
|
145
|
+
if(typeof APP.beforeExit !=='function'){
|
146
|
+
Object.defineProperties(APP,{
|
147
|
+
beforeExit : {
|
148
|
+
value : beforeExitApp,
|
149
|
+
}
|
150
|
+
})
|
151
|
+
}
|
152
|
+
const backAction = (args) => {
|
153
|
+
if(navigationRef && navigationRef.canGoBack()? true : false){
|
154
|
+
resetExitCounter();
|
155
|
+
navigationRef.goBack(null);
|
156
|
+
return false;
|
157
|
+
}
|
158
|
+
if(isBackConfirmShowing) {
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
if(countBack < MAX_BACK_COUNT){
|
162
|
+
countBack++;
|
163
|
+
isBackConfirmShowing = false;
|
164
|
+
if(countBack === MAX_BACK_COUNT){
|
165
|
+
notify.toast({text:'Cliquez à nouveau pour quiiter l\'application'});
|
166
|
+
}
|
167
|
+
if(countBack === 2 && isPreloaderVisible()) {
|
168
|
+
closePreloader();
|
169
|
+
}
|
170
|
+
return false;
|
171
|
+
}
|
172
|
+
isBackConfirmShowing = true;
|
173
|
+
return beforeExitApp().finally(x=>{
|
174
|
+
isBackConfirmShowing = false;
|
175
|
+
}).then(({exit})=>{
|
176
|
+
exit();
|
177
|
+
})
|
178
|
+
};
|
179
|
+
const unsubscribeNetInfo = NetInfo.addEventListener(state => {
|
180
|
+
APP.setOnlineState(state);
|
181
|
+
});
|
182
|
+
NetInfo.fetch().catch((e)=>{
|
183
|
+
console.log(e," is net info heinn")
|
184
|
+
});
|
185
|
+
loadResources().finally(()=>{
|
186
|
+
(typeof initApp =='function'?initApp : init)({appConfig,contex:{setState}}).then((args)=>{
|
187
|
+
if(Auth.isLoggedIn()){
|
188
|
+
Auth.loginUser(false);
|
189
|
+
}
|
190
|
+
setState({
|
191
|
+
...state,hasGetStarted:true,...defaultObj(args && args?.state),isInitialized:true,isLoading : false,
|
192
|
+
});
|
193
|
+
}).catch((e)=>{
|
194
|
+
console.error(e," loading resources for app initialization");
|
195
|
+
setState({...state,isInitialized:true,isLoading : false,hasGetStarted:false});
|
196
|
+
})
|
197
|
+
});
|
198
|
+
|
199
|
+
const Events = {}
|
200
|
+
let events = [];
|
201
|
+
if(navigationRef && navigationRef.addListener){
|
202
|
+
for(let i in Events){
|
203
|
+
events.push(navigationRef.addListener(i,Events[i]));
|
204
|
+
}
|
205
|
+
}
|
206
|
+
APP.onElectron("BEFORE_EXIT",()=>{
|
207
|
+
return beforeExitApp().then(({exit})=>{
|
208
|
+
exit();
|
209
|
+
})
|
210
|
+
});
|
211
|
+
APP.on(APP.EVENTS.BACK_BUTTON,backAction);
|
212
|
+
return () => {
|
213
|
+
APP.off(APP.EVENTS.BACK_BUTTON,backAction);
|
214
|
+
|
215
|
+
if(subscription && subscription.remove){
|
216
|
+
subscription.remove();
|
217
|
+
}
|
218
|
+
events.map((ev)=>{
|
219
|
+
if(typeof ev =="function") ev();
|
220
|
+
})
|
221
|
+
unsubscribeNetInfo();
|
222
|
+
stopIDLE(false,true);
|
223
|
+
|
224
|
+
}
|
225
|
+
}, []);
|
226
|
+
const {isInitialized} = state;
|
227
|
+
const isLoading = state.isLoading || !isInitialized || !appReadyRef.current? true : false;
|
228
|
+
React.useEffect(()=>{
|
229
|
+
if(isInitialized){
|
230
|
+
setIsInitialized(true);
|
231
|
+
trackIDLE(true);
|
232
|
+
}
|
233
|
+
},[isInitialized]);
|
234
|
+
const hasGetStarted = state.hasGetStarted !== false? true : false;
|
235
|
+
const themeRef = React.useRef(null);
|
236
|
+
const [theme,setTheme] = React.useState(themeRef.current || updateTheme(defaultTheme));
|
237
|
+
themeRef.current = theme;
|
238
|
+
const updatePreferenceTheme = (customTheme,persist)=>{
|
239
|
+
setTheme(updateTheme(customTheme));
|
240
|
+
};
|
241
|
+
const forceRender = React.useForceRender();
|
242
|
+
const pref = typeof appPreferences =='function'? appPreferences({setTheme,forceRender,updateTheme:updatePreferenceTheme}) : appPreferences;
|
243
|
+
const preferences = React.useMemo(()=>({
|
244
|
+
updateTheme:updatePreferenceTheme,
|
245
|
+
theme,
|
246
|
+
...defaultObj(pref),
|
247
|
+
}),[theme,pref]);
|
248
|
+
const isLoaded = !isLoading;
|
249
|
+
const prevIsLoaded = React.usePrevious(isLoaded);
|
250
|
+
const onMountRef = React.useRef(false);
|
251
|
+
React.useEffect(()=>{
|
252
|
+
if(prevIsLoaded == isLoaded || !isLoaded || onMountRef.current) return;
|
253
|
+
if(typeof onMount ==='function'){
|
254
|
+
onMount({appConfig});
|
255
|
+
onMountRef.current = true;
|
256
|
+
}
|
257
|
+
},[isLoaded])
|
258
|
+
const child = isLoaded ? <NavigationContainer
|
259
|
+
ref={navigationRef}
|
260
|
+
initialState={initialState}
|
261
|
+
{...containerProps}
|
262
|
+
onStateChange={(state,...rest) =>{
|
263
|
+
setSession(NAVIGATION_PERSISTENCE_KEY,decycle(state),false);
|
264
|
+
if(typeof containerProps.onStateChange =='function'){
|
265
|
+
containerProps.onStateChange(state,...rest);
|
266
|
+
}
|
267
|
+
}}
|
268
|
+
fallback = {React.isValidElement(containerProps.fallback) ? containerProps.fallback : <Logo.Progress/>}
|
269
|
+
>
|
270
|
+
<Navigation
|
271
|
+
initialRouteName = {defaultStr(hasGetStarted ? appInitialRouteName : getStartedRouteName,"Home")}
|
272
|
+
state = {state}
|
273
|
+
hasGetStarted = {hasGetStarted}
|
274
|
+
isInitialized = {isInitialized}
|
275
|
+
onGetStart = {(e)=>{
|
276
|
+
setState({...state,hasGetStarted:true})
|
277
|
+
}}
|
278
|
+
/>
|
279
|
+
</NavigationContainer> : null;
|
280
|
+
const content = isLoaded ? typeof render == 'function'? render({children:child,appConfig,config:appConfig}) : child : null;
|
281
|
+
return <AuthProvider>
|
282
|
+
<GestureHandlerRootView testID={"RN_MainAppGestureHanleRootView"} style={styles.gesture}>
|
283
|
+
<PaperProvider
|
284
|
+
theme={theme}
|
285
|
+
settings={{
|
286
|
+
icon: (props) => {
|
287
|
+
return <FontIcon {...props}/>
|
288
|
+
},
|
289
|
+
}}
|
290
|
+
>
|
291
|
+
<Portal.Host testID="RN_NativePaperPortalHost">
|
292
|
+
<ErrorBoundaryProvider/>
|
293
|
+
<PreloaderProvider/>
|
294
|
+
<DialogProvider responsive testID={"RN_MainAppDialogProvider"}/>
|
295
|
+
<AlertProvider SimpleSelect={SimpleSelect}/>
|
296
|
+
<FormDataDialogProvider/>
|
297
|
+
<BottomSheetProvider/>
|
298
|
+
<DropdownAlert ref={notificationRef}/>
|
299
|
+
<ErrorBoundary>
|
300
|
+
<StatusBar/>
|
301
|
+
<SplashScreen isLoaded={isLoaded}>
|
302
|
+
<PreferencesContext.Provider value={preferences}>
|
303
|
+
{React.isValidElement(content) && content || child}
|
304
|
+
</PreferencesContext.Provider>
|
305
|
+
</SplashScreen>
|
306
|
+
</ErrorBoundary>
|
307
|
+
</Portal.Host>
|
308
|
+
</PaperProvider>
|
309
|
+
</GestureHandlerRootView>
|
310
|
+
</AuthProvider>;
|
311
|
+
}
|
312
|
+
|
313
|
+
export default App;
|
314
|
+
|
315
|
+
const styles = StyleSheet.create({
|
316
|
+
gesture : {
|
317
|
+
flex : 1,
|
318
|
+
flexGrow : 1,
|
319
|
+
}
|
320
|
+
})
|
@@ -0,0 +1,177 @@
|
|
1
|
+
import '$session';
|
2
|
+
import React from 'react';
|
3
|
+
import {SWRConfig} from "$swr";
|
4
|
+
import App from './App';
|
5
|
+
import notify from "$notify";
|
6
|
+
import APP from "$app";
|
7
|
+
import {isMobileNative} from "$cplatform";
|
8
|
+
import {setDeviceIdRef} from "$capp";
|
9
|
+
import {showPrompt} from "$ecomponents/Dialog/confirm";
|
10
|
+
import { AppState } from 'react-native'
|
11
|
+
import {canFetchOffline} from "$capi/utils";
|
12
|
+
import {defaultNumber} from "$cutils";
|
13
|
+
import { timeout as SWR_REFRESH_TIMEOUT} from '$ecomponents/Datagrid/SWRDatagrid';
|
14
|
+
import { Dimensions,Keyboard } from 'react-native';
|
15
|
+
import {isTouchDevice} from "$platform";
|
16
|
+
import * as Utils from "$cutils";
|
17
|
+
import {useContext} from "$econtext/hooks";
|
18
|
+
import appConfig from "$capp/config";
|
19
|
+
import { useKeepAwake } from 'expo-keep-awake';
|
20
|
+
|
21
|
+
Object.map(Utils,(v,i)=>{
|
22
|
+
if(typeof v =='function' && typeof window !='undefined' && window && !window[i]){
|
23
|
+
window[i] = v;
|
24
|
+
}
|
25
|
+
});
|
26
|
+
|
27
|
+
export default function getIndex({onMount,onUnmount,render,onRender,init}){
|
28
|
+
const {swrConfig} = useContext();
|
29
|
+
const isScreenFocusedRef = React.useRef(true);
|
30
|
+
isMobileNative() && useKeepAwake();
|
31
|
+
///garde pour chaque écran sa date de dernière activité
|
32
|
+
const screensRef = React.useRef({});//la liste des écrans actifs
|
33
|
+
const activeScreenRef = React.useRef('');
|
34
|
+
const prevActiveScreenRef = React.useRef('');
|
35
|
+
const appStateRef = React.useRef({});
|
36
|
+
const isKeyboardOpenRef = React.useRef(false);
|
37
|
+
React.useOnRender(onRender);
|
38
|
+
React.useEffect(()=>{
|
39
|
+
///la fonction de rappel lorsque le composant est monté
|
40
|
+
const onScreenFocus = ({sanitizedName})=>{
|
41
|
+
prevActiveScreenRef.current = activeScreenRef.current;
|
42
|
+
if(activeScreenRef.current){
|
43
|
+
screensRef.current[activeScreenRef.current] = null;
|
44
|
+
}
|
45
|
+
screensRef.current[sanitizedName] = new Date();
|
46
|
+
activeScreenRef.current = sanitizedName;
|
47
|
+
isScreenFocusedRef.current = true;
|
48
|
+
console.log(sanitizedName," is focused");
|
49
|
+
}, onScreenBlur = (...args)=>{
|
50
|
+
console.log(args," is blured");
|
51
|
+
isScreenFocusedRef.current = false;
|
52
|
+
}
|
53
|
+
APP.on(APP.EVENTS.SCREEN_FOCUS,onScreenFocus);
|
54
|
+
APP.on(APP.EVENTS.SCREEN_BLUR,onScreenBlur);
|
55
|
+
const triggerKeyboardToggle = (status)=>{
|
56
|
+
APP.trigger(APP.EVENTS.KEYBOARD_DID_TOGGLE,{shown:status,status,visible:status,hide : !status});
|
57
|
+
}
|
58
|
+
const keyBoardDidShow = ()=>{
|
59
|
+
APP.trigger(APP.EVENTS.KEYBOARD_DID_SHOW);
|
60
|
+
triggerKeyboardToggle(true);
|
61
|
+
},keyBoardDidHide = ()=>{
|
62
|
+
APP.trigger(APP.EVENTS.KEYBOARD_DID_HIDE);
|
63
|
+
triggerKeyboardToggle(false);
|
64
|
+
}
|
65
|
+
const keyBoardDidShowListener = Keyboard.addListener("keyboardDidShow",keyBoardDidShow);
|
66
|
+
const keyBoardDidHideListener = Keyboard.addListener("keyboardDidHide",keyBoardDidHide);
|
67
|
+
const listener = isTouchDevice() && typeof window !=='undefined' && window && window.visualViewport && typeof window.visualViewport.addEventListener =='function'?
|
68
|
+
() => {
|
69
|
+
const minKeyboardHeight = 300;
|
70
|
+
const screen = Dimensions.get("screen");
|
71
|
+
const newState = screen.height - minKeyboardHeight > window.visualViewport.height
|
72
|
+
if (isKeyboardOpenRef.current != newState) {
|
73
|
+
isKeyboardOpenRef.current = newState;
|
74
|
+
newState ? keyBoardDidShow() : keyBoardDidHide();
|
75
|
+
}
|
76
|
+
} : undefined;
|
77
|
+
if(listener){
|
78
|
+
window.visualViewport.addEventListener('resize', listener);
|
79
|
+
}
|
80
|
+
return ()=>{
|
81
|
+
APP.off(APP.EVENTS.SCREEN_FOCUS,onScreenFocus);
|
82
|
+
APP.off(APP.EVENTS.SCREEN_BLUR,onScreenBlur);
|
83
|
+
keyBoardDidShowListener && keyBoardDidShowListener.remove && keyBoardDidShowListener.remove();
|
84
|
+
keyBoardDidHideListener && keyBoardDidHideListener.remove && keyBoardDidHideListener.remove();
|
85
|
+
if(listener){
|
86
|
+
window.visualViewport.removeEventListener('resize', listener);
|
87
|
+
}
|
88
|
+
if(typeof onUnmount =='function'){
|
89
|
+
onUnmount();
|
90
|
+
}
|
91
|
+
}
|
92
|
+
},[])
|
93
|
+
|
94
|
+
return (
|
95
|
+
<SWRConfig
|
96
|
+
value={{
|
97
|
+
...swrConfig,
|
98
|
+
provider: () => new Map(),
|
99
|
+
isOnline() {
|
100
|
+
/* Customize the network state detector */
|
101
|
+
if(canFetchOffline) return true;
|
102
|
+
return APP.isOnline();
|
103
|
+
},
|
104
|
+
isVisible() {
|
105
|
+
const screen = activeScreenRef.current;
|
106
|
+
if(!screen) return false;
|
107
|
+
if(!screensRef.current[screen]){
|
108
|
+
screensRef.current[screen] = new Date();
|
109
|
+
return false;
|
110
|
+
}
|
111
|
+
const date = screensRef.current[screen];
|
112
|
+
const diff = new Date().getTime() - date.getTime();
|
113
|
+
const timeout = defaultNumber(swrConfig.refreshTimeout,SWR_REFRESH_TIMEOUT)
|
114
|
+
screensRef.current[screen] = new Date();
|
115
|
+
return diff >= timeout ? true : false;
|
116
|
+
},
|
117
|
+
initFocus(callback) {
|
118
|
+
let appState = AppState.currentState
|
119
|
+
const onAppStateChange = (nextAppState) => {
|
120
|
+
/* If it's resuming from background or inactive mode to active one */
|
121
|
+
const active = appState.match(/inactive|background/) && nextAppState === 'active';
|
122
|
+
if (active) {
|
123
|
+
callback()
|
124
|
+
}
|
125
|
+
appState = nextAppState;
|
126
|
+
appStateRef.current = !!active;
|
127
|
+
}
|
128
|
+
// Subscribe to the app state change events
|
129
|
+
const subscription = AppState.addEventListener('change', onAppStateChange);
|
130
|
+
return () => {
|
131
|
+
subscription?.remove()
|
132
|
+
}
|
133
|
+
},
|
134
|
+
initReconnect(cb) {
|
135
|
+
const callback = ()=>{
|
136
|
+
cb();
|
137
|
+
}
|
138
|
+
/* Register the listener with your state provider */
|
139
|
+
APP.on(APP.EVENTS.GO_ONLINE,callback);
|
140
|
+
return ()=>{
|
141
|
+
APP.off(APP.EVENTS.GO_ONLINE,callback);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}}
|
145
|
+
>
|
146
|
+
<App onMount={onMount} render={render} onUnmount={onUnmount} onRender={onRender} init={init}/>
|
147
|
+
</SWRConfig>
|
148
|
+
);
|
149
|
+
};
|
150
|
+
|
151
|
+
setDeviceIdRef.current = ()=>{
|
152
|
+
return new Promise((resolve,reject)=>{
|
153
|
+
showPrompt({
|
154
|
+
title : 'ID unique pour l\'appareil',
|
155
|
+
maxLength : 30,
|
156
|
+
defaultValue : appConfig.getDeviceId(),
|
157
|
+
yes : 'Définir',
|
158
|
+
placeholder : isMobileNative()? "":'Entrer une valeur unique sans espace SVP',
|
159
|
+
no : 'Annuler',
|
160
|
+
onSuccess : ({value})=>{
|
161
|
+
let message = null;
|
162
|
+
if(!value || value.contains(" ")){
|
163
|
+
message = "Merci d'entrer une valeur non nulle ne contenant pas d'espace";
|
164
|
+
}
|
165
|
+
if(value.length > 30){
|
166
|
+
message = "la valeur entrée doit avoir au plus 30 caractères";
|
167
|
+
}
|
168
|
+
if(message){
|
169
|
+
notify.error(message);
|
170
|
+
return reject({message})
|
171
|
+
}
|
172
|
+
resolve(value);
|
173
|
+
notify.success("la valeur ["+value+"] a été définie comme identifiant unique pour l'application instalée sur cet appareil");
|
174
|
+
}
|
175
|
+
})
|
176
|
+
})
|
177
|
+
}
|
package/src/app.config.json
CHANGED
@@ -1,31 +1,31 @@
|
|
1
|
-
{
|
2
|
-
"name": "SALITE",
|
3
|
-
"version": "7.0.0",
|
4
|
-
"description": "Logiciel de gestion commerciale pour PME",
|
5
|
-
"realeaseDateStr": "1er Juin 2021",
|
6
|
-
"releaseDate": "2020-05-23",
|
7
|
-
"devMail": "saliteapp@gmail.com",
|
8
|
-
"devWebsite": "http://fto-consulting.com/salite/",
|
9
|
-
"copyRight": "firsto consulting@Jan 2020",
|
10
|
-
"id": "com.ftc.apps.salite7",
|
11
|
-
"pouchdbNamePrefix": "com.ftc.apps.slite-",
|
12
|
-
"includeFieldsInDatagridFetchOptions": false,
|
13
|
-
"feeds": {
|
14
|
-
"VIDEOS": {
|
15
|
-
"link": "http://fto-consulting.com/salite/feeds",
|
16
|
-
"label": "Bibliothèque vidéo",
|
17
|
-
"provider": "",
|
18
|
-
"icon": "file-video"
|
19
|
-
}
|
20
|
-
},
|
21
|
-
"theme": {
|
22
|
-
"light": {
|
23
|
-
"primary": "#0073B1",
|
24
|
-
"secondary": "#EC008C",
|
25
|
-
"primaryOnSurface": "#0073B1",
|
26
|
-
"secondaryOnSurface": "#EC008C"
|
27
|
-
}
|
28
|
-
},
|
29
|
-
"author": "@fto-consulting",
|
30
|
-
"license": "ISC"
|
1
|
+
{
|
2
|
+
"name": "SALITE",
|
3
|
+
"version": "7.0.0",
|
4
|
+
"description": "Logiciel de gestion commerciale pour PME",
|
5
|
+
"realeaseDateStr": "1er Juin 2021",
|
6
|
+
"releaseDate": "2020-05-23",
|
7
|
+
"devMail": "saliteapp@gmail.com",
|
8
|
+
"devWebsite": "http://fto-consulting.com/salite/",
|
9
|
+
"copyRight": "firsto consulting@Jan 2020",
|
10
|
+
"id": "com.ftc.apps.salite7",
|
11
|
+
"pouchdbNamePrefix": "com.ftc.apps.slite-",
|
12
|
+
"includeFieldsInDatagridFetchOptions": false,
|
13
|
+
"feeds": {
|
14
|
+
"VIDEOS": {
|
15
|
+
"link": "http://fto-consulting.com/salite/feeds",
|
16
|
+
"label": "Bibliothèque vidéo",
|
17
|
+
"provider": "",
|
18
|
+
"icon": "file-video"
|
19
|
+
}
|
20
|
+
},
|
21
|
+
"theme": {
|
22
|
+
"light": {
|
23
|
+
"primary": "#0073B1",
|
24
|
+
"secondary": "#EC008C",
|
25
|
+
"primaryOnSurface": "#0073B1",
|
26
|
+
"secondaryOnSurface": "#EC008C"
|
27
|
+
}
|
28
|
+
},
|
29
|
+
"author": "@fto-consulting",
|
30
|
+
"license": "ISC"
|
31
31
|
}
|