@eohjsc/react-native-smart-city 0.3.24 → 0.3.25
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/configs/Constants.js +4 -0
- package/src/screens/PlayBackCamera/Timer.js +3 -0
- package/src/screens/PlayBackCamera/__test__/index.test.js +8 -1
- package/src/screens/PlayBackCamera/index.js +67 -46
- package/src/screens/Unit/Detail.js +16 -10
- package/src/screens/Unit/components/__test__/AutomateScript.test.js +116 -0
package/package.json
CHANGED
package/src/configs/Constants.js
CHANGED
|
@@ -25,6 +25,7 @@ const Timer = ({
|
|
|
25
25
|
normalHeight = 20,
|
|
26
26
|
value,
|
|
27
27
|
selected,
|
|
28
|
+
onScrollEndDrag,
|
|
28
29
|
}) => {
|
|
29
30
|
const scrollViewRef = useRef();
|
|
30
31
|
const [scrollX] = useState(new Animated.Value(0));
|
|
@@ -113,6 +114,8 @@ const Timer = ({
|
|
|
113
114
|
],
|
|
114
115
|
{ useNativeDriver: true }
|
|
115
116
|
)}
|
|
117
|
+
onScrollEndDrag={onScrollEndDrag}
|
|
118
|
+
onMomentumScrollEnd={onScrollEndDrag}
|
|
116
119
|
>
|
|
117
120
|
{renderTime}
|
|
118
121
|
</Animated.ScrollView>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import moment from 'moment';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Animated, TouchableOpacity } from 'react-native';
|
|
4
|
+
import { Calendar } from 'react-native-calendars';
|
|
5
|
+
|
|
4
6
|
import { act, create } from 'react-test-renderer';
|
|
5
7
|
import PlayBackCamera from '..';
|
|
6
8
|
import { ModalCustom } from '../../../commons/Modal';
|
|
@@ -58,6 +60,11 @@ describe('Test PlayBackCamera', () => {
|
|
|
58
60
|
await textOpenModal[0].props.onPress();
|
|
59
61
|
expect(mockSetState).toBeCalledWith(true);
|
|
60
62
|
|
|
63
|
+
const Calendars = instance.findAllByType(Calendar);
|
|
64
|
+
expect(Calendars).toHaveLength(1);
|
|
65
|
+
await Calendars[0].props.onDayPress({ dateString: '2022-07-01' });
|
|
66
|
+
expect(mockSetState).toBeCalledWith('2022-07-01');
|
|
67
|
+
|
|
61
68
|
mockSetState.mockClear();
|
|
62
69
|
const buttonCancel = instance.findAll(
|
|
63
70
|
(el) =>
|
|
@@ -83,7 +90,7 @@ describe('Test PlayBackCamera', () => {
|
|
|
83
90
|
el.type === TouchableOpacity
|
|
84
91
|
);
|
|
85
92
|
await buttonAddDate[0].props.onPress();
|
|
86
|
-
expect(mockSetState).
|
|
93
|
+
expect(mockSetState).toBeCalled();
|
|
87
94
|
|
|
88
95
|
mockSetState.mockClear();
|
|
89
96
|
const buttonSubDate = instance.findAll(
|
|
@@ -13,13 +13,13 @@ import Text from '../../commons/Text';
|
|
|
13
13
|
import Timer from './Timer';
|
|
14
14
|
import { useStatusBarPreview } from '../../hooks/Common/useStatusBar';
|
|
15
15
|
import MediaPlayerFull from '../../commons/MediaPlayerDetail/MediaPlayerFull';
|
|
16
|
-
import { TESTID } from '../../configs/Constants';
|
|
16
|
+
import { DATE_TIME_FORMAT, TESTID } from '../../configs/Constants';
|
|
17
17
|
|
|
18
|
-
let dateTemp = moment().format(
|
|
18
|
+
let dateTemp = moment().format(DATE_TIME_FORMAT.YMD);
|
|
19
19
|
let isFirstTime = true;
|
|
20
20
|
|
|
21
21
|
const PlayBackCamera = () => {
|
|
22
|
-
const now = useMemo(() => moment().format(
|
|
22
|
+
const now = useMemo(() => moment().format(DATE_TIME_FORMAT.YMD), []);
|
|
23
23
|
const hourTemp = useMemo(() => moment().format('HH:mm:ss'), []);
|
|
24
24
|
const arrHourTemp = useMemo(() => hourTemp.split(':'), [hourTemp]);
|
|
25
25
|
const t = useTranslations();
|
|
@@ -33,7 +33,8 @@ const PlayBackCamera = () => {
|
|
|
33
33
|
s: arrHourTemp[2],
|
|
34
34
|
});
|
|
35
35
|
const [uri, setUri] = useState(item?.configuration?.uri);
|
|
36
|
-
const [
|
|
36
|
+
const [mainURI, setMainURI] = useState(uri);
|
|
37
|
+
const [paused, setPaused] = useState(false);
|
|
37
38
|
const onOpenDateModal = useCallback(() => {
|
|
38
39
|
setIsShowDate(true);
|
|
39
40
|
}, []);
|
|
@@ -49,15 +50,19 @@ const PlayBackCamera = () => {
|
|
|
49
50
|
}, [selected]);
|
|
50
51
|
|
|
51
52
|
const onAddDate = useCallback(() => {
|
|
53
|
+
setPaused(true);
|
|
52
54
|
if (selected !== now) {
|
|
53
|
-
const date = moment(selected).add(1, 'days').format(
|
|
55
|
+
const date = moment(selected).add(1, 'days').format(DATE_TIME_FORMAT.YMD);
|
|
54
56
|
setSelected(date);
|
|
55
57
|
dateTemp = date;
|
|
56
58
|
}
|
|
57
59
|
}, [selected, now]);
|
|
58
60
|
|
|
59
61
|
const onSubtractDate = useCallback(() => {
|
|
60
|
-
|
|
62
|
+
setPaused(true);
|
|
63
|
+
const date = moment(selected)
|
|
64
|
+
.subtract(1, 'days')
|
|
65
|
+
.format(DATE_TIME_FORMAT.YMD);
|
|
61
66
|
setSelected(date);
|
|
62
67
|
dateTemp = date;
|
|
63
68
|
}, [selected]);
|
|
@@ -72,6 +77,25 @@ const PlayBackCamera = () => {
|
|
|
72
77
|
[item?.configuration?.time_zone]
|
|
73
78
|
);
|
|
74
79
|
|
|
80
|
+
const onScrollEndDrag = useCallback(() => {
|
|
81
|
+
setMainURI(uri);
|
|
82
|
+
setPaused(false);
|
|
83
|
+
}, [uri]);
|
|
84
|
+
|
|
85
|
+
const onDayPress = useCallback((day) => {
|
|
86
|
+
setPaused(true);
|
|
87
|
+
setSelected(day.dateString);
|
|
88
|
+
}, []);
|
|
89
|
+
|
|
90
|
+
const onPressArrowLeft = useCallback((subtractMonth) => {
|
|
91
|
+
setPaused(true);
|
|
92
|
+
subtractMonth && subtractMonth();
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
const onPressArrowRight = useCallback((addMonth) => {
|
|
96
|
+
addMonth && addMonth();
|
|
97
|
+
}, []);
|
|
98
|
+
|
|
75
99
|
const onChangeValue = useCallback(
|
|
76
100
|
(value, selectedTime) => {
|
|
77
101
|
if (!isFirstTime) {
|
|
@@ -100,10 +124,6 @@ const PlayBackCamera = () => {
|
|
|
100
124
|
}T${getHourWithTimeZone(h)}${m}${s}Z`
|
|
101
125
|
);
|
|
102
126
|
}
|
|
103
|
-
const to = setTimeout(() => {
|
|
104
|
-
setPaused(false);
|
|
105
|
-
clearTimeout(to);
|
|
106
|
-
}, 100);
|
|
107
127
|
}
|
|
108
128
|
},
|
|
109
129
|
[
|
|
@@ -115,27 +135,37 @@ const PlayBackCamera = () => {
|
|
|
115
135
|
]
|
|
116
136
|
);
|
|
117
137
|
|
|
138
|
+
const renderArrow = useCallback((direction) => {
|
|
139
|
+
return (
|
|
140
|
+
<Image
|
|
141
|
+
source={Images.arrowLeft}
|
|
142
|
+
style={[direction !== 'left' && styles.arrowRight]}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
}, []);
|
|
146
|
+
|
|
118
147
|
useEffect(() => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
148
|
+
if (!isFirstTime) {
|
|
149
|
+
const date = selected.split('-');
|
|
150
|
+
const playback = item?.configuration?.playback || '';
|
|
151
|
+
if (
|
|
152
|
+
selected === now &&
|
|
153
|
+
parseInt(moment().format('HH:mm:ss'), 10) <=
|
|
154
|
+
parseInt(`${hour.h}:${hour.m}:${hour.s}`, 10)
|
|
155
|
+
) {
|
|
156
|
+
setMainURI(item?.configuration?.uri);
|
|
157
|
+
} else {
|
|
158
|
+
setMainURI(
|
|
159
|
+
`${playback.split('=')[0]}=${date[0]}${date[1]}${
|
|
160
|
+
date[2]
|
|
161
|
+
}T${getHourWithTimeZone(hour.h)}${hour.m}${hour.s}Z`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const to = setTimeout(() => {
|
|
165
|
+
setPaused(false);
|
|
166
|
+
clearTimeout(to);
|
|
167
|
+
}, 100);
|
|
134
168
|
}
|
|
135
|
-
const to = setTimeout(() => {
|
|
136
|
-
setPaused(false);
|
|
137
|
-
clearTimeout(to);
|
|
138
|
-
}, 100);
|
|
139
169
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
140
170
|
}, [selected, getHourWithTimeZone]);
|
|
141
171
|
|
|
@@ -152,7 +182,7 @@ const PlayBackCamera = () => {
|
|
|
152
182
|
clearTimeout(to);
|
|
153
183
|
}, 2000);
|
|
154
184
|
return () => {
|
|
155
|
-
dateTemp = moment().format(
|
|
185
|
+
dateTemp = moment().format(DATE_TIME_FORMAT.YMD);
|
|
156
186
|
isFirstTime = true;
|
|
157
187
|
};
|
|
158
188
|
}, []);
|
|
@@ -161,7 +191,7 @@ const PlayBackCamera = () => {
|
|
|
161
191
|
<View style={styles.wrap}>
|
|
162
192
|
<HeaderCustom title={t('video_detail')} />
|
|
163
193
|
<MediaPlayerFull
|
|
164
|
-
uri={
|
|
194
|
+
uri={mainURI}
|
|
165
195
|
isPaused={paused}
|
|
166
196
|
thumbnail={thumbnail}
|
|
167
197
|
isShowFullScreenIcon
|
|
@@ -223,6 +253,7 @@ const PlayBackCamera = () => {
|
|
|
223
253
|
indicatorHeight={40}
|
|
224
254
|
onChangeValue={onChangeValue}
|
|
225
255
|
selected={selected}
|
|
256
|
+
onScrollEndDrag={onScrollEndDrag}
|
|
226
257
|
/>
|
|
227
258
|
</View>
|
|
228
259
|
</View>
|
|
@@ -230,13 +261,10 @@ const PlayBackCamera = () => {
|
|
|
230
261
|
<ModalCustom isVisible={isShowDate} style={styles.modal}>
|
|
231
262
|
<View style={styles.wrapDate}>
|
|
232
263
|
<Calendar
|
|
233
|
-
onDayPress={
|
|
234
|
-
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
onMonthChange={(month) => {}}
|
|
238
|
-
onPressArrowLeft={(subtractMonth) => subtractMonth()}
|
|
239
|
-
onPressArrowRight={(addMonth) => addMonth()}
|
|
264
|
+
onDayPress={onDayPress}
|
|
265
|
+
maxDate={moment().format(DATE_TIME_FORMAT.YMD)}
|
|
266
|
+
onPressArrowLeft={onPressArrowLeft}
|
|
267
|
+
onPressArrowRight={onPressArrowRight}
|
|
240
268
|
markedDates={{
|
|
241
269
|
[selected]: {
|
|
242
270
|
selected: true,
|
|
@@ -246,14 +274,7 @@ const PlayBackCamera = () => {
|
|
|
246
274
|
},
|
|
247
275
|
}}
|
|
248
276
|
enableSwipeMonths={true}
|
|
249
|
-
renderArrow={
|
|
250
|
-
if (direction === 'left') {
|
|
251
|
-
return <Image source={Images.arrowLeft} />;
|
|
252
|
-
}
|
|
253
|
-
return (
|
|
254
|
-
<Image source={Images.arrowLeft} style={styles.arrowRight} />
|
|
255
|
-
);
|
|
256
|
-
}}
|
|
277
|
+
renderArrow={renderArrow}
|
|
257
278
|
headerStyle={styles.headerStyle}
|
|
258
279
|
/>
|
|
259
280
|
<View style={styles.viewSeparated} />
|
|
@@ -291,6 +291,21 @@ const UnitDetail = ({ route }) => {
|
|
|
291
291
|
navigate(isLavidaSource ? Routes.SmartHomeDashboard : Routes.Dashboard);
|
|
292
292
|
}, [isLavidaSource, navigate]);
|
|
293
293
|
|
|
294
|
+
const renderCamera = useMemo(() => {
|
|
295
|
+
return (
|
|
296
|
+
isFirstOpenCamera &&
|
|
297
|
+
isIOS && (
|
|
298
|
+
<MediaPlayerDetail
|
|
299
|
+
uri={Constants.URL_STREAM_CAMERA_DEMO}
|
|
300
|
+
isPaused={false}
|
|
301
|
+
width={1}
|
|
302
|
+
height={1}
|
|
303
|
+
style={styles.fakeCamera}
|
|
304
|
+
/>
|
|
305
|
+
)
|
|
306
|
+
);
|
|
307
|
+
}, [isFirstOpenCamera, isIOS]);
|
|
308
|
+
|
|
294
309
|
useEffect(() => {
|
|
295
310
|
watchNotificationData(user, onRefresh);
|
|
296
311
|
return () => unwatchNotificationData(user);
|
|
@@ -319,16 +334,7 @@ const UnitDetail = ({ route }) => {
|
|
|
319
334
|
hideRightPlus={!isOwner}
|
|
320
335
|
onBack={(isSuccessfullyConnected && Dashboard) || (routeName && onBack)}
|
|
321
336
|
>
|
|
322
|
-
{
|
|
323
|
-
{isFirstOpenCamera && isIOS && (
|
|
324
|
-
<MediaPlayerDetail
|
|
325
|
-
uri={Constants.URL_STREAM_CAMERA_DEMO}
|
|
326
|
-
isPaused={false}
|
|
327
|
-
width={1}
|
|
328
|
-
height={1}
|
|
329
|
-
style={styles.fakeCamera}
|
|
330
|
-
/>
|
|
331
|
-
)}
|
|
337
|
+
{renderCamera}
|
|
332
338
|
|
|
333
339
|
<View style={styles.container}>
|
|
334
340
|
<Summaries unit={unit} />
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { TouchableWithoutFeedback, View } from 'react-native';
|
|
3
|
+
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import { AUTOMATE_TYPE } from '../../../../configs/Constants';
|
|
5
|
+
import { SCProvider } from '../../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
7
|
+
import AutomateScript from '../AutomateScript';
|
|
8
|
+
|
|
9
|
+
const mockOnPress = jest.fn();
|
|
10
|
+
|
|
11
|
+
const wrapComponent = (isSelected, automate = 'automate') => (
|
|
12
|
+
<SCProvider initState={mockSCStore({})}>
|
|
13
|
+
<AutomateScript
|
|
14
|
+
automate={automate}
|
|
15
|
+
onPress={mockOnPress}
|
|
16
|
+
isSelected={isSelected}
|
|
17
|
+
/>
|
|
18
|
+
</SCProvider>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
describe('test AutomateScript screen', () => {
|
|
22
|
+
let tree,
|
|
23
|
+
automate = { type: '' };
|
|
24
|
+
it('Test isSelected=false', async () => {
|
|
25
|
+
await act(async () => {
|
|
26
|
+
tree = await create(wrapComponent(false, automate));
|
|
27
|
+
});
|
|
28
|
+
const instance = tree.root;
|
|
29
|
+
const TouchableWithoutFeedbacks = instance.findAllByType(
|
|
30
|
+
TouchableWithoutFeedback
|
|
31
|
+
);
|
|
32
|
+
await TouchableWithoutFeedbacks[0].props.onPress();
|
|
33
|
+
expect(mockOnPress).toBeCalledWith(automate);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('Test isSelected=true', async () => {
|
|
37
|
+
await act(async () => {
|
|
38
|
+
tree = await create(wrapComponent(true));
|
|
39
|
+
});
|
|
40
|
+
const instance = tree.root;
|
|
41
|
+
const Views = instance.findAllByType(View);
|
|
42
|
+
expect(Views[0].props.style).toEqual([
|
|
43
|
+
{
|
|
44
|
+
padding: 12,
|
|
45
|
+
borderRadius: 10,
|
|
46
|
+
shadowColor: '#303133',
|
|
47
|
+
shadowOffset: {
|
|
48
|
+
height: 2,
|
|
49
|
+
width: 0,
|
|
50
|
+
},
|
|
51
|
+
shadowOpacity: 0.1,
|
|
52
|
+
shadowRadius: 3,
|
|
53
|
+
elevation: 4,
|
|
54
|
+
width: 353,
|
|
55
|
+
height: 204.144578313253,
|
|
56
|
+
backgroundColor: '#FFFFFF',
|
|
57
|
+
justifyContent: 'space-between',
|
|
58
|
+
marginBottom: 8,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
borderColor: '#00979D',
|
|
62
|
+
borderWidth: 2,
|
|
63
|
+
},
|
|
64
|
+
]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('Test render VALUE_CHANGE', async () => {
|
|
68
|
+
automate = { ...automate, type: AUTOMATE_TYPE.VALUE_CHANGE };
|
|
69
|
+
await act(async () => {
|
|
70
|
+
tree = await create(wrapComponent(true, automate));
|
|
71
|
+
});
|
|
72
|
+
const instance = tree.root;
|
|
73
|
+
const Views = instance.findAllByType(View);
|
|
74
|
+
expect(Views).toHaveLength(9);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('Test render ONE_TAP', async () => {
|
|
78
|
+
automate = { ...automate, type: AUTOMATE_TYPE.ONE_TAP };
|
|
79
|
+
await act(async () => {
|
|
80
|
+
tree = await create(wrapComponent(true, automate));
|
|
81
|
+
});
|
|
82
|
+
const instance = tree.root;
|
|
83
|
+
const Views = instance.findAllByType(View);
|
|
84
|
+
expect(Views).toHaveLength(9);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('Test render EVENT', async () => {
|
|
88
|
+
automate = { ...automate, type: AUTOMATE_TYPE.EVENT };
|
|
89
|
+
await act(async () => {
|
|
90
|
+
tree = await create(wrapComponent(true, automate));
|
|
91
|
+
});
|
|
92
|
+
const instance = tree.root;
|
|
93
|
+
const Views = instance.findAllByType(View);
|
|
94
|
+
expect(Views).toHaveLength(9);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('Test render SCHEDULE', async () => {
|
|
98
|
+
automate = { ...automate, type: AUTOMATE_TYPE.SCHEDULE };
|
|
99
|
+
await act(async () => {
|
|
100
|
+
tree = await create(wrapComponent(true, automate));
|
|
101
|
+
});
|
|
102
|
+
const instance = tree.root;
|
|
103
|
+
const Views = instance.findAllByType(View);
|
|
104
|
+
expect(Views).toHaveLength(9);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('Test render with iconKit', async () => {
|
|
108
|
+
automate = { ...automate, script: { icon_kit: 'iconKit' } };
|
|
109
|
+
await act(async () => {
|
|
110
|
+
tree = await create(wrapComponent(true, automate));
|
|
111
|
+
});
|
|
112
|
+
const instance = tree.root;
|
|
113
|
+
const Views = instance.findAllByType(View);
|
|
114
|
+
expect(Views).toHaveLength(10);
|
|
115
|
+
});
|
|
116
|
+
});
|