@eohjsc/react-native-smart-city 0.3.55 → 0.3.57
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/commons/ActionGroup/ColorPickerTemplate.js +1 -1
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/__test__/index.test.js +11 -0
- package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +0 -4
- package/src/commons/ActionGroup/SmartTiviActionTemplate/__test__/RectangleButton.test.js +13 -0
- package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +56 -3
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +18 -0
- package/src/commons/ActionTemplate/__test__/index.test.js +22 -0
- package/src/commons/Device/HorizontalBarChart.js +6 -0
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +1 -0
- package/src/screens/AddNewGateway/ConnectingWifiDevice.js +1 -5
- package/src/screens/AddNewGateway/ConnectingWifiGuide.js +2 -2
- package/src/screens/AddNewGateway/__test__/ConnectingWifiGuide.test.js +3 -7
- package/src/screens/Device/components/SensorDisplayItem.js +2 -2
- package/src/screens/Device/hooks/useEvaluateValue.js +1 -1
- package/src/screens/Template/detail.js +33 -2
- package/src/screens/Template/utils/ValueEvaluation.js +18 -0
- package/src/utils/I18n/translations/en.json +1 -0
- package/src/utils/I18n/translations/vi.json +1 -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.
|
|
4
|
+
"version": "0.3.57",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"licenseFilename": "LICENSE",
|
|
66
66
|
"peerDependencies": {
|
|
67
|
+
"@react-native-community/clipboard": "*",
|
|
67
68
|
"react": "*",
|
|
68
|
-
"react-native": "*"
|
|
69
|
-
"@react-native-community/clipboard": "*"
|
|
69
|
+
"react-native": "*"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/core": "^7.12.9",
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
"i18n-js": "^3.7.1",
|
|
137
137
|
"i18next": "^20.1.0",
|
|
138
138
|
"lodash": "^4.17.19",
|
|
139
|
-
"lottie-react-native": "
|
|
139
|
+
"lottie-react-native": "4.0.3",
|
|
140
140
|
"moment": "^2.27.0",
|
|
141
141
|
"moment-timezone": "^0.5.32",
|
|
142
142
|
"numeral": "^2.0.6",
|
|
@@ -13,7 +13,7 @@ import { SCContext } from '../../context';
|
|
|
13
13
|
import { Action } from '../../context/actionType';
|
|
14
14
|
import { DEVICE_TYPE } from '../../configs/Constants';
|
|
15
15
|
|
|
16
|
-
const WheelColorPicker = ({ color, onChangeColorComplete, onStart }) => {
|
|
16
|
+
export const WheelColorPicker = ({ color, onChangeColorComplete, onStart }) => {
|
|
17
17
|
const regex = /^#([0-9a-f]{3}){1,2}$/i;
|
|
18
18
|
const isCheckHex = regex.test(color);
|
|
19
19
|
// check crash if valueColor value wrong
|
|
@@ -6,6 +6,7 @@ import { AccessibilityLabel } from '../../../../../configs/Constants';
|
|
|
6
6
|
import { SCProvider } from '../../../../../context';
|
|
7
7
|
import PasscodeList from '../index';
|
|
8
8
|
import { TouchableOpacity } from 'react-native';
|
|
9
|
+
import Routes from '../../../../../utils/Route';
|
|
9
10
|
|
|
10
11
|
const mockNavigate = jest.fn();
|
|
11
12
|
jest.mock('@react-navigation/native', () => {
|
|
@@ -43,5 +44,15 @@ describe('Test SetupGeneratePasscode', () => {
|
|
|
43
44
|
);
|
|
44
45
|
|
|
45
46
|
expect(passcode_list).toHaveLength(3);
|
|
47
|
+
|
|
48
|
+
await act(async () => {
|
|
49
|
+
await passcode_list[0].props.onPress();
|
|
50
|
+
});
|
|
51
|
+
expect(mockNavigate).toBeCalledWith(Routes.SmartLockStack, {
|
|
52
|
+
screen: Routes.ItemPasscode,
|
|
53
|
+
params: {
|
|
54
|
+
item: { code: 123361, name: 'Do Loi' },
|
|
55
|
+
},
|
|
56
|
+
});
|
|
46
57
|
});
|
|
47
58
|
});
|
|
@@ -70,8 +70,6 @@ const SmartTiviActionTemplate = memo(
|
|
|
70
70
|
case SMART_TIVI_BUTTON.BACK_BUTTON:
|
|
71
71
|
case SMART_TIVI_BUTTON.CHANNEL_BUTTON:
|
|
72
72
|
return notImplemented(t);
|
|
73
|
-
default:
|
|
74
|
-
return <></>;
|
|
75
73
|
}
|
|
76
74
|
},
|
|
77
75
|
[t]
|
|
@@ -86,8 +84,6 @@ const SmartTiviActionTemplate = memo(
|
|
|
86
84
|
return <Netflix style={styles.iconChannel} />;
|
|
87
85
|
case 'spotify':
|
|
88
86
|
return <Spotify style={styles.iconChannel} />;
|
|
89
|
-
default:
|
|
90
|
-
return <></>;
|
|
91
87
|
}
|
|
92
88
|
}, []);
|
|
93
89
|
return (
|
|
@@ -111,4 +111,17 @@ describe('Test RectangleButton', () => {
|
|
|
111
111
|
RectangleButtonDown.props.onPress();
|
|
112
112
|
});
|
|
113
113
|
});
|
|
114
|
+
|
|
115
|
+
it('render type not handle', async () => {
|
|
116
|
+
type = 'not-handle';
|
|
117
|
+
const mockOnPress = jest.fn();
|
|
118
|
+
await act(async () => {
|
|
119
|
+
wrapper = await create(
|
|
120
|
+
wrapComponent(type, mockOnPress, mockOnPress, mockOnPress)
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
const instance = wrapper.root;
|
|
124
|
+
const touches = instance.findAllByType(TouchableOpacity);
|
|
125
|
+
expect(touches).toHaveLength(0);
|
|
126
|
+
});
|
|
114
127
|
});
|
|
@@ -2,10 +2,22 @@ import { watchMultiConfigs } from '../../../iot/Monitor';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { act, create } from 'react-test-renderer';
|
|
4
4
|
import ColorPickerTemplate from '../ColorPickerTemplate';
|
|
5
|
+
import { WheelColorPicker } from '../ColorPickerTemplate';
|
|
5
6
|
import { SCProvider } from '../../../context';
|
|
6
7
|
import { mockSCStore } from '../../../context/mockStore';
|
|
7
8
|
import { useConfigGlobalState } from '../../../iot/states';
|
|
8
9
|
import ColorPicker from 'react-native-wheel-color-picker';
|
|
10
|
+
import { DEVICE_TYPE } from '../../../configs/Constants';
|
|
11
|
+
|
|
12
|
+
const mockSetAction = jest.fn();
|
|
13
|
+
jest.mock('react', () => {
|
|
14
|
+
return {
|
|
15
|
+
...jest.requireActual('react'),
|
|
16
|
+
useContext: () => ({
|
|
17
|
+
setAction: mockSetAction,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
9
21
|
|
|
10
22
|
jest.mock('../../../iot/Monitor');
|
|
11
23
|
const mockDoAction = jest.fn();
|
|
@@ -46,6 +58,7 @@ describe('Test ColorPickerTemplate', () => {
|
|
|
46
58
|
},
|
|
47
59
|
title: '',
|
|
48
60
|
};
|
|
61
|
+
mockSetAction.mockClear();
|
|
49
62
|
});
|
|
50
63
|
|
|
51
64
|
it('render template ColorPickerTemplate', async () => {
|
|
@@ -58,10 +71,50 @@ describe('Test ColorPickerTemplate', () => {
|
|
|
58
71
|
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
59
72
|
});
|
|
60
73
|
const instance = wrapper.root;
|
|
61
|
-
const
|
|
62
|
-
expect(
|
|
74
|
+
const pickers = instance.findAllByType(ColorPicker);
|
|
75
|
+
expect(pickers).toHaveLength(1);
|
|
76
|
+
expect(pickers[0].props.color).toEqual('#ffffff');
|
|
77
|
+
await act(async () => {
|
|
78
|
+
await pickers[0].props.onColorChangeComplete();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('render template ColorPickerTemplate config value not null', async () => {
|
|
83
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
84
|
+
{
|
|
85
|
+
5: {
|
|
86
|
+
value: 3093151,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
jest.fn(),
|
|
90
|
+
]);
|
|
91
|
+
const sensor = {
|
|
92
|
+
is_managed_by_backend: true,
|
|
93
|
+
name: 'Sensor',
|
|
94
|
+
device_type: DEVICE_TYPE.LG_THINQ,
|
|
95
|
+
};
|
|
96
|
+
await act(async () => {
|
|
97
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
98
|
+
});
|
|
99
|
+
const instance = wrapper.root;
|
|
100
|
+
const pickers = instance.findAllByType(ColorPicker);
|
|
101
|
+
expect(pickers[0].props.color).toEqual(`#${3093151?.toString(16)}`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('test WheelColorPicker onStartPick set global state lock view', async () => {
|
|
105
|
+
const sensor = {
|
|
106
|
+
is_managed_by_backend: true,
|
|
107
|
+
name: 'Sensor',
|
|
108
|
+
device_type: DEVICE_TYPE.LG_THINQ,
|
|
109
|
+
};
|
|
110
|
+
await act(async () => {
|
|
111
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
112
|
+
});
|
|
113
|
+
const instance = wrapper.root;
|
|
114
|
+
const wheelpicker = instance.findByType(WheelColorPicker);
|
|
63
115
|
await act(async () => {
|
|
64
|
-
await
|
|
116
|
+
await wheelpicker.props.onStart();
|
|
65
117
|
});
|
|
118
|
+
expect(mockSetAction).toBeCalled();
|
|
66
119
|
});
|
|
67
120
|
});
|
|
@@ -85,4 +85,22 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
85
85
|
JSON.stringify({ value_brness: 50 })
|
|
86
86
|
);
|
|
87
87
|
});
|
|
88
|
+
|
|
89
|
+
it('render template SliderRangeTemplate with config value not null', async () => {
|
|
90
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
91
|
+
{
|
|
92
|
+
5: {
|
|
93
|
+
value: 50,
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
jest.fn(),
|
|
97
|
+
]);
|
|
98
|
+
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
99
|
+
await act(async () => {
|
|
100
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
101
|
+
});
|
|
102
|
+
const instance = wrapper.root;
|
|
103
|
+
const silderRange = instance.findByType(SliderRange);
|
|
104
|
+
expect(silderRange.props.value).toBe(50);
|
|
105
|
+
});
|
|
88
106
|
});
|
|
@@ -62,6 +62,28 @@ describe('Test ActionTemplate', () => {
|
|
|
62
62
|
action_off: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
63
63
|
},
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
title: '',
|
|
67
|
+
template: 'curtain_action_template',
|
|
68
|
+
configuration: {
|
|
69
|
+
open_action: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
70
|
+
close_action: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
71
|
+
stop_action: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
72
|
+
text1: 'One',
|
|
73
|
+
text2: 'Two',
|
|
74
|
+
text3: 'Three',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: '',
|
|
79
|
+
template: 'OnOffSmartLockActionTemplate',
|
|
80
|
+
configuration: {
|
|
81
|
+
action_on: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
82
|
+
action_off: '94ae262d-46e3-42ff-9d10-516831ecc830',
|
|
83
|
+
text_on: 'on',
|
|
84
|
+
text_off: 'off',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
65
87
|
];
|
|
66
88
|
it('test onPress SelectActionCard', async () => {
|
|
67
89
|
await act(async () => {
|
|
@@ -126,6 +126,8 @@ const HorizontalBarChart = memo(({ datas, config }) => {
|
|
|
126
126
|
dataY.splice(maxY._index, 1, { ...maxY.max, color: Colors.Primary });
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
const isAllZero = dataY.every((item) => item.y === 0);
|
|
130
|
+
|
|
129
131
|
setChartOptions((options) => ({
|
|
130
132
|
...options,
|
|
131
133
|
chart: {
|
|
@@ -135,6 +137,10 @@ const HorizontalBarChart = memo(({ datas, config }) => {
|
|
|
135
137
|
...options.xAxis,
|
|
136
138
|
categories: dataX,
|
|
137
139
|
},
|
|
140
|
+
yAxis: {
|
|
141
|
+
...options.yAxis,
|
|
142
|
+
minRange: isAllZero ? 0.5 : 0,
|
|
143
|
+
},
|
|
138
144
|
series: [
|
|
139
145
|
{
|
|
140
146
|
name: JSON.stringify(config),
|
|
@@ -71,11 +71,7 @@ const ConnectingWifiDevice = ({ route }) => {
|
|
|
71
71
|
|
|
72
72
|
useEffect(() => {
|
|
73
73
|
const unsubscribe = NetInfo.addEventListener((state) => {
|
|
74
|
-
if (
|
|
75
|
-
state.isConnected &&
|
|
76
|
-
state.details?.ssid === selectedWifi.ssid &&
|
|
77
|
-
channelName
|
|
78
|
-
) {
|
|
74
|
+
if (state.isConnected && channelName) {
|
|
79
75
|
onReady(channelName);
|
|
80
76
|
}
|
|
81
77
|
});
|
|
@@ -53,7 +53,7 @@ const ConnectingWifiGuide = ({ route }) => {
|
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
text: t('retry'),
|
|
56
|
-
onPress: connectToDeviceWifi,
|
|
56
|
+
onPress: () => connectToDeviceWifi(),
|
|
57
57
|
},
|
|
58
58
|
],
|
|
59
59
|
[connectToDeviceWifi, goBack, t]
|
|
@@ -104,7 +104,7 @@ const ConnectingWifiGuide = ({ route }) => {
|
|
|
104
104
|
if (!wifi) {
|
|
105
105
|
phoneWifiList = null;
|
|
106
106
|
Alert.alert(
|
|
107
|
-
t('
|
|
107
|
+
t('cannot_find_device_wifi'),
|
|
108
108
|
t('try_to_turn_on_device_or_try_again'),
|
|
109
109
|
buttons
|
|
110
110
|
);
|
|
@@ -138,9 +138,7 @@ describe('test share wifi password', () => {
|
|
|
138
138
|
tree = await renderer.create(wrapComponent(route));
|
|
139
139
|
});
|
|
140
140
|
await ConnectWifiActionButton(tree.root);
|
|
141
|
-
expect(Alert.alert.mock.calls[0][0]).toEqual(
|
|
142
|
-
'Fail to discover device wifi'
|
|
143
|
-
);
|
|
141
|
+
expect(Alert.alert.mock.calls[0][0]).toEqual("Cannot find Device's Wifi");
|
|
144
142
|
expect(Alert.alert.mock.calls[0][1]).toEqual(
|
|
145
143
|
'Try to turn on device or Try again'
|
|
146
144
|
);
|
|
@@ -153,7 +151,7 @@ describe('test share wifi password', () => {
|
|
|
153
151
|
it('fail connect to wifi android show error push retry', async () => {
|
|
154
152
|
jest.spyOn(Alert, 'alert');
|
|
155
153
|
Alert.alert(
|
|
156
|
-
|
|
154
|
+
"Cannot find Device's Wifi",
|
|
157
155
|
'Try to turn on device or Try again',
|
|
158
156
|
[
|
|
159
157
|
{ text: 'Cancel', onPress: mockedGoBack },
|
|
@@ -175,9 +173,7 @@ describe('test share wifi password', () => {
|
|
|
175
173
|
tree = await renderer.create(wrapComponent(route));
|
|
176
174
|
});
|
|
177
175
|
await ConnectWifiActionButton(tree.root);
|
|
178
|
-
expect(Alert.alert.mock.calls[1][0]).toEqual(
|
|
179
|
-
'Fail to discover device wifi'
|
|
180
|
-
);
|
|
176
|
+
expect(Alert.alert.mock.calls[1][0]).toEqual("Cannot find Device's Wifi");
|
|
181
177
|
expect(Alert.alert.mock.calls[1][1]).toEqual(
|
|
182
178
|
'Try to turn on device or Try again'
|
|
183
179
|
);
|
|
@@ -41,7 +41,7 @@ export const SensorDisplayItem = ({
|
|
|
41
41
|
const t = useTranslations();
|
|
42
42
|
const userId = useSCContextSelector((state) => state.auth.account.user.id);
|
|
43
43
|
const { configuration = {}, id: idTemplate } = item;
|
|
44
|
-
const { type, uri, id, name, title } = configuration;
|
|
44
|
+
const { type, template, uri, id, name, title } = configuration;
|
|
45
45
|
|
|
46
46
|
const { isEditingTemplate } = useSCContextSelector((state) => state.devMode);
|
|
47
47
|
|
|
@@ -94,7 +94,7 @@ export const SensorDisplayItem = ({
|
|
|
94
94
|
case 'history':
|
|
95
95
|
return <DetailHistoryChart item={item} sensor={sensor} />;
|
|
96
96
|
case 'value':
|
|
97
|
-
switch (type) {
|
|
97
|
+
switch (type || template) {
|
|
98
98
|
case 'circle':
|
|
99
99
|
return (
|
|
100
100
|
<CardDevMode id={idTemplate}>
|
|
@@ -20,6 +20,8 @@ import Routes from '../../utils/Route';
|
|
|
20
20
|
import { SensorDisplayItem } from '../Device/components/SensorDisplayItem';
|
|
21
21
|
import { axiosGet } from '../../utils/Apis/axios';
|
|
22
22
|
import { watchMultiConfigs } from '../../iot/Monitor';
|
|
23
|
+
import { useConfigGlobalState } from '../../iot/states';
|
|
24
|
+
import { evaluateValue } from './utils/ValueEvaluation';
|
|
23
25
|
|
|
24
26
|
const TemplateDetail = () => {
|
|
25
27
|
const refMenuAction = useRef();
|
|
@@ -31,6 +33,9 @@ const TemplateDetail = () => {
|
|
|
31
33
|
const [data, setData] = useState([]);
|
|
32
34
|
const [isLoading, setIsLoading] = useState(true);
|
|
33
35
|
|
|
36
|
+
// eslint-disable-next-line no-unused-vars
|
|
37
|
+
const [configValues, setConfigValues] = useConfigGlobalState('configValues');
|
|
38
|
+
|
|
34
39
|
const listIds = useMemo(() => {
|
|
35
40
|
const configIds = [];
|
|
36
41
|
// eslint-disable-next-line no-shadow
|
|
@@ -45,7 +50,7 @@ const TemplateDetail = () => {
|
|
|
45
50
|
configIds.push(item?.configuration?.configuration?.config);
|
|
46
51
|
}
|
|
47
52
|
});
|
|
48
|
-
return configIds;
|
|
53
|
+
return configIds.filter((id) => id);
|
|
49
54
|
}, [data]);
|
|
50
55
|
|
|
51
56
|
// eslint-disable-next-line no-shadow
|
|
@@ -136,6 +141,32 @@ const TemplateDetail = () => {
|
|
|
136
141
|
listIds.length && watchMultiConfigs(listIds);
|
|
137
142
|
}, [listIds]);
|
|
138
143
|
|
|
144
|
+
const getData = useCallback(
|
|
145
|
+
(_item) => {
|
|
146
|
+
if (!_item.configuration) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const _data = _item?.configuration?.configs.map((config) => {
|
|
151
|
+
const configValue = configValues[config.id]?.value;
|
|
152
|
+
if ([null, undefined, NaN].includes(configValue)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const value = {
|
|
156
|
+
id: config.id,
|
|
157
|
+
value: configValue,
|
|
158
|
+
evaluate: evaluateValue(
|
|
159
|
+
configValue,
|
|
160
|
+
_item?.configuration?.value_evaluation
|
|
161
|
+
),
|
|
162
|
+
};
|
|
163
|
+
return { ...config, ...value };
|
|
164
|
+
});
|
|
165
|
+
return _data.filter((value) => value);
|
|
166
|
+
},
|
|
167
|
+
[configValues]
|
|
168
|
+
);
|
|
169
|
+
|
|
139
170
|
return (
|
|
140
171
|
<View style={styles.wrap}>
|
|
141
172
|
<WrapHeaderScrollable
|
|
@@ -152,7 +183,7 @@ const TemplateDetail = () => {
|
|
|
152
183
|
return (
|
|
153
184
|
<SensorDisplayItem
|
|
154
185
|
item={item}
|
|
155
|
-
getData={
|
|
186
|
+
getData={getData}
|
|
156
187
|
offsetTitle={'offsetTitle'}
|
|
157
188
|
setOffsetTitle={'setOffsetTitle'}
|
|
158
189
|
maxValue={100}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { valueEvaluationFuncs } from '../../Device/hooks/useEvaluateValue';
|
|
2
|
+
|
|
3
|
+
export const evaluateValue = (value, valueEvaluation) => {
|
|
4
|
+
if (!valueEvaluation) {
|
|
5
|
+
return { text: value };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const evaluateFunc = valueEvaluationFuncs[valueEvaluation.template];
|
|
9
|
+
if (!evaluateFunc) {
|
|
10
|
+
return { text: value };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
return evaluateFunc(value, valueEvaluation.configuration);
|
|
15
|
+
} catch (e) {
|
|
16
|
+
return { text: value };
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -1100,5 +1100,6 @@
|
|
|
1100
1100
|
"text_under_development": "This feature is under development.",
|
|
1101
1101
|
"text_working_hard": "We are working hard to get this running",
|
|
1102
1102
|
"photo_request_permission": "Photo request permission",
|
|
1103
|
+
"cannot_find_device_wifi": "Cannot find Device's Wifi",
|
|
1103
1104
|
"photo_request_permission_des": "To select photo from gallery, please unlock access photo permission"
|
|
1104
1105
|
}
|
|
@@ -1099,5 +1099,6 @@
|
|
|
1099
1099
|
"text_under_development": "Tính năng này đang được phát triển.",
|
|
1100
1100
|
"text_working_hard": "Chúng tôi đang làm việc chăm chỉ để làm cho điều này hoạt động",
|
|
1101
1101
|
"photo_request_permission": "Quyền yêu cầu ảnh",
|
|
1102
|
+
"cannot_find_device_wifi": "Không thể tìm thấy Wifi của thiết bị",
|
|
1102
1103
|
"photo_request_permission_des": "Để chọn ảnh từ thư viện, vui lòng mở khóa quyền truy cập ảnh"
|
|
1103
1104
|
}
|