@eohjsc/react-native-smart-city 0.5.9 → 0.6.0
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/commons/Device/HorizontalBarChart.js +1 -1
- package/src/commons/Device/PowerConsumptionChart.js +154 -0
- package/src/commons/UnitSummary/ConfigHistoryChart/index.js +6 -61
- package/src/hooks/Common/useDevicesStatus.js +24 -23
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +3 -3
- package/src/screens/Device/components/SensorDisplayItem.js +0 -4
- package/src/screens/PlayBackCamera/Styles/index.js +2 -4
- package/src/screens/PlayBackCamera/Timer.js +65 -47
- package/src/screens/PlayBackCamera/__test__/index.test.js +27 -19
- package/src/screens/PlayBackCamera/index.js +114 -111
- package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +10 -23
- package/src/screens/UnitSummary/components/PowerConsumption/__test__/PowerConsumption.test.js +38 -3
- package/src/screens/UnitSummary/components/PowerConsumption/index.js +21 -30
- package/src/commons/Device/HistoryChart.js +0 -225
- package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +0 -289
- package/src/screens/Device/__test__/DetailHistoryChart.test.js +0 -69
- package/src/screens/Device/components/DetailHistoryChart.js +0 -118
package/package.json
CHANGED
|
@@ -123,7 +123,7 @@ const HorizontalBarChart = memo(({ datas, config }) => {
|
|
|
123
123
|
y: item.y,
|
|
124
124
|
};
|
|
125
125
|
});
|
|
126
|
-
const dataX = (datas[0]
|
|
126
|
+
const dataX = (datas[0]?.data || []).map((item) => item.x);
|
|
127
127
|
const maxY = getMaxValueIndex(dataY);
|
|
128
128
|
if (!isEmpty(maxY.max)) {
|
|
129
129
|
dataY.splice(maxY._index, 1, { ...maxY.max, color: Colors.Primary });
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import React, { memo, useCallback, useState, useMemo, useEffect } from 'react';
|
|
2
|
+
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import moment from 'moment';
|
|
4
|
+
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
|
+
|
|
6
|
+
import { Colors } from '../../configs';
|
|
7
|
+
import Text from '../Text';
|
|
8
|
+
import Button from '../Button';
|
|
9
|
+
import CurrencyInput from '../Form/CurrencyInput';
|
|
10
|
+
import DateTimeRangeChange from '../DateTimeRangeChange';
|
|
11
|
+
import HorizontalBarChart from './HorizontalBarChart';
|
|
12
|
+
import ChartAggregationOption from '../ChartAggregationOption';
|
|
13
|
+
import { formatMoney } from '../../utils/Utils';
|
|
14
|
+
|
|
15
|
+
const PowerConsumptionChart = memo(
|
|
16
|
+
({
|
|
17
|
+
datas,
|
|
18
|
+
chartConfig,
|
|
19
|
+
setChartConfig,
|
|
20
|
+
style,
|
|
21
|
+
groupBy,
|
|
22
|
+
setGroupBy,
|
|
23
|
+
onChangeDate,
|
|
24
|
+
}) => {
|
|
25
|
+
const t = useTranslations();
|
|
26
|
+
const [price, setPrice] = useState(null);
|
|
27
|
+
|
|
28
|
+
const onCalculateCost = useCallback(() => {
|
|
29
|
+
setChartConfig((config) => ({
|
|
30
|
+
...config,
|
|
31
|
+
price,
|
|
32
|
+
}));
|
|
33
|
+
}, [setChartConfig, price]);
|
|
34
|
+
|
|
35
|
+
const totalPrice = useMemo(() => {
|
|
36
|
+
const { price: chartPrice } = chartConfig;
|
|
37
|
+
if (chartPrice === '' || isNaN(chartPrice)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const sum = datas[0].data.reduce((a, b) => a + b.y, 0);
|
|
41
|
+
const roundedSum = sum * chartPrice;
|
|
42
|
+
return roundedSum.toFixed();
|
|
43
|
+
}, [datas, chartConfig]);
|
|
44
|
+
|
|
45
|
+
const renderChart = useMemo(() => {
|
|
46
|
+
return <HorizontalBarChart datas={datas} config={chartConfig} />;
|
|
47
|
+
}, [chartConfig, datas]);
|
|
48
|
+
|
|
49
|
+
const [value, setValue] = useState([
|
|
50
|
+
moment().subtract(6, 'days'),
|
|
51
|
+
moment(),
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
onChangeDate(value[0], value[1]);
|
|
56
|
+
}, [onChangeDate, value]);
|
|
57
|
+
|
|
58
|
+
const selectStart = (date) => {
|
|
59
|
+
setValue((state) => [date, state[1]]);
|
|
60
|
+
};
|
|
61
|
+
const selectEnd = (date) => {
|
|
62
|
+
setValue((state) => [state[0], date]);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<View style={style}>
|
|
67
|
+
<View style={styles.historyView}>
|
|
68
|
+
<View style={styles.titleHistory}>
|
|
69
|
+
<Text size={20} semibold color={Colors.Gray9}>
|
|
70
|
+
{t('history')}
|
|
71
|
+
</Text>
|
|
72
|
+
|
|
73
|
+
<ChartAggregationOption groupBy={groupBy} setGroupBy={setGroupBy} />
|
|
74
|
+
</View>
|
|
75
|
+
{groupBy === 'date' && (
|
|
76
|
+
<DateTimeRangeChange
|
|
77
|
+
startTime={value[0]}
|
|
78
|
+
endTime={value[1]}
|
|
79
|
+
selectStart={selectStart}
|
|
80
|
+
selectEnd={selectEnd}
|
|
81
|
+
/>
|
|
82
|
+
)}
|
|
83
|
+
</View>
|
|
84
|
+
|
|
85
|
+
<View style={styles.wrapCalculateCost}>
|
|
86
|
+
<Text type="H4">
|
|
87
|
+
{t('input_price_to_calculate_electricity_cost')}
|
|
88
|
+
</Text>
|
|
89
|
+
<View style={styles.row}>
|
|
90
|
+
<CurrencyInput
|
|
91
|
+
value={price}
|
|
92
|
+
onChange={setPrice}
|
|
93
|
+
minValue={0}
|
|
94
|
+
maxValue={100000000}
|
|
95
|
+
placeholder={'0'}
|
|
96
|
+
onSubmitEditing={onCalculateCost}
|
|
97
|
+
/>
|
|
98
|
+
<Button
|
|
99
|
+
type="primary"
|
|
100
|
+
title={t('calculate_cost')}
|
|
101
|
+
onPress={onCalculateCost}
|
|
102
|
+
style={styles.buttonCalculate}
|
|
103
|
+
textSemiBold={false}
|
|
104
|
+
/>
|
|
105
|
+
</View>
|
|
106
|
+
</View>
|
|
107
|
+
|
|
108
|
+
{renderChart}
|
|
109
|
+
{!!chartConfig.price && (
|
|
110
|
+
<Text type="H4">
|
|
111
|
+
{t('total_power_price')} <Text bold>{formatMoney(totalPrice)}</Text>
|
|
112
|
+
</Text>
|
|
113
|
+
)}
|
|
114
|
+
</View>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
export default PowerConsumptionChart;
|
|
120
|
+
|
|
121
|
+
const styles = StyleSheet.create({
|
|
122
|
+
historyView: {
|
|
123
|
+
paddingTop: 16,
|
|
124
|
+
},
|
|
125
|
+
titleHistory: {
|
|
126
|
+
flexDirection: 'row',
|
|
127
|
+
alignItems: 'center',
|
|
128
|
+
justifyContent: 'space-between',
|
|
129
|
+
},
|
|
130
|
+
chartInfo: {
|
|
131
|
+
flexDirection: 'row',
|
|
132
|
+
justifyContent: 'center',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
},
|
|
135
|
+
chartContainer: {
|
|
136
|
+
marginLeft: -8,
|
|
137
|
+
},
|
|
138
|
+
chart: {
|
|
139
|
+
height: 300,
|
|
140
|
+
},
|
|
141
|
+
wrapCalculateCost: {
|
|
142
|
+
marginTop: 12,
|
|
143
|
+
},
|
|
144
|
+
row: {
|
|
145
|
+
flexDirection: 'row',
|
|
146
|
+
alignItems: 'center',
|
|
147
|
+
marginTop: 8,
|
|
148
|
+
},
|
|
149
|
+
buttonCalculate: {
|
|
150
|
+
width: null,
|
|
151
|
+
flex: null,
|
|
152
|
+
paddingHorizontal: 12,
|
|
153
|
+
},
|
|
154
|
+
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
2
|
import moment from 'moment';
|
|
3
3
|
|
|
4
4
|
import { API } from '../../../configs';
|
|
5
|
-
import HistoryChart from '../../../commons/Device/HistoryChart';
|
|
6
5
|
import { axiosGet } from '../../../utils/Apis/axios';
|
|
7
6
|
import { getPusher } from '../../../utils/Pusher';
|
|
8
7
|
|
|
@@ -39,11 +38,12 @@ export const useFetchConfigHistory = (
|
|
|
39
38
|
});
|
|
40
39
|
|
|
41
40
|
const timezone = moment().utcOffset();
|
|
42
|
-
startDate = startDate.subtract(timezone, 'minutes');
|
|
43
|
-
endDate = endDate.subtract(timezone, 'minutes');
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
const date_from = moment(startDate).subtract(timezone, 'minutes');
|
|
43
|
+
const date_to = moment(endDate).subtract(timezone, 'minutes');
|
|
44
|
+
|
|
45
|
+
params.append('date_from', date_from.format('YYYY-MM-DDTHH:mm:ss'));
|
|
46
|
+
params.append('date_to', date_to.format('YYYY-MM-DDTHH:mm:ss'));
|
|
47
47
|
|
|
48
48
|
const { success, data } = await axiosGet(endpoint, {
|
|
49
49
|
params,
|
|
@@ -122,58 +122,3 @@ export const updateConfigChart = async (
|
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
};
|
|
125
|
-
|
|
126
|
-
let timeoutId;
|
|
127
|
-
|
|
128
|
-
const ConfigHistoryChart = ({ configs }) => {
|
|
129
|
-
const [chartData, setChartData] = useState(configs);
|
|
130
|
-
const [startDate, setStartDate] = useState(
|
|
131
|
-
moment().subtract(1, 'days').valueOf()
|
|
132
|
-
);
|
|
133
|
-
const [endDate, setEndDate] = useState(moment().valueOf());
|
|
134
|
-
|
|
135
|
-
useEffect(() => {
|
|
136
|
-
const fetchData = async () => {
|
|
137
|
-
let params = new URLSearchParams();
|
|
138
|
-
let configuration = configs.filter((item) => item.id);
|
|
139
|
-
configuration.map((item) => {
|
|
140
|
-
params.append('configs', item.id);
|
|
141
|
-
});
|
|
142
|
-
params.append(
|
|
143
|
-
'date_from',
|
|
144
|
-
moment(startDate).utc().format('YYYY-MM-DD HH:mm:ss')
|
|
145
|
-
);
|
|
146
|
-
params.append(
|
|
147
|
-
'date_to',
|
|
148
|
-
moment(endDate).utc().format('YYYY-MM-DD HH:mm:ss')
|
|
149
|
-
);
|
|
150
|
-
const { success, data } = await axiosGet(
|
|
151
|
-
API.CONFIG.DISPLAY_HISTORY_V3(),
|
|
152
|
-
{
|
|
153
|
-
params,
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
updateConfigChart(success, data, configuration, setChartData);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
timeoutId = setTimeout(fetchData, 200);
|
|
160
|
-
return () => {
|
|
161
|
-
clearTimeout(timeoutId);
|
|
162
|
-
};
|
|
163
|
-
}, [startDate, endDate, configs]);
|
|
164
|
-
|
|
165
|
-
if (!chartData.length) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return (
|
|
170
|
-
<HistoryChart
|
|
171
|
-
configuration={{ type: 'line_chart', date_format: 'DD.MM' }}
|
|
172
|
-
datas={chartData}
|
|
173
|
-
setStartDate={setStartDate}
|
|
174
|
-
setEndDate={setEndDate}
|
|
175
|
-
/>
|
|
176
|
-
);
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
export default ConfigHistoryChart;
|
|
@@ -5,20 +5,21 @@ import { axiosGet } from '../../utils/Apis/axios';
|
|
|
5
5
|
import { API } from '../../configs';
|
|
6
6
|
import { Action } from '../../context/actionType';
|
|
7
7
|
|
|
8
|
+
let timeoutId = null;
|
|
9
|
+
|
|
8
10
|
const useDevicesStatus = (unit, devices) => {
|
|
9
11
|
const { setAction } = useContext(SCContext);
|
|
10
12
|
const isNetworkConnected = useSCContextSelector(
|
|
11
13
|
(state) => state.app.isNetworkConnected
|
|
12
14
|
);
|
|
13
15
|
const isFocused = useIsFocused();
|
|
14
|
-
const
|
|
15
|
-
const hasFetchedRef = useRef(false);
|
|
16
|
+
const hasFetched = useRef(false); // Track if data has been fetched
|
|
16
17
|
|
|
17
18
|
const getDevicesStatus = useCallback(
|
|
18
19
|
async (_unit, _devices) => {
|
|
19
|
-
if (
|
|
20
|
-
clearTimeout(
|
|
21
|
-
|
|
20
|
+
if (timeoutId) {
|
|
21
|
+
clearTimeout(timeoutId);
|
|
22
|
+
timeoutId = null;
|
|
22
23
|
}
|
|
23
24
|
const params = new URLSearchParams();
|
|
24
25
|
_devices.forEach((device) => {
|
|
@@ -30,24 +31,18 @@ const useDevicesStatus = (unit, devices) => {
|
|
|
30
31
|
params: params,
|
|
31
32
|
}
|
|
32
33
|
);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
timeoutIdRef.current = setTimeout(
|
|
37
|
-
() => getDevicesStatus(_unit, _devices),
|
|
38
|
-
10000
|
|
39
|
-
);
|
|
34
|
+
success && setAction(Action.SET_DEVICES_STATUS, data);
|
|
35
|
+
timeoutId = setTimeout(() => getDevicesStatus(_unit, _devices), 10000);
|
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
40
37
|
},
|
|
41
38
|
[setAction]
|
|
42
39
|
);
|
|
43
40
|
|
|
44
41
|
useEffect(() => {
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
hasFetchedRef.current
|
|
50
|
-
) {
|
|
42
|
+
if (!isFocused || !isNetworkConnected || hasFetched.current) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!devices?.length) {
|
|
51
46
|
return;
|
|
52
47
|
}
|
|
53
48
|
|
|
@@ -57,19 +52,25 @@ const useDevicesStatus = (unit, devices) => {
|
|
|
57
52
|
if (!managedDevices.length) {
|
|
58
53
|
return;
|
|
59
54
|
}
|
|
55
|
+
|
|
60
56
|
getDevicesStatus(unit, devices);
|
|
61
|
-
|
|
57
|
+
hasFetched.current = true; // Mark as fetched
|
|
62
58
|
return () => {
|
|
63
|
-
if (
|
|
64
|
-
clearTimeout(
|
|
65
|
-
|
|
59
|
+
if (timeoutId) {
|
|
60
|
+
clearTimeout(timeoutId);
|
|
61
|
+
timeoutId = null;
|
|
66
62
|
}
|
|
67
63
|
};
|
|
68
64
|
}, [getDevicesStatus, unit, devices, isNetworkConnected, isFocused]);
|
|
69
65
|
|
|
70
66
|
useEffect(() => {
|
|
67
|
+
// Reset the hasFetched flag when the component is no longer focused
|
|
71
68
|
if (!isFocused) {
|
|
72
|
-
|
|
69
|
+
hasFetched.current = false;
|
|
70
|
+
if (timeoutId) {
|
|
71
|
+
clearTimeout(timeoutId); // Clear timeout when losing focus
|
|
72
|
+
timeoutId = null;
|
|
73
|
+
}
|
|
73
74
|
}
|
|
74
75
|
}, [isFocused]);
|
|
75
76
|
};
|
|
@@ -45,7 +45,7 @@ jest.mock('@react-navigation/native', () => {
|
|
|
45
45
|
|
|
46
46
|
describe('Test SensorDisplayItem', () => {
|
|
47
47
|
let tree;
|
|
48
|
-
it('render
|
|
48
|
+
it('render visualChart', async () => {
|
|
49
49
|
const item = {
|
|
50
50
|
id: 10452,
|
|
51
51
|
order: 0,
|
|
@@ -74,8 +74,8 @@ describe('Test SensorDisplayItem', () => {
|
|
|
74
74
|
tree = await renderer.create(wrapComponent({ item, sensor }));
|
|
75
75
|
});
|
|
76
76
|
const instance = tree.root;
|
|
77
|
-
const
|
|
78
|
-
expect(
|
|
77
|
+
const visualChart = instance.findAllByType(VisualChart);
|
|
78
|
+
expect(visualChart).toHaveLength(1);
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
it('render ActionGroup', async () => {
|
|
@@ -20,7 +20,6 @@ import { useConfigGlobalState } from '../../../iot/states';
|
|
|
20
20
|
import SmartIr from '../../../screens/SmartIr';
|
|
21
21
|
import { useEvaluateValue } from '../hooks/useEvaluateValue';
|
|
22
22
|
import styles from '../styles';
|
|
23
|
-
import { DetailHistoryChart } from './DetailHistoryChart';
|
|
24
23
|
import VisualChart from './VisualChart';
|
|
25
24
|
import { standardizeCameraScreenSize } from '../../../utils/Utils';
|
|
26
25
|
import { Device } from '../../../configs';
|
|
@@ -177,9 +176,6 @@ export const SensorDisplayItem = ({
|
|
|
177
176
|
/>
|
|
178
177
|
);
|
|
179
178
|
case 'history':
|
|
180
|
-
if (configuration?.config === 'power_consumption') {
|
|
181
|
-
return <DetailHistoryChart item={item} sensor={sensor} />;
|
|
182
|
-
}
|
|
183
179
|
return (
|
|
184
180
|
<VisualChart
|
|
185
181
|
item={item}
|
|
@@ -52,12 +52,14 @@ export default StyleSheet.create({
|
|
|
52
52
|
},
|
|
53
53
|
commonButton: {
|
|
54
54
|
height: 40,
|
|
55
|
+
width: 80,
|
|
55
56
|
justifyContent: 'center',
|
|
56
57
|
alignItems: 'center',
|
|
57
58
|
},
|
|
58
59
|
row: {
|
|
59
60
|
flexDirection: 'row',
|
|
60
61
|
alignItems: 'center',
|
|
62
|
+
marginHorizontal: 20,
|
|
61
63
|
},
|
|
62
64
|
container: {
|
|
63
65
|
position: 'absolute',
|
|
@@ -66,12 +68,8 @@ export default StyleSheet.create({
|
|
|
66
68
|
alignItems: 'center',
|
|
67
69
|
},
|
|
68
70
|
textDate: {
|
|
69
|
-
marginLeft: 32,
|
|
70
71
|
marginRight: 10,
|
|
71
72
|
},
|
|
72
|
-
iconDate: {
|
|
73
|
-
marginRight: 32,
|
|
74
|
-
},
|
|
75
73
|
timer: {
|
|
76
74
|
height: 80,
|
|
77
75
|
marginTop: 20,
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useEffect,
|
|
3
|
+
useMemo,
|
|
4
|
+
useRef,
|
|
5
|
+
useState,
|
|
6
|
+
useCallback,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import { View, Animated } from 'react-native';
|
|
3
9
|
import { Constants, Colors } from '../../configs';
|
|
4
10
|
import Text from '../../commons/Text';
|
|
5
11
|
import styles from './Styles/TimerStyles';
|
|
6
12
|
|
|
7
|
-
let time = -1;
|
|
8
|
-
let isFirstTime = true;
|
|
9
|
-
|
|
10
13
|
const Timer = ({
|
|
11
14
|
width = Constants.width,
|
|
12
15
|
onChangeValue,
|
|
@@ -29,70 +32,91 @@ const Timer = ({
|
|
|
29
32
|
}) => {
|
|
30
33
|
const scrollViewRef = useRef();
|
|
31
34
|
const [scrollX] = useState(new Animated.Value(0));
|
|
35
|
+
const isFirstTime = useRef(true); // Use useRef to track the first render
|
|
32
36
|
|
|
33
|
-
const snapSegment =
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const snapSegment = useMemo(
|
|
38
|
+
() => segmentWidth + segmentSpacing,
|
|
39
|
+
[segmentWidth, segmentSpacing]
|
|
40
|
+
);
|
|
41
|
+
const spacerWidth = useMemo(
|
|
42
|
+
() => (width - segmentWidth) / 2,
|
|
43
|
+
[width, segmentWidth]
|
|
44
|
+
);
|
|
45
|
+
const timerWidth = useMemo(
|
|
46
|
+
() => width - segmentWidth + (maximum - minimum) * snapSegment,
|
|
47
|
+
[width, segmentWidth, maximum, minimum, snapSegment]
|
|
48
|
+
);
|
|
36
49
|
|
|
37
50
|
const renderTime = useMemo(() => {
|
|
51
|
+
let time = -1;
|
|
38
52
|
const data = [...Array(maximum - minimum + 1).keys()].map(
|
|
39
53
|
(i) => i + minimum
|
|
40
54
|
);
|
|
55
|
+
|
|
41
56
|
return (
|
|
42
57
|
<View style={[styles.wrap, { width: timerWidth + segmentWidth }]}>
|
|
43
|
-
<View
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
<View style={{ width: spacerWidth }} />
|
|
59
|
+
{data.map((i) => {
|
|
60
|
+
const isStep = i % step === 0;
|
|
61
|
+
if (isStep) {
|
|
62
|
+
time += 1;
|
|
63
|
+
}
|
|
49
64
|
return (
|
|
50
65
|
<View key={i}>
|
|
51
66
|
<View
|
|
52
67
|
style={{
|
|
53
|
-
backgroundColor:
|
|
54
|
-
height:
|
|
68
|
+
backgroundColor: isStep ? stepColor : normalColor,
|
|
69
|
+
height: isStep ? stepHeight : normalHeight,
|
|
55
70
|
width: segmentWidth,
|
|
56
71
|
marginRight: segmentSpacing,
|
|
57
72
|
}}
|
|
58
73
|
/>
|
|
59
|
-
{
|
|
60
|
-
<Text type="Label" color={Colors.Gray7} style={styles.time}>
|
|
61
|
-
time < 9 ? '0' +
|
|
62
|
-
|
|
74
|
+
{isStep && (
|
|
75
|
+
<Text type="Label" color={Colors.Gray7} style={styles.time}>
|
|
76
|
+
{`${time < 9 ? '0' + time : time}:00`}
|
|
77
|
+
</Text>
|
|
63
78
|
)}
|
|
64
79
|
</View>
|
|
65
80
|
);
|
|
66
81
|
})}
|
|
67
82
|
</View>
|
|
68
83
|
);
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
}, [
|
|
85
|
+
maximum,
|
|
86
|
+
minimum,
|
|
87
|
+
step,
|
|
88
|
+
stepColor,
|
|
89
|
+
normalColor,
|
|
90
|
+
stepHeight,
|
|
91
|
+
normalHeight,
|
|
92
|
+
segmentWidth,
|
|
93
|
+
segmentSpacing,
|
|
94
|
+
timerWidth,
|
|
95
|
+
spacerWidth,
|
|
96
|
+
]);
|
|
71
97
|
|
|
72
98
|
useEffect(() => {
|
|
73
99
|
const scrollListener = scrollX.addListener(({ value: timeValue }) => {
|
|
74
|
-
!isFirstTime
|
|
100
|
+
if (!isFirstTime.current) {
|
|
101
|
+
onChangeValue(timeValue, selected);
|
|
102
|
+
}
|
|
75
103
|
});
|
|
104
|
+
|
|
76
105
|
return () => scrollX.removeListener(scrollListener);
|
|
77
|
-
|
|
78
|
-
}, [isFirstTime, selected]);
|
|
106
|
+
}, [scrollX, onChangeValue, selected]);
|
|
79
107
|
|
|
80
108
|
useEffect(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
109
|
+
const timeoutId = setTimeout(() => {
|
|
110
|
+
if (scrollViewRef.current) {
|
|
111
|
+
scrollViewRef.current.scrollTo({ x: value, animated: false });
|
|
112
|
+
}
|
|
113
|
+
isFirstTime.current = false; // Set to false after initial scroll
|
|
114
|
+
}, 400);
|
|
86
115
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
clearTimeout(to);
|
|
92
|
-
isFirstTime = false;
|
|
93
|
-
}, 400);
|
|
94
|
-
}
|
|
95
|
-
}, [value, scrollViewRef]);
|
|
116
|
+
return () => clearTimeout(timeoutId);
|
|
117
|
+
}, [value]);
|
|
118
|
+
|
|
119
|
+
const handleScrollEndDrag = useCallback(onScrollEndDrag, [onScrollEndDrag]);
|
|
96
120
|
|
|
97
121
|
return (
|
|
98
122
|
<View>
|
|
@@ -104,17 +128,11 @@ const Timer = ({
|
|
|
104
128
|
showsHorizontalScrollIndicator={false}
|
|
105
129
|
scrollEventThrottle={16}
|
|
106
130
|
onScroll={Animated.event(
|
|
107
|
-
[
|
|
108
|
-
{
|
|
109
|
-
nativeEvent: {
|
|
110
|
-
contentOffset: { x: scrollX },
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
],
|
|
131
|
+
[{ nativeEvent: { contentOffset: { x: scrollX } } }],
|
|
114
132
|
{ useNativeDriver: true }
|
|
115
133
|
)}
|
|
116
|
-
onScrollEndDrag={
|
|
117
|
-
onMomentumScrollEnd={
|
|
134
|
+
onScrollEndDrag={handleScrollEndDrag}
|
|
135
|
+
onMomentumScrollEnd={handleScrollEndDrag}
|
|
118
136
|
>
|
|
119
137
|
{renderTime}
|
|
120
138
|
</Animated.ScrollView>
|