@eohjsc/react-native-smart-city 0.2.58 → 0.2.59
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 +1 -1
- package/src/Images/Common/buttonLeftCurtain.png +0 -0
- package/src/Images/Common/buttonPause-center-curtain.png +0 -0
- package/src/Images/Common/buttonRightCurtain.png +0 -0
- package/src/commons/ActionGroup/CurtainButtonTemplate.js +139 -0
- package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +58 -0
- package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +72 -0
- package/src/commons/ActionGroup/index.js +3 -0
- package/src/commons/Form/CurrencyInput.js +7 -1
- package/src/commons/MediaPlayerDetail/Styles/MediaPlayerDetailStyles.js +4 -0
- package/src/commons/MediaPlayerDetail/index.js +73 -39
- package/src/commons/SearchLocation/index.js +0 -1
- package/src/commons/SubUnit/ShortDetail.js +1 -1
- package/src/configs/API.js +5 -3
- package/src/configs/Constants.js +5 -1
- package/src/configs/Images.js +3 -0
- package/src/context/actionType.ts +5 -0
- package/src/context/mockStore.ts +3 -0
- package/src/context/reducer.ts +14 -0
- package/src/navigations/UnitStack.js +26 -4
- package/src/screens/ActivityLog/FilterPopup.js +1 -1
- package/src/screens/AddLocationMaps/index.js +137 -44
- package/src/screens/AddLocationMaps/indexStyle.js +14 -12
- package/src/screens/AddNewAction/SelectAction.js +1 -0
- package/src/screens/Automate/MultiUnits.js +8 -8
- package/src/screens/Automate/__test__/MultiUnits.test.js +2 -2
- package/src/screens/Automate/__test__/index.test.js +2 -0
- package/src/screens/Automate/index.js +4 -2
- package/src/screens/Device/detail.js +6 -3
- package/src/screens/Notification/__test__/Notification.test.js +3 -3
- package/src/screens/Notification/components/NotificationItem.js +3 -6
- package/src/screens/Notification/index.js +2 -2
- package/src/screens/ScriptDetail/__test__/index.test.js +13 -0
- package/src/screens/ScriptDetail/index.js +20 -17
- package/src/screens/SelectUnit/index.js +2 -0
- package/src/screens/SubUnit/AddSubUnit.js +4 -3
- package/src/screens/SubUnit/__test__/AddSubUnit.test.js +4 -3
- package/src/screens/Unit/ChooseLocation.js +100 -0
- package/src/screens/Unit/ChooseLocationStyles.js +29 -0
- package/src/screens/Unit/Detail.js +8 -2
- package/src/screens/Unit/ManageUnit.js +1 -1
- package/src/screens/Unit/SelectAddress.js +240 -0
- package/src/screens/Unit/SelectAddressStyles.js +48 -0
- package/src/screens/Unit/__test__/ChooseLocation.test.js +112 -0
- package/src/screens/Unit/__test__/SelectAddress.test.js +216 -0
- package/src/screens/Unit/components/MyUnitDevice/index.js +21 -5
- package/src/utils/I18n/translations/en.json +6 -2
- package/src/utils/I18n/translations/vi.json +8 -4
- package/src/utils/Route/index.js +2 -1
- package/assets/images/AddLocationMaps/PinLocation.svg +0 -3
- package/assets/images/AddLocationMaps/Point.svg +0 -3
- package/src/screens/Unit/ManageUnit/index.js +0 -286
- package/src/screens/Unit/ManageUnit/index.test.js +0 -34
- package/src/screens/Unit/SelectLocation.js +0 -161
- package/src/screens/Unit/SelectLocationStyles.js +0 -114
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import React, { memo, useCallback, useState } from 'react';
|
|
2
|
+
import { TouchableOpacity, View, Switch, Image } from 'react-native';
|
|
3
|
+
import { Icon } from '@ant-design/react-native';
|
|
4
|
+
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
|
+
import styles from './CurtainButtonTemplateStyle';
|
|
6
|
+
import Text from '../Text';
|
|
7
|
+
import { TESTID } from '../../configs/Constants';
|
|
8
|
+
import { Colors, Images } from '../../configs';
|
|
9
|
+
import { Section } from '../../commons/Section';
|
|
10
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
11
|
+
|
|
12
|
+
const CurtainButtonTemplate = memo(({ actionGroup, doAction }) => {
|
|
13
|
+
const t = useTranslations();
|
|
14
|
+
const { configuration } = actionGroup;
|
|
15
|
+
const [lock, setLock] = useState(false);
|
|
16
|
+
|
|
17
|
+
const onButtonOpenPress = useCallback(
|
|
18
|
+
() => doAction(configuration.open_action_data),
|
|
19
|
+
[configuration.open_action_data, doAction]
|
|
20
|
+
);
|
|
21
|
+
const onButtonStopPress = useCallback(
|
|
22
|
+
() => doAction(configuration.stop_action_data),
|
|
23
|
+
[configuration.stop_action_data, doAction]
|
|
24
|
+
);
|
|
25
|
+
const onButtonClosePress = useCallback(
|
|
26
|
+
() => doAction(configuration.close_action_data),
|
|
27
|
+
[configuration.close_action_data, doAction]
|
|
28
|
+
);
|
|
29
|
+
const onChangeSwitch = useCallback(() => {
|
|
30
|
+
if (lock) {
|
|
31
|
+
setLock(false);
|
|
32
|
+
doAction(configuration.action_off_data);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
doAction(configuration.action_on_data);
|
|
36
|
+
setLock(true);
|
|
37
|
+
}, [
|
|
38
|
+
configuration.action_off_data,
|
|
39
|
+
configuration.action_on_data,
|
|
40
|
+
doAction,
|
|
41
|
+
lock,
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
const RenderThreeButtonActions = () => {
|
|
45
|
+
const buttons = [
|
|
46
|
+
{
|
|
47
|
+
style: styles.buttonActionCurtain,
|
|
48
|
+
icon: Images.buttonLeftCurtain,
|
|
49
|
+
text: configuration.text1,
|
|
50
|
+
onPress: onButtonOpenPress,
|
|
51
|
+
testID: TESTID.BUTTON_TEMPLATE_1,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
style: styles.buttonActionCurtainCenter,
|
|
55
|
+
icon: Images.buttonPauseCurtain,
|
|
56
|
+
text: configuration.text2,
|
|
57
|
+
onPress: onButtonStopPress,
|
|
58
|
+
testID: TESTID.BUTTON_TEMPLATE_2,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
style: styles.buttonActionCurtain,
|
|
62
|
+
icon: Images.buttonRightCurtain,
|
|
63
|
+
text: configuration.text3,
|
|
64
|
+
onPress: onButtonClosePress,
|
|
65
|
+
testID: TESTID.BUTTON_TEMPLATE_3,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
{buttons.map((item, index) => (
|
|
72
|
+
<TouchableOpacity
|
|
73
|
+
testID={item.testID}
|
|
74
|
+
style={item.style}
|
|
75
|
+
onPress={item.onPress}
|
|
76
|
+
underlayColor={Colors.Gray2}
|
|
77
|
+
>
|
|
78
|
+
<Image source={item.icon} />
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
))}
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
const itemLock = (icon, color) => {
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<View style={styles.lockDoor}>
|
|
88
|
+
<Icon name={icon} size={15} color={color} style={styles.iconLock} />
|
|
89
|
+
<Text
|
|
90
|
+
style={styles.textLockDoor}
|
|
91
|
+
testID={TESTID.TEXT_DOOR_LOOK_ON_OFF}
|
|
92
|
+
>
|
|
93
|
+
{configuration.text_door_lock}{' '}
|
|
94
|
+
</Text>
|
|
95
|
+
</View>
|
|
96
|
+
<Switch
|
|
97
|
+
trackColor={{ false: Colors.Gray4, true: Colors.Primary }}
|
|
98
|
+
thumbColor={Colors.White}
|
|
99
|
+
ios_backgroundColor={Colors.Gray4}
|
|
100
|
+
onValueChange={onChangeSwitch}
|
|
101
|
+
value={lock}
|
|
102
|
+
/>
|
|
103
|
+
</>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
<View style={styles.wrap}>
|
|
109
|
+
<RenderThreeButtonActions />
|
|
110
|
+
</View>
|
|
111
|
+
<View style={styles.lockSwitch}>
|
|
112
|
+
{configuration.is_display_lock &&
|
|
113
|
+
itemLock(
|
|
114
|
+
lock ? 'lock' : 'unlock',
|
|
115
|
+
lock ? Colors.Primary : Colors.Gray6
|
|
116
|
+
)}
|
|
117
|
+
</View>
|
|
118
|
+
<Section style={styles.section}>
|
|
119
|
+
<View style={styles.reminderOption}>
|
|
120
|
+
<Text type="H4" color={Colors.Gray8}>
|
|
121
|
+
{t('schedule')}
|
|
122
|
+
</Text>
|
|
123
|
+
<TouchableOpacity>
|
|
124
|
+
<IconOutline name="plus" size={20} />
|
|
125
|
+
</TouchableOpacity>
|
|
126
|
+
</View>
|
|
127
|
+
<View>
|
|
128
|
+
<TouchableOpacity style={styles.tapToAddSchedule}>
|
|
129
|
+
<Text type="Body" color={Colors.Gray6} center>
|
|
130
|
+
{t('tap_to_add_new_schedule')}
|
|
131
|
+
</Text>
|
|
132
|
+
</TouchableOpacity>
|
|
133
|
+
</View>
|
|
134
|
+
</Section>
|
|
135
|
+
</>
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export default CurtainButtonTemplate;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export default StyleSheet.create({
|
|
4
|
+
wrap: {
|
|
5
|
+
flexDirection: 'row',
|
|
6
|
+
justifyContent: 'space-around',
|
|
7
|
+
paddingVertical: 30,
|
|
8
|
+
},
|
|
9
|
+
text: {
|
|
10
|
+
fontSize: 14,
|
|
11
|
+
lineHeight: 22,
|
|
12
|
+
},
|
|
13
|
+
lockSwitch: {
|
|
14
|
+
flexDirection: 'row',
|
|
15
|
+
justifyContent: 'space-between',
|
|
16
|
+
marginBottom: 7,
|
|
17
|
+
},
|
|
18
|
+
iconLock: {
|
|
19
|
+
paddingBottom: 7,
|
|
20
|
+
},
|
|
21
|
+
textLockDoor: {
|
|
22
|
+
paddingLeft: 12,
|
|
23
|
+
height: 24,
|
|
24
|
+
fontSize: 16,
|
|
25
|
+
lineHeight: 24,
|
|
26
|
+
},
|
|
27
|
+
lockDoor: {
|
|
28
|
+
flexDirection: 'row',
|
|
29
|
+
alignItems: 'flex-end',
|
|
30
|
+
paddingLeft: 5,
|
|
31
|
+
},
|
|
32
|
+
section: {
|
|
33
|
+
marginHorizontal: 20,
|
|
34
|
+
borderRadius: 10,
|
|
35
|
+
},
|
|
36
|
+
reminderOption: {
|
|
37
|
+
flex: 1,
|
|
38
|
+
flexDirection: 'row',
|
|
39
|
+
justifyContent: 'space-between',
|
|
40
|
+
},
|
|
41
|
+
tapToAddSchedule: {
|
|
42
|
+
paddingVertical: 50,
|
|
43
|
+
},
|
|
44
|
+
buttonActionCurtain: {
|
|
45
|
+
flex: 1,
|
|
46
|
+
aspectRatio: 1,
|
|
47
|
+
marginHorizontal: 4,
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
justifyContent: 'center',
|
|
50
|
+
},
|
|
51
|
+
buttonActionCurtainCenter: {
|
|
52
|
+
flex: 1,
|
|
53
|
+
aspectRatio: 1,
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
justifyContent: 'center',
|
|
56
|
+
marginTop: 15,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import CurtainButtonTemplate from '../CurtainButtonTemplate';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (actionGroup) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<CurtainButtonTemplate actionGroup={actionGroup} doAction={jest.fn()} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
describe('Test CurtainButtonTemplate', () => {
|
|
16
|
+
const actionGroup = {
|
|
17
|
+
configuration: {
|
|
18
|
+
action1: '2b949045-8e03-4c07-a855-7794ade2e69c',
|
|
19
|
+
action1_data: {
|
|
20
|
+
color: '#00979D',
|
|
21
|
+
command_prefer_over_bluetooth: true,
|
|
22
|
+
command_prefer_over_googlehome: false,
|
|
23
|
+
command_prefer_over_internet: false,
|
|
24
|
+
googlehome_actions: [],
|
|
25
|
+
icon: 'caret-up',
|
|
26
|
+
id: 9,
|
|
27
|
+
key: '2b949045-8e03-4c07-a855-7794ade2e69c',
|
|
28
|
+
},
|
|
29
|
+
action2: '38347d5e-4418-4ab0-978c-c82f4c034897',
|
|
30
|
+
action2_data: {
|
|
31
|
+
color: '#00979D',
|
|
32
|
+
command_prefer_over_bluetooth: true,
|
|
33
|
+
command_prefer_over_googlehome: false,
|
|
34
|
+
command_prefer_over_internet: false,
|
|
35
|
+
googlehome_actions: [],
|
|
36
|
+
icon: 'stop',
|
|
37
|
+
id: 11,
|
|
38
|
+
key: '38347d5e-4418-4ab0-978c-c82f4c034897',
|
|
39
|
+
},
|
|
40
|
+
action3: 'a492e08c-8cb1-44ee-8ea0-46aaca4e5141',
|
|
41
|
+
action3_data: {
|
|
42
|
+
color: '#00979D',
|
|
43
|
+
command_prefer_over_bluetooth: true,
|
|
44
|
+
command_prefer_over_googlehome: false,
|
|
45
|
+
command_prefer_over_internet: false,
|
|
46
|
+
googlehome_actions: [],
|
|
47
|
+
icon: 'caret-down',
|
|
48
|
+
id: 10,
|
|
49
|
+
key: 'a492e08c-8cb1-44ee-8ea0-46aaca4e5141',
|
|
50
|
+
},
|
|
51
|
+
icon1: 'caret-up',
|
|
52
|
+
icon2: 'stop',
|
|
53
|
+
icon3: 'caret-down',
|
|
54
|
+
text1: 'UP',
|
|
55
|
+
text2: 'STOP/UNLOCK',
|
|
56
|
+
text3: 'DOWN',
|
|
57
|
+
id: 1,
|
|
58
|
+
template: 'curtain_button_action_template',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
let wrapper;
|
|
63
|
+
|
|
64
|
+
test('render CurtainButtonTemplate', async () => {
|
|
65
|
+
await act(() => {
|
|
66
|
+
wrapper = renderer.create(wrapComponent(actionGroup));
|
|
67
|
+
});
|
|
68
|
+
const instance = wrapper.root;
|
|
69
|
+
const touchableOpacities = instance.findAllByType(TouchableOpacity);
|
|
70
|
+
expect(touchableOpacities.length).toEqual(5);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -8,6 +8,7 @@ import NumberUpDownActionTemplate from './NumberUpDownActionTemplate';
|
|
|
8
8
|
import OptionsDropdownActionTemplate from './OptionsDropdownActionTemplate';
|
|
9
9
|
import OnOffTemplate from './OnOffTemplate';
|
|
10
10
|
import TimerActionTemplate from './TimerActionTemplate';
|
|
11
|
+
import CurtainButtonTemplate from './CurtainButtonTemplate';
|
|
11
12
|
|
|
12
13
|
export const getActionComponent = (template) => {
|
|
13
14
|
switch (template) {
|
|
@@ -29,6 +30,8 @@ export const getActionComponent = (template) => {
|
|
|
29
30
|
return OptionsDropdownActionTemplate;
|
|
30
31
|
case 'TimerActionTemplate':
|
|
31
32
|
return TimerActionTemplate;
|
|
33
|
+
case 'curtain_action_template':
|
|
34
|
+
return CurtainButtonTemplate;
|
|
32
35
|
default:
|
|
33
36
|
return null;
|
|
34
37
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
TextInput,
|
|
5
5
|
StyleSheet,
|
|
6
6
|
TouchableWithoutFeedback,
|
|
7
|
+
Platform,
|
|
7
8
|
} from 'react-native';
|
|
8
9
|
import Text from '../Text';
|
|
9
10
|
import { Colors } from '../../configs';
|
|
@@ -117,7 +118,12 @@ const CurrencyInput = ({
|
|
|
117
118
|
: formattedValue;
|
|
118
119
|
}, [formattedValue, startingWithSign]);
|
|
119
120
|
|
|
120
|
-
const currencyMarginLeft =
|
|
121
|
+
const currencyMarginLeft = useMemo(() => {
|
|
122
|
+
if (Platform.OS === 'ios') {
|
|
123
|
+
return 5;
|
|
124
|
+
}
|
|
125
|
+
return textInputValue.toString().length < 2 ? -12 : 0;
|
|
126
|
+
}, [textInputValue]);
|
|
121
127
|
|
|
122
128
|
return (
|
|
123
129
|
<TouchableWithoutFeedback onPress={focusInput}>
|
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
memo,
|
|
3
|
+
useCallback,
|
|
4
|
+
useState,
|
|
5
|
+
useEffect,
|
|
6
|
+
useContext,
|
|
7
|
+
useMemo,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import {
|
|
10
|
+
Image,
|
|
11
|
+
View,
|
|
12
|
+
StyleSheet,
|
|
13
|
+
Text,
|
|
14
|
+
TouchableOpacity,
|
|
15
|
+
Platform,
|
|
16
|
+
} from 'react-native';
|
|
3
17
|
import { VLCPlayer } from 'react-native-vlc-media-player';
|
|
4
18
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
19
|
|
|
@@ -9,6 +23,8 @@ import { colorOpacity } from '../../utils/Converter/color';
|
|
|
9
23
|
import styles from './Styles/MediaPlayerDetailStyles';
|
|
10
24
|
import FImage from '../../commons/FImage';
|
|
11
25
|
import { TESTID } from '../../configs/Constants';
|
|
26
|
+
import { SCContext, useSCContextSelector } from '../../context';
|
|
27
|
+
import { Action } from '../../context/actionType';
|
|
12
28
|
|
|
13
29
|
const MediaPlayerDetail = ({
|
|
14
30
|
uri,
|
|
@@ -16,7 +32,6 @@ const MediaPlayerDetail = ({
|
|
|
16
32
|
thumbnail,
|
|
17
33
|
style,
|
|
18
34
|
wrapStyles,
|
|
19
|
-
resizeMode = 'none',
|
|
20
35
|
amount,
|
|
21
36
|
handleFullScreen,
|
|
22
37
|
isPaused = true,
|
|
@@ -25,6 +40,10 @@ const MediaPlayerDetail = ({
|
|
|
25
40
|
width,
|
|
26
41
|
height,
|
|
27
42
|
}) => {
|
|
43
|
+
const { setAction } = useContext(SCContext);
|
|
44
|
+
const isFirstOpenCamera = useSCContextSelector(
|
|
45
|
+
(state) => state.app.isFirstOpenCamera
|
|
46
|
+
);
|
|
28
47
|
const t = useTranslations();
|
|
29
48
|
const [paused, setPaused] = useState(isPaused);
|
|
30
49
|
const onTapPause = useCallback(() => {
|
|
@@ -72,13 +91,63 @@ const MediaPlayerDetail = ({
|
|
|
72
91
|
};
|
|
73
92
|
}, [amount]);
|
|
74
93
|
|
|
94
|
+
const renderCamera = useMemo(() => {
|
|
95
|
+
return (
|
|
96
|
+
<VLCPlayer
|
|
97
|
+
autoAspectRatio={true}
|
|
98
|
+
videoAspectRatio={
|
|
99
|
+
width && height
|
|
100
|
+
? `${width}:${height}`
|
|
101
|
+
: `${getWidthHeight().width}:${getWidthHeight().height}`
|
|
102
|
+
}
|
|
103
|
+
source={{
|
|
104
|
+
initType: 2,
|
|
105
|
+
hwDecoderEnabled: 1,
|
|
106
|
+
hwDecoderForced: 1,
|
|
107
|
+
uri,
|
|
108
|
+
initOptions: [
|
|
109
|
+
'--no-audio',
|
|
110
|
+
'--rtsp-tcp',
|
|
111
|
+
'--network-caching=150',
|
|
112
|
+
'--rtsp-caching=150',
|
|
113
|
+
'--no-stats',
|
|
114
|
+
'--tcp-caching=150',
|
|
115
|
+
'--realrtsp-caching=150',
|
|
116
|
+
],
|
|
117
|
+
}}
|
|
118
|
+
style={[
|
|
119
|
+
styles.player,
|
|
120
|
+
style,
|
|
121
|
+
{
|
|
122
|
+
width: width || getWidthHeight().width,
|
|
123
|
+
height: height || getWidthHeight().height,
|
|
124
|
+
},
|
|
125
|
+
isFirstOpenCamera && styles.firstOpenCamera,
|
|
126
|
+
]}
|
|
127
|
+
isLive={true}
|
|
128
|
+
/>
|
|
129
|
+
);
|
|
130
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
131
|
+
}, [uri, isFirstOpenCamera]);
|
|
132
|
+
|
|
75
133
|
useEffect(() => {
|
|
76
134
|
setPaused(isPaused);
|
|
77
135
|
}, [isPaused]);
|
|
78
136
|
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (isFirstOpenCamera) {
|
|
139
|
+
const to = setTimeout(() => {
|
|
140
|
+
setAction(Action.IS_FIRST_OPEN_CAMERA, false);
|
|
141
|
+
clearTimeout(to);
|
|
142
|
+
}, 500);
|
|
143
|
+
}
|
|
144
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
145
|
+
}, [isFirstOpenCamera]);
|
|
146
|
+
|
|
79
147
|
const source = !thumbnail || !thumbnail.uri ? Images.BgDevice : thumbnail;
|
|
80
148
|
return (
|
|
81
149
|
<View style={[styles.wrap, wrapStyles]}>
|
|
150
|
+
{isFirstOpenCamera && Platform.OS === 'ios' && renderCamera}
|
|
82
151
|
<View style={[styles.loadingWrap]}>
|
|
83
152
|
<Text style={styles.loadingText}>{t('loading')}</Text>
|
|
84
153
|
</View>
|
|
@@ -103,42 +172,7 @@ const MediaPlayerDetail = ({
|
|
|
103
172
|
/>
|
|
104
173
|
</View>
|
|
105
174
|
) : (
|
|
106
|
-
|
|
107
|
-
autoAspectRatio={true}
|
|
108
|
-
videoAspectRatio={
|
|
109
|
-
width && height
|
|
110
|
-
? `${width}:${height}`
|
|
111
|
-
: `${getWidthHeight().width}:${getWidthHeight().height}`
|
|
112
|
-
}
|
|
113
|
-
source={{
|
|
114
|
-
initType: 2,
|
|
115
|
-
hwDecoderEnabled: 1,
|
|
116
|
-
hwDecoderForced: 1,
|
|
117
|
-
uri,
|
|
118
|
-
initOptions: [
|
|
119
|
-
'--no-audio',
|
|
120
|
-
'--rtsp-tcp',
|
|
121
|
-
'--network-caching=150',
|
|
122
|
-
'--rtsp-caching=150',
|
|
123
|
-
'--no-stats',
|
|
124
|
-
'--tcp-caching=150',
|
|
125
|
-
'--realrtsp-caching=150',
|
|
126
|
-
// '--avcodec-threads=20',
|
|
127
|
-
// '--live-cacheing=150',
|
|
128
|
-
],
|
|
129
|
-
}}
|
|
130
|
-
style={[
|
|
131
|
-
styles.player,
|
|
132
|
-
style,
|
|
133
|
-
{
|
|
134
|
-
width: width || getWidthHeight().width,
|
|
135
|
-
height: height || getWidthHeight().height,
|
|
136
|
-
},
|
|
137
|
-
]}
|
|
138
|
-
// resizeMode={resizeMode}
|
|
139
|
-
isLive={true}
|
|
140
|
-
// playInBackground={true}
|
|
141
|
-
/>
|
|
175
|
+
renderCamera
|
|
142
176
|
)}
|
|
143
177
|
|
|
144
178
|
<View style={styles.buttonView}>
|
|
@@ -84,7 +84,7 @@ const ShortDetailSubUnit = ({ unit, station, isGGHomeConnected }) => {
|
|
|
84
84
|
const itemAddNewTitle = t(
|
|
85
85
|
station?.isFavorites
|
|
86
86
|
? 'add_to_favorites'
|
|
87
|
-
: station?.name === SubUnitName.
|
|
87
|
+
: station?.name === SubUnitName.smart
|
|
88
88
|
? 'add_script'
|
|
89
89
|
: 'add_new'
|
|
90
90
|
);
|
package/src/configs/API.js
CHANGED
|
@@ -179,9 +179,9 @@ const API = {
|
|
|
179
179
|
},
|
|
180
180
|
},
|
|
181
181
|
NOTIFICATION: {
|
|
182
|
-
|
|
183
|
-
SCConfig.apiRoot + `/notifications/
|
|
184
|
-
SET_READ: (id) => SCConfig.apiRoot + `/notifications/
|
|
182
|
+
LIST_EOH_NOTIFICATIONS: (page, type) =>
|
|
183
|
+
SCConfig.apiRoot + `/notifications/eoh/?page=${page}&type=${type}`,
|
|
184
|
+
SET_READ: (id) => SCConfig.apiRoot + `/notifications/eoh/${id}/set_read/`,
|
|
185
185
|
},
|
|
186
186
|
EXTERNAL: {
|
|
187
187
|
GOOGLE_MAP: {
|
|
@@ -189,6 +189,8 @@ const API = {
|
|
|
189
189
|
'https://maps.googleapis.com/maps/api/place/autocomplete/json',
|
|
190
190
|
GET_LAT_LNG_BY_PLACE_ID:
|
|
191
191
|
'https://maps.googleapis.com/maps/api/place/details/json',
|
|
192
|
+
GET_LOCATION_FROM_LAT_LNG:
|
|
193
|
+
'https://maps.googleapis.com/maps/api/geocode/json',
|
|
192
194
|
},
|
|
193
195
|
},
|
|
194
196
|
SMART_ACCOUNT: {
|
package/src/configs/Constants.js
CHANGED
|
@@ -84,7 +84,7 @@ export const SCANNING_STATUS = {
|
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
export const SubUnitName = {
|
|
87
|
-
|
|
87
|
+
smart: 'Kịch Bản',
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
export const AUTOMATE_TYPE = {
|
|
@@ -572,6 +572,10 @@ export const TESTID = {
|
|
|
572
572
|
// ThreeButtonHistory
|
|
573
573
|
HISTORY_BUTTON: 'HISTORY_BUTTON',
|
|
574
574
|
HISTORY_CALENDAR: 'HISTORY_CALENDAR',
|
|
575
|
+
|
|
576
|
+
// SelectAddress
|
|
577
|
+
BUTTON_YOUR_LOCATION: 'BUTTON_YOUR_LOCATION',
|
|
578
|
+
BUTTON_CHOOSE_ON_MAP: 'BUTTON_CHOOSE_ON_MAP',
|
|
575
579
|
};
|
|
576
580
|
|
|
577
581
|
export const NOTIFICATION_TYPES = {
|
package/src/configs/Images.js
CHANGED
|
@@ -7,4 +7,7 @@ export default {
|
|
|
7
7
|
file: require('../Images/Common/file.png'),
|
|
8
8
|
activeButton: require('../Images/Common/ActiveButton.png'),
|
|
9
9
|
logo: require('../Images/Common/logo.png'),
|
|
10
|
+
buttonPauseCurtain: require('../Images/Common/buttonPause-center-curtain.png'),
|
|
11
|
+
buttonLeftCurtain: require('../Images/Common/buttonLeftCurtain.png'),
|
|
12
|
+
buttonRightCurtain: require('../Images/Common/buttonRightCurtain.png'),
|
|
10
13
|
};
|
|
@@ -4,6 +4,7 @@ export const Action = {
|
|
|
4
4
|
STORE_STATUS_BAR: 'STORE_STATUS_BAR',
|
|
5
5
|
LIST_DEVICE_TYPES: 'LIST_DEVICE_TYPES',
|
|
6
6
|
LIST_ACTION: 'LIST_ACTION',
|
|
7
|
+
IS_FIRST_OPEN_CAMERA: 'IS_FIRST_OPEN_CAMERA',
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
export type AuthData = {
|
|
@@ -44,3 +45,7 @@ export type ActionDataMap = {
|
|
|
44
45
|
LIST_DEVICE_TYPES: ListDevice;
|
|
45
46
|
LIST_ACTION: ListAction;
|
|
46
47
|
};
|
|
48
|
+
|
|
49
|
+
export type AppType = {
|
|
50
|
+
isFirstOpenCamera: boolean;
|
|
51
|
+
};
|
package/src/context/mockStore.ts
CHANGED
|
@@ -47,5 +47,8 @@ export const mockSCStore = (data: ContextData): ContextData => {
|
|
|
47
47
|
barStyle: data?.statusBar?.barStyle || mockDataStore?.statusBar?.barStyle,
|
|
48
48
|
},
|
|
49
49
|
listAction: [...mockDataStore.listAction, ...(data?.listAction || [])],
|
|
50
|
+
app: {
|
|
51
|
+
isFirstOpenCamera: true,
|
|
52
|
+
},
|
|
50
53
|
};
|
|
51
54
|
};
|
package/src/context/reducer.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
Action,
|
|
8
8
|
ListDevice,
|
|
9
9
|
ListAction,
|
|
10
|
+
AppType,
|
|
10
11
|
} from './actionType';
|
|
11
12
|
|
|
12
13
|
export type ContextData = {
|
|
@@ -15,6 +16,7 @@ export type ContextData = {
|
|
|
15
16
|
listDevice: ListDevice;
|
|
16
17
|
listAction: ListAction;
|
|
17
18
|
statusBar: StatusBar;
|
|
19
|
+
app: AppType;
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export type Action = {
|
|
@@ -35,6 +37,9 @@ export const initialState = {
|
|
|
35
37
|
statusBar: {} as StatusBar,
|
|
36
38
|
listDevice: {} as ListDevice,
|
|
37
39
|
listAction: [] as ListAction,
|
|
40
|
+
app: {
|
|
41
|
+
isFirstOpenCamera: true,
|
|
42
|
+
},
|
|
38
43
|
};
|
|
39
44
|
|
|
40
45
|
export const reducer = (currentState: ContextData, action: Action) => {
|
|
@@ -83,6 +88,15 @@ export const reducer = (currentState: ContextData, action: Action) => {
|
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
return { ...currentState, listAction: newListAction };
|
|
91
|
+
|
|
92
|
+
case Action.IS_FIRST_OPEN_CAMERA:
|
|
93
|
+
return {
|
|
94
|
+
...currentState,
|
|
95
|
+
app: {
|
|
96
|
+
...currentState.app,
|
|
97
|
+
isFirstOpenCamera: payload,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
86
100
|
default:
|
|
87
101
|
return currentState;
|
|
88
102
|
}
|