@eohjsc/react-native-smart-city 0.3.42 → 0.3.45

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.
Files changed (26) hide show
  1. package/package.json +1 -1
  2. package/src/commons/Action/ItemQuickAction.js +20 -52
  3. package/src/commons/Action/__test__/ItemQuickAction.test.js +73 -235
  4. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +1 -1
  5. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +4 -3
  6. package/src/commons/AlertAction/index.js +1 -1
  7. package/src/configs/Constants.js +1 -0
  8. package/src/iot/RemoteControl/Bluetooth.js +19 -3
  9. package/src/iot/RemoteControl/__test__/Bluetooth.test.js +39 -11
  10. package/src/navigations/UnitStack.js +2 -1
  11. package/src/screens/AddNewGateway/ConnectingWifiDevice.js +48 -23
  12. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +14 -12
  13. package/src/screens/AddNewGateway/RenameNewDevices.js +36 -16
  14. package/src/screens/AddNewGateway/RenameNewDevicesStyles.js +0 -8
  15. package/src/screens/AddNewGateway/ScanGatewayQR.js +2 -2
  16. package/src/screens/AddNewGateway/ScanModbusQR.js +4 -1
  17. package/src/screens/AddNewGateway/ScanWifiDeviceQR.js +2 -2
  18. package/src/screens/AddNewGateway/SelectDeviceType.js +3 -3
  19. package/src/screens/AddNewGateway/ShareWifiPassword.js +7 -2
  20. package/src/screens/AddNewGateway/__test__/ConnectingWifiDevice.test.js +9 -1
  21. package/src/screens/AddNewGateway/__test__/ConnectingWifiGuide.test.js +1 -1
  22. package/src/screens/AddNewGateway/__test__/ScanGatewayQR.test.js +12 -0
  23. package/src/screens/Device/detail.js +7 -3
  24. package/src/screens/UVIndexGuide/index.js +8 -13
  25. package/src/utils/Apis/axios.js +5 -0
  26. package/src/utils/__test__/Utils.test.js +115 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.3.42",
4
+ "version": "0.3.45",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -11,46 +11,32 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
11
11
  const [action, setAction] = useState(sensor.action);
12
12
  // eslint-disable-next-line no-unused-vars
13
13
  const [configValues, _] = useConfigGlobalState('configValues');
14
+ const [isOn, setIsOn] = useState(false);
14
15
 
15
16
  const sendRemoteCommand = useRemoteControl();
16
17
 
17
- const revertActionUpdate = useCallback(
18
- (value, on_action, on_status, off_action, off_status) => {
19
- setIsSendingCommand(false);
20
- if (value) {
21
- setAction(off_action);
22
- setStatus && setStatus(on_status);
23
- } else {
24
- setAction(on_action);
25
- setStatus && setStatus(off_status);
26
- }
27
- },
28
- [setStatus]
29
- );
30
-
31
- const statusCallback = useCallback(
32
- (value) => {
33
- revertActionUpdate(
34
- value,
35
- sensor.quick_action.on_action,
36
- sensor.quick_action.on_status,
37
- sensor.quick_action.off_action,
38
- sensor.quick_action.off_status
39
- );
40
- },
41
- [sensor, revertActionUpdate]
42
- );
18
+ useEffect(() => {
19
+ if (!(sensor.quick_action?.config_id in configValues)) {
20
+ return;
21
+ }
22
+ const configValue = configValues[sensor.quick_action.config_id];
23
+ setIsOn(configValue?.value);
24
+ }, [sensor, configValues]);
43
25
 
44
26
  useEffect(() => {
45
27
  if (!sensor.quick_action) {
46
28
  return;
47
29
  }
48
- if (!(sensor.quick_action.config_id in configValues)) {
49
- return;
30
+
31
+ if (isOn) {
32
+ setAction(sensor.quick_action.off_action);
33
+ setStatus && setStatus(sensor.quick_action.on_status);
34
+ } else {
35
+ setAction(sensor.quick_action.on_action);
36
+ setStatus && setStatus(sensor.quick_action.off_status);
50
37
  }
51
- const configValue = configValues[sensor.quick_action.config_id];
52
- statusCallback(configValue?.value);
53
- }, [sensor, configValues, statusCallback]);
38
+ }, [isOn, setStatus, sensor.quick_action]);
39
+
54
40
  const userId = useSCContextSelector((state) => state?.auth.account.user.id);
55
41
  const onActionPress = useCallback(() => {
56
42
  let data = null;
@@ -73,30 +59,12 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
73
59
  sendRemoteCommand(sensor, action, data, userId);
74
60
  setIsSendingCommand(true);
75
61
 
76
- if (!sensor.quick_action) {
77
- // old version
78
- setTimeout(() => {
79
- revertActionUpdate(
80
- action.id === sensor.action.id,
81
- sensor.action,
82
- sensor.status,
83
- sensor.action2,
84
- sensor.status2
85
- );
86
- }, 5000);
87
- } else if (!sensor.quick_action.will_auto_update_status) {
62
+ if (!sensor.quick_action.will_auto_update_status) {
88
63
  setTimeout(() => {
89
- statusCallback(action.id === sensor.quick_action.on_action.id);
64
+ setIsOn(action.id === sensor.quick_action.on_action.id);
90
65
  }, sensor.quick_action.interval);
91
66
  }
92
- }, [
93
- sensor,
94
- action,
95
- userId,
96
- revertActionUpdate,
97
- statusCallback,
98
- sendRemoteCommand,
99
- ]);
67
+ }, [sensor, action, userId, sendRemoteCommand]);
100
68
 
101
69
  if (!action) {
102
70
  return <View />;
@@ -1,25 +1,24 @@
1
- import React, { useState } from 'react';
1
+ import React from 'react';
2
2
  import { TouchableOpacity } from 'react-native';
3
3
  import { act, create } from 'react-test-renderer';
4
4
  import ItemQuickAction from '../ItemQuickAction';
5
5
  import { Colors } from '../../../configs';
6
6
  import { AccessibilityLabel } from '../../../configs/Constants';
7
7
  import { factory } from 'factory-girl';
8
+ import IconComponent from '../../IconComponent';
9
+ import { IconFill, IconOutline } from '@ant-design/icons-react-native';
8
10
 
9
11
  class Sensor {}
10
12
 
11
13
  factory.define('Sensor', Sensor, {});
12
- const mockSetState = jest.fn();
13
14
 
14
15
  jest.mock('react', () => {
15
16
  return {
16
17
  ...jest.requireActual('react'),
17
- useState: jest.fn(),
18
+ memo: (x) => x,
18
19
  };
19
20
  });
20
21
 
21
- useState.mockImplementation((init) => [init, mockSetState]);
22
-
23
22
  const mockSendRemoteControl = jest.fn();
24
23
  jest.mock('../../../hooks/IoT', () => {
25
24
  return {
@@ -33,62 +32,41 @@ jest.mock('../../../iot/states', () => ({
33
32
  }));
34
33
 
35
34
  describe('Test ItemQuickAction', () => {
36
- let tree;
35
+ let tree, sensor, style;
37
36
  beforeEach(() => {
38
37
  jest.useFakeTimers();
39
- mockSetState.mockClear();
40
- });
41
-
42
- const sensor = {
43
- action: {
44
- name: 'off',
45
- color: '#00979D',
46
- command_prefer_over_bluetooth: true,
47
- command_prefer_over_googlehome: false,
48
- command_prefer_over_internet: false,
49
- allow_config_store_value_id: 51,
50
- id: 9,
51
- },
52
- quick_action: {
53
- config_id: 51,
54
- interval: 5000,
55
- off_action: {
56
- color: '#00979D',
57
- command_prefer_over_bluetooth: true,
58
- command_prefer_over_googlehome: false,
59
- command_prefer_over_internet: false,
60
- id: 10,
61
- },
62
- on_action: {
63
- color: '#00979D',
64
- command_prefer_over_bluetooth: true,
65
- command_prefer_over_googlehome: false,
66
- command_prefer_over_internet: false,
67
- id: 9,
38
+ sensor = {
39
+ quick_action: {
40
+ config_id: 51,
41
+ interval: 5000,
42
+ off_action: {
43
+ icon: 'down',
44
+ command_prefer_over_bluetooth: true,
45
+ command_prefer_over_googlehome: false,
46
+ command_prefer_over_internet: false,
47
+ id: 10,
48
+ },
49
+ on_action: {
50
+ icon: 'up',
51
+ command_prefer_over_bluetooth: true,
52
+ command_prefer_over_googlehome: false,
53
+ command_prefer_over_internet: false,
54
+ id: 9,
55
+ },
56
+ off_status: 'OFF',
57
+ on_status: 'ON',
58
+ will_auto_update_status: false,
68
59
  },
69
- off_status: 'OFF',
70
- on_status: 'ON',
71
- will_auto_update_status: false,
72
- },
73
- action2: {
74
- color: '#00979D',
75
- command_prefer_over_bluetooth: true,
76
- command_prefer_over_googlehome: false,
77
- command_prefer_over_internet: false,
78
- allow_config_store_value_id: 51,
79
- id: 10,
80
- },
81
- status: 'OFF',
82
- status2: 'ON',
83
- };
84
- const style = {
85
- width: 32,
86
- height: 32,
87
- backgroundColor: Colors.Gray3,
88
- borderRadius: 16,
89
- justifyContent: 'center',
90
- alignItems: 'center',
91
- };
60
+ };
61
+ style = {
62
+ width: 32,
63
+ height: 32,
64
+ backgroundColor: Colors.Gray3,
65
+ borderRadius: 16,
66
+ justifyContent: 'center',
67
+ alignItems: 'center',
68
+ };
69
+ });
92
70
 
93
71
  it('render with no action', async () => {
94
72
  const newSensor = await factory.build('Sensor');
@@ -105,9 +83,9 @@ describe('Test ItemQuickAction', () => {
105
83
  expect(buttonOnActionPress).toHaveLength(0);
106
84
  });
107
85
 
108
- it('render with full action data case on and icon up', async () => {
86
+ it('render with icon_outlined poweroff', async () => {
109
87
  const mockSetStatus = jest.fn();
110
- sensor.action.icon = 'up';
88
+ sensor.quick_action.on_action.icon = null;
111
89
  await act(async () => {
112
90
  tree = await create(
113
91
  <ItemQuickAction
@@ -119,36 +97,15 @@ describe('Test ItemQuickAction', () => {
119
97
  });
120
98
 
121
99
  const instance = tree.root;
122
- const buttonOnActionPress = instance.find(
123
- (el) =>
124
- el.props.accessibilityLabel ===
125
- `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
126
- el.type === TouchableOpacity
127
- );
128
- expect(buttonOnActionPress).toBeDefined();
129
-
130
- mockSetState.mockClear();
131
- await act(async () => {
132
- buttonOnActionPress.props.onPress();
133
- });
134
- expect(mockSendRemoteControl).toBeCalled();
135
- expect(mockSetState).toBeCalledTimes(1);
136
-
137
- jest.runAllTimers();
138
- expect(mockSetState).toBeCalledTimes(3);
139
- expect(mockSetState).toBeCalledWith(sensor.quick_action.off_action);
100
+ const icon = instance.findByType(IconOutline);
101
+ expect(icon).toBeDefined();
102
+ expect(icon.props.name).toEqual('poweroff');
140
103
  });
141
104
 
142
- it('render with icon_outlined poweroff and action have allow_config_store_value_id', async () => {
143
- const mockSetStatus = jest.fn();
144
- sensor.action.icon = null;
105
+ it('click quick action icon down , isSendingCommand = true', async () => {
145
106
  await act(async () => {
146
107
  tree = await create(
147
- <ItemQuickAction
148
- sensor={sensor}
149
- wrapperStyle={style}
150
- setStatus={mockSetStatus}
151
- />
108
+ <ItemQuickAction sensor={sensor} wrapperStyle={style} />
152
109
  );
153
110
  });
154
111
 
@@ -159,95 +116,25 @@ describe('Test ItemQuickAction', () => {
159
116
  `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
160
117
  el.type === TouchableOpacity
161
118
  );
162
- expect(buttonOnActionPress).toBeDefined();
163
119
 
164
- mockSetState.mockClear();
165
120
  await act(async () => {
166
- buttonOnActionPress.props.onPress();
121
+ await buttonOnActionPress.props.onPress();
167
122
  });
168
- expect(mockSendRemoteControl).toBeCalledWith(
169
- sensor,
170
- sensor.action,
171
- JSON.stringify({ config_id: 51, config_value: 0 }),
172
- undefined
173
- );
174
- expect(mockSetState).toBeCalledTimes(1);
175
123
 
176
- jest.runAllTimers();
177
- expect(mockSetState).toBeCalledTimes(3);
178
- expect(mockSetState).toBeCalledWith(sensor.quick_action.off_action);
124
+ const icon = instance.findByType(IconFill);
125
+ expect(icon.props.color).toEqual(Colors.TextGray);
179
126
  });
180
127
 
181
- it('render case old version config', async () => {
182
- const oldSensor = {
183
- action: {
184
- color: '#00979D',
185
- command_prefer_over_bluetooth: true,
186
- command_prefer_over_googlehome: false,
187
- command_prefer_over_internet: false,
188
- id: 9,
189
- icon: 'caret-up',
190
- },
191
- action2: {
192
- color: '#00979D',
193
- command_prefer_over_bluetooth: true,
194
- command_prefer_over_googlehome: false,
195
- command_prefer_over_internet: false,
196
- id: 10,
197
- },
198
- status: 'OFF',
199
- status2: 'ON',
200
- };
201
- await act(async () => {
202
- tree = await create(
203
- <ItemQuickAction sensor={oldSensor} wrapperStyle={style} />
204
- );
205
- });
206
-
207
- const instance = tree.root;
208
- const buttonOnActionPress = instance.find(
209
- (el) =>
210
- el.props.accessibilityLabel ===
211
- `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
212
- el.type === TouchableOpacity
213
- );
214
-
215
- mockSetState.mockClear();
216
- await act(async () => {
217
- buttonOnActionPress.props.onPress();
218
- });
219
- expect(mockSetState).toBeCalledTimes(1);
220
-
221
- jest.runAllTimers();
222
- expect(mockSetState).toBeCalledTimes(3);
223
- });
128
+ it('trigger action with quick action with auto update', async () => {
129
+ sensor.quick_action.will_auto_update_status = true;
224
130
 
225
- it('when sending command, button is disabled', async () => {
226
- useState.mockImplementationOnce((init) => [true, mockSetState]);
227
131
  await act(async () => {
228
132
  tree = await create(
229
133
  <ItemQuickAction sensor={sensor} wrapperStyle={style} />
230
134
  );
231
135
  });
232
136
 
233
- const instance = tree.root;
234
- const buttonOnActionPress = instance.find(
235
- (el) =>
236
- el.props.accessibilityLabel ===
237
- `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
238
- el.type === TouchableOpacity
239
- );
240
- expect(buttonOnActionPress).toBeDefined();
241
- });
242
-
243
- it('click quick action icon down , isSendingCommand = true', async () => {
244
- sensor.action.icon = 'down';
245
- useState.mockImplementationOnce((init) => [true, mockSetState]);
246
- await act(async () => {
247
- tree = await create(
248
- <ItemQuickAction sensor={sensor} wrapperStyle={style} />
249
- );
250
- });
137
+ assertIsActionOn();
251
138
 
252
139
  const instance = tree.root;
253
140
  const buttonOnActionPress = instance.find(
@@ -256,75 +143,20 @@ describe('Test ItemQuickAction', () => {
256
143
  `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
257
144
  el.type === TouchableOpacity
258
145
  );
259
- expect(buttonOnActionPress).toBeDefined();
260
- });
261
- it('trigger action with quick action no auto update', async () => {
262
- const noAutoUpdateSensor = {
263
- action: {
264
- name: 'on',
265
- color: '#00979D',
266
- command_prefer_over_bluetooth: true,
267
- command_prefer_over_googlehome: false,
268
- command_prefer_over_internet: false,
269
- allow_config_store_value_id: 51,
270
- id: 9,
271
- icon: 'caret-up',
272
- },
273
- quick_action: {
274
- config_id: 51,
275
- interval: 5000,
276
- off_action: {
277
- color: '#00979D',
278
- command_prefer_over_bluetooth: true,
279
- command_prefer_over_googlehome: false,
280
- command_prefer_over_internet: false,
281
- id: 10,
282
- },
283
- on_action: {
284
- color: '#00979D',
285
- command_prefer_over_bluetooth: true,
286
- command_prefer_over_googlehome: false,
287
- command_prefer_over_internet: false,
288
- id: 9,
289
- },
290
- off_status: 'OFF',
291
- on_status: 'ON',
292
- will_auto_update_status: true,
293
- },
294
- };
295
146
 
296
147
  await act(async () => {
297
- tree = await create(
298
- <ItemQuickAction sensor={noAutoUpdateSensor} wrapperStyle={style} />
299
- );
148
+ await buttonOnActionPress.props.onPress();
300
149
  });
301
150
 
302
- const instance = tree.root;
303
- const buttonOnActionPress = instance.find(
304
- (el) =>
305
- el.props.accessibilityLabel ===
306
- `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
307
- el.type === TouchableOpacity
308
- );
309
-
310
- mockSetState.mockClear();
311
151
  await act(async () => {
312
- buttonOnActionPress.props.onPress();
152
+ jest.runAllTimers();
313
153
  });
314
- expect(mockSendRemoteControl).toBeCalledWith(
315
- noAutoUpdateSensor,
316
- noAutoUpdateSensor.action,
317
- JSON.stringify({ config_id: 51, config_value: 1 }),
318
- undefined
319
- );
320
- expect(mockSetState).toBeCalledTimes(1);
321
154
 
322
- jest.runAllTimers();
323
- expect(mockSetState).toBeCalledTimes(1);
155
+ assertIsActionOn();
324
156
  });
325
157
 
326
- it('render with full action data case off', async () => {
327
- sensor.action.id = 10; // off action
158
+ it('on press will toggle action', async () => {
159
+ sensor.quick_action.on_action.id = 10; // off action
328
160
  const mockSetStatus = jest.fn();
329
161
 
330
162
  await act(async () => {
@@ -336,7 +168,7 @@ describe('Test ItemQuickAction', () => {
336
168
  />
337
169
  );
338
170
  });
339
-
171
+ assertIsActionOn();
340
172
  const instance = tree.root;
341
173
  const buttonOnActionPress = instance.find(
342
174
  (el) =>
@@ -345,31 +177,37 @@ describe('Test ItemQuickAction', () => {
345
177
  el.type === TouchableOpacity
346
178
  );
347
179
 
348
- mockSetState.mockClear();
349
180
  await act(async () => {
350
- buttonOnActionPress.props.onPress();
181
+ await buttonOnActionPress.props.onPress();
182
+ jest.runAllTimers();
351
183
  });
352
184
 
353
- jest.runAllTimers();
354
- expect(mockSetState).toBeCalledWith(sensor.quick_action.on_action);
185
+ assertIsActionOff();
355
186
  });
356
187
 
357
188
  it('listen to config value for update action', async () => {
358
189
  const globalStates = require('../../../iot/states');
359
190
  globalStates.useConfigGlobalState = () => [{ 51: { value: true } }, null];
360
191
 
361
- const mockSetStatus = jest.fn();
362
-
363
192
  await act(async () => {
364
193
  tree = await create(
365
- <ItemQuickAction
366
- sensor={sensor}
367
- wrapperStyle={style}
368
- setStatus={mockSetStatus}
369
- />
194
+ <ItemQuickAction sensor={sensor} wrapperStyle={style} />
370
195
  );
371
196
  });
372
197
 
373
- expect(mockSetState).toBeCalledWith(sensor.quick_action.off_action);
198
+ assertIsActionOff();
374
199
  });
200
+
201
+ const assertIsActionOn = () => {
202
+ const icon = tree.root.findByType(IconComponent);
203
+
204
+ expect(icon.props.icon).toEqual(sensor.quick_action.on_action.icon);
205
+ expect(icon.props.icon).not.toEqual(sensor.quick_action.off_action.icon);
206
+ };
207
+ const assertIsActionOff = () => {
208
+ const icon = tree.root.findByType(IconComponent);
209
+
210
+ expect(icon.props.icon).toEqual(sensor.quick_action.off_action.icon);
211
+ expect(icon.props.icon).not.toEqual(sensor.quick_action.on_action.icon);
212
+ };
375
213
  });
@@ -52,7 +52,7 @@ const OptionsDropdownActionTemplate = ({
52
52
  for (let i = 0; i < options.length; i++) {
53
53
  const option = options[i];
54
54
  const value = getOptionValue(option, allow_config_store_value);
55
- if (value === currentValue) {
55
+ if (String(value) === String(currentValue)) {
56
56
  return option;
57
57
  }
58
58
  }
@@ -61,12 +61,12 @@ describe('Test OptionsDropdownActionTemplate', () => {
61
61
  {
62
62
  text: 'Level1',
63
63
  value_int: 1,
64
- value_text: '',
64
+ value_text: '1',
65
65
  },
66
66
  {
67
67
  text: 'Level2',
68
68
  value_int: 2,
69
- value_text: '',
69
+ value_text: '2',
70
70
  },
71
71
  ],
72
72
  icon: 'slack',
@@ -96,6 +96,7 @@ describe('Test OptionsDropdownActionTemplate', () => {
96
96
  });
97
97
 
98
98
  it('render template without selectedOption match, get first one', async () => {
99
+ actionGroup.configuration.options[1].value_text = '3';
99
100
  actionGroup.configuration.options[1].value_int = 3;
100
101
  sensor.is_managed_by_backend = true;
101
102
  const mockDoAction = jest.fn();
@@ -160,7 +161,7 @@ describe('Test OptionsDropdownActionTemplate', () => {
160
161
 
161
162
  expect(mockDoAction).toHaveBeenCalledWith(
162
163
  action_data,
163
- JSON.stringify({ level: 1, key_code: 1 })
164
+ JSON.stringify({ level: '1', key_code: 1 })
164
165
  );
165
166
  is_managed_by_backend
166
167
  ? expect(watchMultiConfigs).not.toBeCalled()
@@ -22,7 +22,7 @@ const AlertAction = ({
22
22
  accessibilityLabelPrefix = '',
23
23
  boxLeftButtonStyle,
24
24
  boxRightButtonStyle,
25
- transY,
25
+ transY = 0,
26
26
  }) => {
27
27
  const [keyboardAnim] = useState(new Animated.Value(0));
28
28
 
@@ -269,6 +269,7 @@ export const PROBLEM_CODE = {
269
269
  NETWORK_ERROR: 'NETWORK_ERROR',
270
270
  UNKNOWN_ERROR: 'UNKNOWN_ERROR',
271
271
  CANCEL_ERROR: 'CANCEL_ERROR',
272
+ ADDRESS_CHANGING: 'Please wait 30s for changing address.',
272
273
  };
273
274
 
274
275
  export const DATE_TIME_FORMAT = {
@@ -4,11 +4,23 @@ 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';
7
8
 
8
9
  const bluetoothDevices = {};
9
10
  const needToScanDevices = [];
10
11
  const bleManager = new BleManager();
11
12
 
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
+
12
24
  export const SEND_COMMAND_OVER_BLUETOOTH_FAIL =
13
25
  'SEND_COMMAND_OVER_BLUETOOTH_FAIL';
14
26
 
@@ -22,17 +34,21 @@ export const clearFoundDevices = () => {
22
34
  }
23
35
  };
24
36
 
25
- export const scanBluetoothDevices = (names, onDeviceFound) => {
37
+ export const scanBluetoothDevices = async (names, onDeviceFound) => {
26
38
  names.map((name) => {
27
39
  if (bluetoothDevices[name]) {
28
40
  return;
29
41
  }
30
42
  needToScanDevices.push(name);
31
43
  });
32
- realScanBluetoothDevices(onDeviceFound);
44
+ await realScanBluetoothDevices(onDeviceFound);
33
45
  };
34
46
 
35
- export const realScanBluetoothDevices = (onDeviceFound) => {
47
+ export const realScanBluetoothDevices = async (onDeviceFound) => {
48
+ const permissionsGranted = await requestBluetoothPermissions();
49
+ if (!permissionsGranted) {
50
+ return;
51
+ }
36
52
  if (!needToScanDevices.length) {
37
53
  return;
38
54
  }