@eohjsc/react-native-smart-city 0.3.48 → 0.3.49
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 +4 -4
- package/src/Images/DevMode/file_copy.svg +3 -0
- package/src/Images/DevMode/inforCode.png +0 -0
- package/src/Images/DevMode/inforCode@2x.png +0 -0
- package/src/Images/DevMode/inforCode@3x.png +0 -0
- package/src/commons/Action/__test__/ItemQuickAction.test.js +0 -7
- package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +1 -8
- package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +1 -1
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +1 -8
- package/src/commons/ActionTemplate/__test__/index.test.js +0 -7
- package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +3 -3
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +1 -1
- package/src/commons/Dashboard/MyUnit/index.js +30 -4
- package/src/commons/DevMode/Styles/ItemStyles.js +1 -1
- package/src/commons/Device/PMSensor/PMSensorIndicatior.js +2 -1
- package/src/commons/FourButtonFilterHistory/__test__/FourButtonFilterHistory.test.js +0 -7
- package/src/commons/Header/HeaderCustom.js +13 -6
- package/src/commons/MediaPlayer/__test__/index.test.js +0 -7
- package/src/commons/MediaPlayerDetail/__test__/MediaPlayerFull.test.js +0 -1
- package/src/commons/MenuActionMore/index.js +4 -1
- package/src/commons/NavBar/index.js +1 -1
- package/src/commons/OneTapTemplate/OptionsDropdownActionTemplate.js +1 -1
- package/src/commons/OneTapTemplate/__test__/NumberUpDownActionTemplate.test.js +0 -7
- package/src/commons/OneTapTemplate/__test__/OptionsDropdownActionTemplate.test.js +0 -7
- package/src/commons/OneTapTemplate/__test__/StatesGridActionTemplate.test.js +0 -7
- package/src/commons/RowItem/index.js +6 -1
- package/src/commons/SelectUnit/index.js +4 -1
- package/src/commons/StatusBox/styles.js +8 -3
- package/src/commons/SubUnit/__test__/Favorites.test.js +0 -7
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +0 -7
- package/src/commons/Tabbar/__test__/index.test.js +0 -7
- package/src/commons/Unit/__test__/HeaderUnit.test.js +0 -5
- package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +0 -7
- package/src/configs/API.js +28 -0
- package/src/configs/AccessibilityLabel.js +13 -0
- package/src/configs/Colors.js +4 -0
- package/src/configs/Constants.js +6 -0
- package/src/configs/Images.js +1 -0
- package/src/context/actionType.ts +8 -1
- package/src/context/mockStore.ts +8 -2
- package/src/context/reducer.ts +27 -4
- package/src/hooks/IoT/__test__/useWatchConfigs.test.js +46 -0
- package/src/hooks/IoT/useBluetoothConnection.js +78 -4
- package/src/hooks/IoT/useBluetoothDeviceConnected.js +1 -1
- package/src/iot/RemoteControl/Bluetooth.js +0 -16
- package/src/iot/RemoteControl/__test__/Bluetooth.test.js +0 -25
- package/src/navigations/Main.js +39 -0
- package/src/navigations/UnitStack.js +18 -5
- package/src/screens/ActivityLog/__test__/FilterPopup.test.js +0 -7
- package/src/screens/ActivityLog/__test__/ItemLog.test.js +0 -7
- package/src/screens/ActivityLog/__test__/index.test.js +0 -7
- package/src/screens/AddLocationMaps/__test__/index.test.js +0 -7
- package/src/screens/AddNewAction/SelectAction.js +22 -18
- package/src/screens/AddNewAction/__test__/SelectAction.test.js +35 -16
- package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +0 -7
- package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +0 -4
- package/src/screens/AddNewGateway/ConnectingZigbeeDevice.js +17 -4
- package/src/screens/AddNewGateway/__test__/AddNewGateway.test.js +0 -4
- package/src/screens/AddNewGateway/__test__/ConnectingModbusDevice.test.js +0 -4
- package/src/screens/AddNewGateway/__test__/ConnectingWifiDevice.test.js +0 -4
- package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +4 -7
- package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +0 -7
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +0 -4
- package/src/screens/AddNewGateway/__test__/SelectModbusGateway.test.js +0 -4
- package/src/screens/AddNewGateway/__test__/SelectZigbeeGateway.test.js +0 -4
- package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +0 -7
- package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +0 -1
- package/src/screens/Device/EditDevice/__test__/EditDevice.test.js +0 -7
- package/src/screens/Device/__test__/detail.test.js +1 -1
- package/src/screens/Device/detail.js +11 -3
- package/src/screens/Device/hooks/useDisconnectedDevice.js +26 -7
- package/src/screens/EmergencyContacts/__test__/hooks.test.js +79 -0
- package/src/screens/Gateway/DetailConfigActionModbus/__test__/index.test.js +138 -0
- package/src/screens/Gateway/DetailConfigActionModbus/index.js +180 -0
- package/src/screens/Gateway/DetailConfigActionModbus/styles.js +9 -0
- package/src/screens/Gateway/DetailConfigActionZigbee/__test__/index.test.js +73 -0
- package/src/screens/Gateway/DetailConfigActionZigbee/index.js +62 -0
- package/src/screens/Gateway/DetailConfigActionZigbee/styles.js +9 -0
- package/src/screens/Gateway/DeviceGatewayInfo/__test__/index.test.js +73 -0
- package/src/screens/Gateway/DeviceGatewayInfo/index.js +96 -0
- package/src/screens/Gateway/DeviceGatewayInfo/styles.js +9 -0
- package/src/screens/Gateway/DeviceModbusDetail/__test__/index.test.js +393 -0
- package/src/screens/Gateway/DeviceModbusDetail/index.js +176 -0
- package/src/screens/Gateway/DeviceModbusDetail/styles.js +12 -0
- package/src/screens/Gateway/DeviceZigbeeDetail/__test__/index.test.js +265 -0
- package/src/screens/Gateway/DeviceZigbeeDetail/index.js +148 -0
- package/src/screens/Gateway/DeviceZigbeeDetail/styles.js +12 -0
- package/src/screens/Gateway/GatewayConnectionMethods/__test__/index.test.js +37 -0
- package/src/screens/Gateway/GatewayConnectionMethods/index.js +73 -0
- package/src/screens/Gateway/GatewayConnectionMethods/styles.js +45 -0
- package/src/screens/Gateway/GatewayDetail/__test__/index.test.js +298 -0
- package/src/screens/Gateway/GatewayDetail/index.js +148 -0
- package/src/screens/Gateway/GatewayDetail/styles.js +12 -0
- package/src/screens/Gateway/GatewayInfo/__test__/index.test.js +137 -0
- package/src/screens/Gateway/GatewayInfo/index.js +115 -0
- package/src/screens/Gateway/GatewayInfo/styles.js +9 -0
- package/src/screens/Gateway/__test__/index.test.js +58 -0
- package/src/screens/Gateway/components/Detail/__test__/index.test.js +46 -0
- package/src/screens/Gateway/components/Detail/index.js +62 -0
- package/src/screens/Gateway/components/Detail/styles.js +27 -0
- package/src/screens/Gateway/components/DetailActionModbus/__test__/index.test.js +49 -0
- package/src/screens/Gateway/components/DetailActionModbus/index.js +52 -0
- package/src/screens/Gateway/components/DetailActionModbus/styles.js +32 -0
- package/src/screens/Gateway/components/DetailConfigAction/__test__/index.test.js +59 -0
- package/src/screens/Gateway/components/DetailConfigAction/index.js +69 -0
- package/src/screens/Gateway/components/DetailConfigAction/styles.js +21 -0
- package/src/screens/Gateway/components/GatewayItem/__test__/index.test.js +1 -1
- package/src/screens/Gateway/components/GatewayItem/styles.js +4 -33
- package/src/screens/Gateway/components/Information/__test__/index.test.js +70 -0
- package/src/screens/Gateway/components/Information/index.js +116 -0
- package/src/screens/Gateway/components/Information/styles.js +59 -0
- package/src/screens/Gateway/components/RowItem/__test__/index.test.js +67 -0
- package/src/screens/Gateway/components/RowItem/index.js +65 -0
- package/src/screens/Gateway/components/RowItem/styles.js +25 -0
- package/src/screens/Gateway/components/TabPaneCT/__test__/index.test.js +98 -0
- package/src/screens/Gateway/components/TabPaneCT/index.js +134 -0
- package/src/screens/Gateway/components/TabPaneCT/styles.js +58 -0
- package/src/screens/Gateway/hooks/__test__/index.test.js +93 -0
- package/src/screens/Gateway/hooks/useGateway.js +110 -16
- package/src/screens/Gateway/index.js +19 -3
- package/src/screens/Gateway/styles.js +6 -8
- package/src/screens/Gateway/utils/index.js +16 -0
- package/src/screens/GuestInfo/__test__/index.test.js +0 -7
- package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +0 -7
- package/src/screens/HanetCamera/__test__/Detail.test.js +0 -7
- package/src/screens/HanetCamera/__test__/ManageAccess.test.js +0 -7
- package/src/screens/HanetCamera/__test__/MemberInfo.test.js +0 -7
- package/src/screens/ManageAccess/__test__/ManageAccess.test.js +0 -6
- package/src/screens/ManageAccess/hooks/__test__/useManageAccess.test.js +0 -7
- package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +0 -7
- package/src/screens/Notification/__test__/Notification.test.js +0 -7
- package/src/screens/PlayBackCamera/__test__/index.test.js +0 -1
- package/src/screens/ScriptDetail/__test__/index.test.js +0 -7
- package/src/screens/SelectUnit/__test__/index.test.js +0 -1
- package/src/screens/SetSchedule/__test__/index.test.js +0 -7
- package/src/screens/Sharing/Components/__test__/DeviceItem.test.js +0 -7
- package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +0 -7
- package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +0 -7
- package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +0 -6
- package/src/screens/Sharing/hooks/__test__/index.test.js +80 -0
- package/src/screens/SmartAccount/ListDevice/__test__/DeviceItem.test.js +0 -7
- package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +0 -6
- package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +1 -6
- package/src/screens/SmartIr/__test__/SelectBrand.test.js +1 -6
- package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +1 -6
- package/src/screens/SubUnit/AddSubUnit.js +1 -0
- package/src/screens/SubUnit/ManageSubUnit.js +4 -1
- package/src/screens/SubUnit/hooks/__test__/useEmergencyContacts.test.js +34 -0
- package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +0 -7
- package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +0 -7
- package/src/screens/Unit/__test__/AddMenu.test.js +0 -7
- package/src/screens/Unit/__test__/CheckSendEmail.test.js +1 -1
- package/src/screens/Unit/__test__/ChooseLocation.test.js +0 -7
- package/src/screens/Unit/__test__/Detail.test.js +1 -8
- package/src/screens/Unit/__test__/SelectAddToFavorites.test.js +0 -7
- package/src/screens/Unit/__test__/SelectAddress.test.js +0 -7
- package/src/screens/Unit/__test__/SmartAccount.test.js +0 -7
- package/src/screens/Unit/__test__/SmartAccountItem.test.js +0 -7
- package/src/screens/Unit/__test__/Summaries.test.js +0 -7
- package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +4 -3
- package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +2 -2
- package/src/utils/I18n/translations/en.json +28 -0
- package/src/utils/I18n/translations/vi.json +28 -0
- package/src/utils/Route/index.js +8 -0
package/src/configs/Constants.js
CHANGED
|
@@ -84,6 +84,12 @@ export const DEVICE_TYPE = {
|
|
|
84
84
|
WIFI_DEVICE: 'WIFI_DEVICE',
|
|
85
85
|
MODBUS: 'MODBUS',
|
|
86
86
|
};
|
|
87
|
+
export const PERMISSION_TYPE = {
|
|
88
|
+
ACTION: 'ACTION',
|
|
89
|
+
CONFIG: 'CONFIG',
|
|
90
|
+
CONFIG_WRITE: 'CONFIG_WRITE',
|
|
91
|
+
CONFIG_READ: 'CONFIG_READ',
|
|
92
|
+
};
|
|
87
93
|
|
|
88
94
|
const marginItem = 12;
|
|
89
95
|
const marginHorizontal = 16;
|
package/src/configs/Images.js
CHANGED
|
@@ -18,6 +18,8 @@ export const Action = {
|
|
|
18
18
|
STAR_SCRIPTS: 'STAR_SCRIPTS',
|
|
19
19
|
UNSTAR_SCRIPTS: 'UNSTAR_SCRIPTS',
|
|
20
20
|
SET_BLUETOOTH_CONNECTED_DEVICE: 'SET_BLUETOOTH_CONNECTED_DEVICE',
|
|
21
|
+
SET_BLUETOOTH_PERM_REQUESTED: 'SET_BLUETOOTH_PERM_REQUESTED',
|
|
22
|
+
SET_BLUETOOTH_PERM_GRANTED: 'SET_BLUETOOTH_PERM_GRANTED',
|
|
21
23
|
SET_HOME_ASSISTANT_CONNECTIONS: 'SET_HOME_ASSISTANT_CONNECTIONS',
|
|
22
24
|
CHANGE_HOME_ASSISTANT_CONN_STATE: 'CHANGE_HOME_ASSISTANT_CONN_STATE',
|
|
23
25
|
SET_LG_THINQ_CONNECTED: 'SET_LG_THINQ_CONNECTED',
|
|
@@ -87,7 +89,6 @@ export type AppType = {
|
|
|
87
89
|
isFirstOpenCamera: boolean;
|
|
88
90
|
isLavidaSource: boolean;
|
|
89
91
|
isConnectWifiGateway: boolean;
|
|
90
|
-
isBluetoothEnabled: boolean;
|
|
91
92
|
isNetworkConnected: boolean;
|
|
92
93
|
camera_opened: any[];
|
|
93
94
|
notificationData: any;
|
|
@@ -115,3 +116,9 @@ export type DevModeType = {
|
|
|
115
116
|
isEditingTemplate: boolean;
|
|
116
117
|
isInEditTemplateScreen: boolean;
|
|
117
118
|
};
|
|
119
|
+
|
|
120
|
+
export type BluetoothType = {
|
|
121
|
+
isEnabled: boolean;
|
|
122
|
+
permissionsGranted: boolean;
|
|
123
|
+
permissionsRequested: boolean;
|
|
124
|
+
};
|
package/src/context/mockStore.ts
CHANGED
|
@@ -35,7 +35,6 @@ export const mockDataStore: ContextData = {
|
|
|
35
35
|
isFirstOpenCamera: true,
|
|
36
36
|
isLavidaSource: false,
|
|
37
37
|
isConnectWifiGateway: false,
|
|
38
|
-
isBluetoothEnabled: true,
|
|
39
38
|
isNetworkConnected: true,
|
|
40
39
|
camera_opened: [],
|
|
41
40
|
isLockWhenPickColor: false,
|
|
@@ -61,6 +60,11 @@ export const mockDataStore: ContextData = {
|
|
|
61
60
|
isEditingTemplate: false,
|
|
62
61
|
isInEditTemplateScreen: false,
|
|
63
62
|
},
|
|
63
|
+
bluetooth: {
|
|
64
|
+
isEnabled: true,
|
|
65
|
+
permissionsGranted: false,
|
|
66
|
+
permissionsRequested: false,
|
|
67
|
+
},
|
|
64
68
|
};
|
|
65
69
|
|
|
66
70
|
export const mockSCStore = (data: ContextData): ContextData => {
|
|
@@ -86,7 +90,6 @@ export const mockSCStore = (data: ContextData): ContextData => {
|
|
|
86
90
|
app: {
|
|
87
91
|
isFirstOpenCamera: true,
|
|
88
92
|
isConnectWifiGateway: false,
|
|
89
|
-
isBluetoothEnabled: true,
|
|
90
93
|
isNetworkConnected: true,
|
|
91
94
|
isLockWhenPickColor: false,
|
|
92
95
|
},
|
|
@@ -122,5 +125,8 @@ export const mockSCStore = (data: ContextData): ContextData => {
|
|
|
122
125
|
isEditingTemplate: false,
|
|
123
126
|
isInEditTemplateScreen: false,
|
|
124
127
|
},
|
|
128
|
+
bluetooth: {
|
|
129
|
+
...mockDataStore.bluetooth,
|
|
130
|
+
},
|
|
125
131
|
};
|
|
126
132
|
};
|
package/src/context/reducer.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
AppType,
|
|
13
13
|
IoTType,
|
|
14
14
|
DevModeType,
|
|
15
|
+
BluetoothType,
|
|
15
16
|
} from './actionType';
|
|
16
17
|
import { uniq, reduce } from 'lodash';
|
|
17
18
|
|
|
@@ -28,6 +29,7 @@ export type ContextData = {
|
|
|
28
29
|
valueEvaluations: {};
|
|
29
30
|
fetchedValueEvaluationUnits: Array<number>;
|
|
30
31
|
devMode: DevModeType;
|
|
32
|
+
bluetooth: BluetoothType;
|
|
31
33
|
percent: number;
|
|
32
34
|
};
|
|
33
35
|
|
|
@@ -60,7 +62,6 @@ export const initialState = {
|
|
|
60
62
|
isFirstOpenCamera: true,
|
|
61
63
|
isLavidaSource: false,
|
|
62
64
|
isConnectWifiGateway: false,
|
|
63
|
-
isBluetoothEnabled: false,
|
|
64
65
|
isNetworkConnected: false,
|
|
65
66
|
camera_opened: [],
|
|
66
67
|
notificationData: null,
|
|
@@ -88,6 +89,11 @@ export const initialState = {
|
|
|
88
89
|
isEditingTemplate: false,
|
|
89
90
|
isInEditTemplateScreen: false,
|
|
90
91
|
},
|
|
92
|
+
bluetooth: {
|
|
93
|
+
isEnabled: false,
|
|
94
|
+
permissionsGranted: false,
|
|
95
|
+
permissionsRequested: false,
|
|
96
|
+
},
|
|
91
97
|
};
|
|
92
98
|
|
|
93
99
|
export const reducer = (currentState: ContextData, action: Action) => {
|
|
@@ -187,9 +193,9 @@ export const reducer = (currentState: ContextData, action: Action) => {
|
|
|
187
193
|
case Action.SET_BLUETOOTH_STATE: {
|
|
188
194
|
return {
|
|
189
195
|
...currentState,
|
|
190
|
-
|
|
191
|
-
...currentState.
|
|
192
|
-
|
|
196
|
+
bluetooth: {
|
|
197
|
+
...currentState.bluetooth,
|
|
198
|
+
isEnabled: payload,
|
|
193
199
|
},
|
|
194
200
|
};
|
|
195
201
|
}
|
|
@@ -308,6 +314,23 @@ export const reducer = (currentState: ContextData, action: Action) => {
|
|
|
308
314
|
},
|
|
309
315
|
},
|
|
310
316
|
};
|
|
317
|
+
case Action.SET_BLUETOOTH_PERM_REQUESTED:
|
|
318
|
+
return {
|
|
319
|
+
...currentState,
|
|
320
|
+
bluetooth: {
|
|
321
|
+
...currentState.bluetooth,
|
|
322
|
+
permissionsRequested: true,
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
case Action.SET_BLUETOOTH_PERM_GRANTED:
|
|
326
|
+
return {
|
|
327
|
+
...currentState,
|
|
328
|
+
bluetooth: {
|
|
329
|
+
...currentState.bluetooth,
|
|
330
|
+
permissionsGranted: payload,
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
|
|
311
334
|
case Action.SET_HOME_ASSISTANT_CONNECTIONS:
|
|
312
335
|
return {
|
|
313
336
|
...currentState,
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { renderHook } from '@testing-library/react-hooks';
|
|
3
|
+
import { SCProvider } from '../../../context';
|
|
4
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
5
|
+
import { useWatchConfigs } from '../index';
|
|
6
|
+
import { watchMultiConfigs, unwatchMultiConfigs } from '../../../iot/Monitor';
|
|
7
|
+
|
|
8
|
+
const mockedSetAction = jest.fn();
|
|
9
|
+
|
|
10
|
+
const wrapper = ({ children }) => <SCProvider>{children}</SCProvider>;
|
|
11
|
+
|
|
12
|
+
jest.mock('react', () => {
|
|
13
|
+
return {
|
|
14
|
+
...jest.requireActual('react'),
|
|
15
|
+
useCallback: (func) => func(),
|
|
16
|
+
useContext: () => ({
|
|
17
|
+
stateData: mockSCStore({}),
|
|
18
|
+
setAction: mockedSetAction,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
jest.mock('@react-navigation/native', () => {
|
|
24
|
+
return {
|
|
25
|
+
...jest.requireActual('@react-navigation/native'),
|
|
26
|
+
useFocusEffect: (func) => func(),
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
jest.mock('../../../iot/Monitor');
|
|
31
|
+
|
|
32
|
+
describe('Test useWatchConfigs', () => {
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.useFakeTimers();
|
|
35
|
+
watchMultiConfigs.mockClear();
|
|
36
|
+
unwatchMultiConfigs.mockClear();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('test unitId null', async () => {
|
|
40
|
+
renderHook(() => useWatchConfigs([1]), {
|
|
41
|
+
wrapper,
|
|
42
|
+
});
|
|
43
|
+
expect(watchMultiConfigs).toBeCalledWith([1]);
|
|
44
|
+
expect(unwatchMultiConfigs).toBeCalledWith([1]);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -1,10 +1,32 @@
|
|
|
1
|
-
import { useContext, useCallback } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import { useContext, useCallback, useRef, useEffect } from 'react';
|
|
2
|
+
import { AppState, Platform } from 'react-native';
|
|
3
|
+
import { SCContext, useSCContextSelector } from '../../context';
|
|
3
4
|
import { Action } from '../../context/actionType';
|
|
4
5
|
import { scanBluetoothDevices } from '../../iot/RemoteControl/Bluetooth';
|
|
6
|
+
import Permissions from 'react-native-permissions';
|
|
7
|
+
import { OpenSetting } from '../../utils/Permission/common';
|
|
8
|
+
import { useTranslations } from '../Common/useTranslations';
|
|
9
|
+
|
|
10
|
+
const permissions = [
|
|
11
|
+
'android.permission.BLUETOOTH_CONNECT',
|
|
12
|
+
'android.permission.BLUETOOTH_SCAN',
|
|
13
|
+
'android.permission.BLUETOOTH_ADVERTISE',
|
|
14
|
+
];
|
|
5
15
|
|
|
6
16
|
const useBluetoothConnection = () => {
|
|
17
|
+
const t = useTranslations();
|
|
18
|
+
const appState = useRef(AppState.currentState);
|
|
19
|
+
|
|
7
20
|
const { setAction } = useContext(SCContext);
|
|
21
|
+
const isEnabled = useSCContextSelector((state) => state.bluetooth.isEnabled);
|
|
22
|
+
const permissionsRequested = useSCContextSelector(
|
|
23
|
+
(state) => state.bluetooth.permissionsRequested
|
|
24
|
+
);
|
|
25
|
+
const permissionsGranted =
|
|
26
|
+
Platform.OS === 'ios'
|
|
27
|
+
? true
|
|
28
|
+
: // eslint-disable-next-line react-hooks/rules-of-hooks
|
|
29
|
+
useSCContextSelector((state) => state.bluetooth.permissionsGranted);
|
|
8
30
|
|
|
9
31
|
const onDeviceFound = useCallback(async (name, device) => {
|
|
10
32
|
setAction(Action.SET_BLUETOOTH_CONNECTED_DEVICE, { name, device });
|
|
@@ -13,12 +35,64 @@ const useBluetoothConnection = () => {
|
|
|
13
35
|
|
|
14
36
|
const bluetoothScanDevices = useCallback(
|
|
15
37
|
(addresses) => {
|
|
16
|
-
scanBluetoothDevices(addresses, onDeviceFound);
|
|
38
|
+
permissionsGranted && scanBluetoothDevices(addresses, onDeviceFound);
|
|
17
39
|
},
|
|
18
|
-
[onDeviceFound]
|
|
40
|
+
[permissionsGranted, onDeviceFound]
|
|
19
41
|
);
|
|
20
42
|
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const subscription = AppState.addEventListener(
|
|
45
|
+
'change',
|
|
46
|
+
async (nextAppState) => {
|
|
47
|
+
if (
|
|
48
|
+
appState.current.match(/inactive|background/) &&
|
|
49
|
+
nextAppState === 'active'
|
|
50
|
+
) {
|
|
51
|
+
const results = await Permissions.checkMultiple(permissions);
|
|
52
|
+
const granted = Object.values(results).every((result) =>
|
|
53
|
+
[
|
|
54
|
+
Permissions.RESULTS.GRANTED,
|
|
55
|
+
Permissions.RESULTS.UNAVAILABLE,
|
|
56
|
+
].includes(result)
|
|
57
|
+
);
|
|
58
|
+
setAction(Action.SET_BLUETOOTH_PERM_GRANTED, granted);
|
|
59
|
+
}
|
|
60
|
+
appState.current = nextAppState;
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return () => {
|
|
65
|
+
subscription?.remove();
|
|
66
|
+
};
|
|
67
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
68
|
+
}, []);
|
|
69
|
+
|
|
70
|
+
const requestPerm = useCallback(async () => {
|
|
71
|
+
let results = await Permissions.requestMultiple(permissions);
|
|
72
|
+
const blocked = Object.values(results).some(
|
|
73
|
+
(result) => result === Permissions.RESULTS.BLOCKED
|
|
74
|
+
);
|
|
75
|
+
if (blocked) {
|
|
76
|
+
OpenSetting(
|
|
77
|
+
t('bluetooth_rationale_title'),
|
|
78
|
+
t('bluetooth_rationale_message')
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
const granted = Object.values(results).every((result) =>
|
|
82
|
+
[Permissions.RESULTS.GRANTED, Permissions.RESULTS.UNAVAILABLE].includes(
|
|
83
|
+
result
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
setAction(Action.SET_BLUETOOTH_PERM_GRANTED, granted);
|
|
87
|
+
setAction(Action.SET_BLUETOOTH_PERM_REQUESTED);
|
|
88
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
89
|
+
}, []);
|
|
90
|
+
|
|
21
91
|
return {
|
|
92
|
+
isEnabled,
|
|
93
|
+
permissionsRequested,
|
|
94
|
+
permissionsGranted,
|
|
95
|
+
requestPerm,
|
|
22
96
|
onDeviceFound,
|
|
23
97
|
bluetoothScanDevices,
|
|
24
98
|
};
|
|
@@ -5,7 +5,7 @@ const useBluetoothDeviceConnected = (device) => {
|
|
|
5
5
|
(state) => state.iot.bluetooth.connectedDevices
|
|
6
6
|
);
|
|
7
7
|
const isBluetoothEnabled = useSCContextSelector((state) => {
|
|
8
|
-
return state.
|
|
8
|
+
return state.bluetooth.isEnabled;
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
const isConnected =
|
|
@@ -4,23 +4,11 @@ import t from '../../hooks/Common/useTranslations';
|
|
|
4
4
|
import base64 from 'react-native-base64';
|
|
5
5
|
import { BleManager } from 'react-native-ble-plx';
|
|
6
6
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
7
|
-
import { PermissionsAndroid } from 'react-native';
|
|
8
7
|
|
|
9
8
|
const bluetoothDevices = {};
|
|
10
9
|
const needToScanDevices = [];
|
|
11
10
|
const bleManager = new BleManager();
|
|
12
11
|
|
|
13
|
-
export const requestBluetoothPermissions = async () => {
|
|
14
|
-
const results = await PermissionsAndroid.requestMultiple([
|
|
15
|
-
'android.permission.BLUETOOTH_CONNECT',
|
|
16
|
-
'android.permission.BLUETOOTH_SCAN',
|
|
17
|
-
'android.permission.BLUETOOTH_ADVERTISE',
|
|
18
|
-
]);
|
|
19
|
-
return Object.values(results).every(
|
|
20
|
-
(result) => result === PermissionsAndroid.RESULTS.GRANTED
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
12
|
export const SEND_COMMAND_OVER_BLUETOOTH_FAIL =
|
|
25
13
|
'SEND_COMMAND_OVER_BLUETOOTH_FAIL';
|
|
26
14
|
|
|
@@ -45,10 +33,6 @@ export const scanBluetoothDevices = async (names, onDeviceFound) => {
|
|
|
45
33
|
};
|
|
46
34
|
|
|
47
35
|
export const realScanBluetoothDevices = async (onDeviceFound) => {
|
|
48
|
-
const permissionsGranted = await requestBluetoothPermissions();
|
|
49
|
-
if (!permissionsGranted) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
36
|
if (!needToScanDevices.length) {
|
|
53
37
|
return;
|
|
54
38
|
}
|
|
@@ -12,20 +12,6 @@ const bleManager = new BleManager();
|
|
|
12
12
|
|
|
13
13
|
const mockOnDeviceFound = jest.fn();
|
|
14
14
|
|
|
15
|
-
const mockRequestMultiplePerms = jest.fn();
|
|
16
|
-
|
|
17
|
-
jest.mock(
|
|
18
|
-
'react-native/Libraries/PermissionsAndroid/PermissionsAndroid',
|
|
19
|
-
() => {
|
|
20
|
-
return {
|
|
21
|
-
...jest.requireActual(
|
|
22
|
-
'react-native/Libraries/PermissionsAndroid/PermissionsAndroid'
|
|
23
|
-
),
|
|
24
|
-
requestMultiple: mockRequestMultiplePerms,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
|
|
29
15
|
describe('Test IOT Bluetooth', () => {
|
|
30
16
|
beforeEach(() => {
|
|
31
17
|
mockOnDeviceFound.mockClear();
|
|
@@ -33,9 +19,6 @@ describe('Test IOT Bluetooth', () => {
|
|
|
33
19
|
bleManager.stopDeviceScan.mockClear();
|
|
34
20
|
clearNeedToScanDevices();
|
|
35
21
|
clearFoundDevices();
|
|
36
|
-
mockRequestMultiplePerms.mockImplementation(async (perms) =>
|
|
37
|
-
perms.map(() => 'granted')
|
|
38
|
-
);
|
|
39
22
|
});
|
|
40
23
|
|
|
41
24
|
afterEach(() => {
|
|
@@ -48,14 +31,6 @@ describe('Test IOT Bluetooth', () => {
|
|
|
48
31
|
expect(bleManager.startDeviceScan).toBeCalled();
|
|
49
32
|
});
|
|
50
33
|
|
|
51
|
-
test('Scan bluetooth device not scan without permissions', async () => {
|
|
52
|
-
mockRequestMultiplePerms.mockImplementation(async (perms) =>
|
|
53
|
-
perms.map(() => 'denied')
|
|
54
|
-
);
|
|
55
|
-
await scanBluetoothDevices(['123456'], mockOnDeviceFound);
|
|
56
|
-
expect(bleManager.startDeviceScan).not.toBeCalled();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
34
|
test('When look for bluetooth name, hardware will auto stop after period of time', async () => {
|
|
60
35
|
jest.useFakeTimers();
|
|
61
36
|
await scanBluetoothDevices(['123456'], mockOnDeviceFound);
|
package/src/navigations/Main.js
CHANGED
|
@@ -27,6 +27,15 @@ import TemplateDetail from '../screens/Template/detail';
|
|
|
27
27
|
import Information from '../screens/Template/Information';
|
|
28
28
|
import GatewayList from '../screens/Template/GatewayList';
|
|
29
29
|
import EditTemplate from '../screens/Template/EditTemplate';
|
|
30
|
+
import GatewayDetail from '../screens/Gateway/GatewayDetail';
|
|
31
|
+
import GatewayInfo from '../screens/Gateway/GatewayInfo';
|
|
32
|
+
import GatewayConnectionMethods from '../screens/Gateway/GatewayConnectionMethods';
|
|
33
|
+
import DeviceZigbeeDetail from '../screens/Gateway/DeviceZigbeeDetail';
|
|
34
|
+
import DeviceGatewayInfo from '../screens/Gateway/DeviceGatewayInfo';
|
|
35
|
+
import DetailConfigActionZigbee from '../screens/Gateway/DetailConfigActionZigbee';
|
|
36
|
+
import DeviceModbusDetail from '../screens/Gateway/DeviceModbusDetail';
|
|
37
|
+
import DetailConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
38
|
+
import DetailChildConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
30
39
|
|
|
31
40
|
const Tab = createBottomTabNavigator();
|
|
32
41
|
const Drawer = createDrawerNavigator();
|
|
@@ -132,6 +141,36 @@ const DevModeStack = () => {
|
|
|
132
141
|
>
|
|
133
142
|
<Stack.Screen component={DrawerScreen} name={Routes.DrawerScreen} />
|
|
134
143
|
<Stack.Screen component={TemplateDetail} name={Routes.TemplateDetail} />
|
|
144
|
+
<Stack.Screen component={GatewayDetail} name={Routes.GatewayDetail} />
|
|
145
|
+
<Stack.Screen component={GatewayInfo} name={Routes.GatewayInfo} />
|
|
146
|
+
<Stack.Screen
|
|
147
|
+
component={DeviceGatewayInfo}
|
|
148
|
+
name={Routes.DeviceGatewayInfo}
|
|
149
|
+
/>
|
|
150
|
+
<Stack.Screen
|
|
151
|
+
component={GatewayConnectionMethods}
|
|
152
|
+
name={Routes.GatewayConnectionMethods}
|
|
153
|
+
/>
|
|
154
|
+
<Stack.Screen
|
|
155
|
+
component={DeviceZigbeeDetail}
|
|
156
|
+
name={Routes.DeviceZigbeeDetail}
|
|
157
|
+
/>
|
|
158
|
+
<Stack.Screen
|
|
159
|
+
component={DeviceModbusDetail}
|
|
160
|
+
name={Routes.DeviceModbusDetail}
|
|
161
|
+
/>
|
|
162
|
+
<Stack.Screen
|
|
163
|
+
component={DetailConfigActionZigbee}
|
|
164
|
+
name={Routes.DetailConfigActionZigbee}
|
|
165
|
+
/>
|
|
166
|
+
<Stack.Screen
|
|
167
|
+
component={DetailConfigActionModbus}
|
|
168
|
+
name={Routes.DetailConfigActionModbus}
|
|
169
|
+
/>
|
|
170
|
+
<Stack.Screen
|
|
171
|
+
component={DetailChildConfigActionModbus}
|
|
172
|
+
name={Routes.DetailChildConfigActionModbus}
|
|
173
|
+
/>
|
|
135
174
|
<Stack.Screen component={Information} name={Routes.Information} />
|
|
136
175
|
<Stack.Screen component={GatewayList} name={Routes.GatewayList} />
|
|
137
176
|
<Stack.Screen component={EditTemplate} name={Routes.EditTemplate} />
|
|
@@ -82,22 +82,35 @@ export const UnitStack = memo((props) => {
|
|
|
82
82
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
83
83
|
}, []);
|
|
84
84
|
|
|
85
|
-
const {
|
|
85
|
+
const {
|
|
86
|
+
isEnabled: isBluetoothEnabled,
|
|
87
|
+
permissionsRequested: bluetoothPermRequested,
|
|
88
|
+
permissionsGranted: bluetoothPermGranted,
|
|
89
|
+
requestPerm: requestBluetoothPerm,
|
|
90
|
+
onDeviceFound,
|
|
91
|
+
} = useBluetoothConnection();
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
!bluetoothPermRequested && requestBluetoothPerm();
|
|
95
|
+
}, [bluetoothPermRequested, requestBluetoothPerm]);
|
|
86
96
|
|
|
87
97
|
useEffect(() => {
|
|
88
98
|
const subscription = bleManager.onStateChange((state) => {
|
|
89
99
|
const connected = state === 'PoweredOn';
|
|
90
100
|
setAction(Action.SET_BLUETOOTH_STATE, connected);
|
|
91
|
-
|
|
92
|
-
ToastBottomHelper.success(t('text_ble_is_powered_on'));
|
|
93
|
-
realScanBluetoothDevices(onDeviceFound);
|
|
94
|
-
}
|
|
101
|
+
connected && ToastBottomHelper.success(t('text_ble_is_powered_on'));
|
|
95
102
|
}, true);
|
|
96
103
|
|
|
97
104
|
return () => subscription.remove();
|
|
98
105
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
99
106
|
}, []);
|
|
100
107
|
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
isBluetoothEnabled &&
|
|
110
|
+
bluetoothPermGranted &&
|
|
111
|
+
realScanBluetoothDevices(onDeviceFound);
|
|
112
|
+
}, [isBluetoothEnabled, bluetoothPermGranted, onDeviceFound]);
|
|
113
|
+
|
|
101
114
|
useEffect(() => {
|
|
102
115
|
const fetchFavoriteDevices = async () => {
|
|
103
116
|
const id = unitId || unitData?.id;
|
|
@@ -17,13 +17,6 @@ const wrapComponent = (props) => (
|
|
|
17
17
|
</SCProvider>
|
|
18
18
|
);
|
|
19
19
|
|
|
20
|
-
jest.mock('react', () => {
|
|
21
|
-
return {
|
|
22
|
-
...jest.requireActual('react'),
|
|
23
|
-
memo: (x) => x,
|
|
24
|
-
};
|
|
25
|
-
});
|
|
26
|
-
|
|
27
20
|
it('test FilterPopup', async () => {
|
|
28
21
|
Date.now = jest.fn(() => new Date('2021-09-09T10:00:00.000Z'));
|
|
29
22
|
const mockOnHide = jest.fn();
|
|
@@ -12,13 +12,6 @@ const wrapComponent = (props) => (
|
|
|
12
12
|
</SCProvider>
|
|
13
13
|
);
|
|
14
14
|
|
|
15
|
-
jest.mock('react', () => {
|
|
16
|
-
return {
|
|
17
|
-
...jest.requireActual('react'),
|
|
18
|
-
memo: (x) => x,
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
|
|
22
15
|
it('test ItemLog smart assistant', async () => {
|
|
23
16
|
let tree;
|
|
24
17
|
let props = {
|
|
@@ -25,13 +25,6 @@ jest.mock('react-redux', () => {
|
|
|
25
25
|
};
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
jest.mock('react', () => {
|
|
29
|
-
return {
|
|
30
|
-
...jest.requireActual('react'),
|
|
31
|
-
memo: (x) => x,
|
|
32
|
-
};
|
|
33
|
-
});
|
|
34
|
-
|
|
35
28
|
const mock = new MockAdapter(api.axiosInstance);
|
|
36
29
|
|
|
37
30
|
const wrapComponent = (route) => (
|
|
@@ -37,13 +37,6 @@ jest.mock('@react-navigation/native', () => {
|
|
|
37
37
|
};
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
jest.mock('react', () => {
|
|
41
|
-
return {
|
|
42
|
-
...jest.requireActual('react'),
|
|
43
|
-
memo: (x) => x,
|
|
44
|
-
};
|
|
45
|
-
});
|
|
46
|
-
|
|
47
40
|
jest.mock('react-native-maps', () => {
|
|
48
41
|
const { forwardRef } = require('react');
|
|
49
42
|
const { View } = require('react-native');
|
|
@@ -252,6 +252,7 @@ const SelectAction = memo(({ route }) => {
|
|
|
252
252
|
case 'three_button_action_template':
|
|
253
253
|
case 'OnOffSimpleActionTemplate':
|
|
254
254
|
case 'curtain_action_template':
|
|
255
|
+
case 'OnOffSmartLockActionTemplate':
|
|
255
256
|
index = newActions.findIndex((item) => {
|
|
256
257
|
return (
|
|
257
258
|
item.template === 'on_off_button_action_template' ||
|
|
@@ -264,13 +265,15 @@ const SelectAction = memo(({ route }) => {
|
|
|
264
265
|
});
|
|
265
266
|
break;
|
|
266
267
|
|
|
267
|
-
case 'OptionsDropdownActionTemplate':
|
|
268
|
-
case 'NumberUpDownActionTemplate':
|
|
269
268
|
case 'StatesGridActionTemplate':
|
|
270
269
|
index = newActions.findIndex(
|
|
271
270
|
(item) => item.template === action.template
|
|
272
271
|
);
|
|
273
272
|
break;
|
|
273
|
+
case 'OptionsDropdownActionTemplate':
|
|
274
|
+
case 'NumberUpDownActionTemplate':
|
|
275
|
+
index = newActions.findIndex((item) => item.action === action.action);
|
|
276
|
+
break;
|
|
274
277
|
}
|
|
275
278
|
|
|
276
279
|
if (index < 0) {
|
|
@@ -438,13 +441,13 @@ const SelectAction = memo(({ route }) => {
|
|
|
438
441
|
});
|
|
439
442
|
|
|
440
443
|
const RenderActionItem = ({ device, data, onSelectAction }) => {
|
|
441
|
-
if (!data) {
|
|
444
|
+
if (!data.length) {
|
|
442
445
|
return null;
|
|
443
446
|
}
|
|
444
447
|
const actionTemplate = [];
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
+
const optionsDropdownActionTemplates = [];
|
|
449
|
+
const numberUpDownActionTemplates = [];
|
|
450
|
+
const statesGridActionTemplates = [];
|
|
448
451
|
|
|
449
452
|
data.forEach((item) => {
|
|
450
453
|
switch (item.template) {
|
|
@@ -457,13 +460,13 @@ const RenderActionItem = ({ device, data, onSelectAction }) => {
|
|
|
457
460
|
actionTemplate.push(item);
|
|
458
461
|
break;
|
|
459
462
|
case 'OptionsDropdownActionTemplate':
|
|
460
|
-
|
|
463
|
+
optionsDropdownActionTemplates.push(item);
|
|
461
464
|
break;
|
|
462
465
|
case 'NumberUpDownActionTemplate':
|
|
463
|
-
|
|
466
|
+
numberUpDownActionTemplates.push(item);
|
|
464
467
|
break;
|
|
465
468
|
case 'StatesGridActionTemplate':
|
|
466
|
-
|
|
469
|
+
statesGridActionTemplates.push(item);
|
|
467
470
|
break;
|
|
468
471
|
}
|
|
469
472
|
});
|
|
@@ -481,27 +484,28 @@ const RenderActionItem = ({ device, data, onSelectAction }) => {
|
|
|
481
484
|
onSelectAction={handleOnSelectAction}
|
|
482
485
|
/>
|
|
483
486
|
)}
|
|
484
|
-
{
|
|
487
|
+
{numberUpDownActionTemplates.map((item) => (
|
|
485
488
|
<NumberUpDownActionTemplate
|
|
486
489
|
device={device}
|
|
487
|
-
data={
|
|
490
|
+
data={item}
|
|
488
491
|
onSelectAction={handleOnSelectAction}
|
|
489
492
|
/>
|
|
490
|
-
)}
|
|
491
|
-
|
|
493
|
+
))}
|
|
494
|
+
|
|
495
|
+
{optionsDropdownActionTemplates.map((item) => (
|
|
492
496
|
<OptionsDropdownActionTemplate
|
|
493
497
|
device={device}
|
|
494
|
-
data={
|
|
498
|
+
data={item}
|
|
495
499
|
onSelectAction={handleOnSelectAction}
|
|
496
500
|
/>
|
|
497
|
-
)}
|
|
498
|
-
{
|
|
501
|
+
))}
|
|
502
|
+
{statesGridActionTemplates.map((item) => (
|
|
499
503
|
<StatesGridActionTemplate
|
|
500
504
|
device={device}
|
|
501
|
-
data={
|
|
505
|
+
data={item}
|
|
502
506
|
onSelectAction={handleOnSelectAction}
|
|
503
507
|
/>
|
|
504
|
-
)}
|
|
508
|
+
))}
|
|
505
509
|
</>
|
|
506
510
|
);
|
|
507
511
|
};
|