@ledvance/ui-biz-bundle 1.1.145 → 1.1.147
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/modules/flags/FlagItem.tsx +14 -6
- package/src/newModules/energyConsumption/EnergyConsumptionActions.ts +87 -24
- package/src/newModules/energyConsumption/EnergyConsumptionPage.tsx +36 -31
- package/src/newModules/energyConsumption/component/PowerLineChart.tsx +4 -1
- package/src/newModules/mood/MoodItem.tsx +172 -166
- package/src/newModules/sleepWakeUp/SleepWakeUpPage.tsx +1 -1
- package/src/newModules/swithInching/SwithInching.tsx +2 -1
- package/src/newModules/timeSchedule/TimeScheduleActions.ts +5 -2
- package/src/newModules/timeSchedule/TimeScheduleDetailPage.tsx +2 -2
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { StyleSheet, View, Text, ViewStyle, Image } from 'react-native'
|
|
1
|
+
import { StyleSheet, View, Text, ViewStyle, Image, TouchableOpacity } from 'react-native'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import Card from '@ledvance/base/src/components/Card'
|
|
4
|
-
import {
|
|
4
|
+
import { Utils } from 'tuya-panel-kit'
|
|
5
5
|
import MoodColorsLine from '@ledvance/base/src/components/MoodColorsLine'
|
|
6
6
|
import Spacer from '@ledvance/base/src/components/Spacer'
|
|
7
7
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
8
|
+
import res from '@ledvance/base/src/res'
|
|
8
9
|
|
|
9
10
|
const cx = Utils.RatioUtils.convertX
|
|
10
11
|
const { withTheme } = Utils.ThemeUtils
|
|
@@ -31,6 +32,7 @@ function FlagItem(props: RecommendMoodItemProps) {
|
|
|
31
32
|
flexDirection: 'row',
|
|
32
33
|
marginHorizontal: cx(16),
|
|
33
34
|
justifyContent: 'space-between',
|
|
35
|
+
alignItems: 'center',
|
|
34
36
|
},
|
|
35
37
|
headText: {
|
|
36
38
|
color: props.theme?.global.fontColor,
|
|
@@ -39,6 +41,13 @@ function FlagItem(props: RecommendMoodItemProps) {
|
|
|
39
41
|
lineHeight: cx(20),
|
|
40
42
|
flex: 1
|
|
41
43
|
},
|
|
44
|
+
checkbox: {
|
|
45
|
+
width: cx(45),
|
|
46
|
+
height: cx(45),
|
|
47
|
+
marginTop: cx(-5),
|
|
48
|
+
marginBottom: cx(-10),
|
|
49
|
+
fontWeight: 'bold',
|
|
50
|
+
},
|
|
42
51
|
gradientItem: {
|
|
43
52
|
alignItems: 'center',
|
|
44
53
|
},
|
|
@@ -55,10 +64,9 @@ function FlagItem(props: RecommendMoodItemProps) {
|
|
|
55
64
|
{props.title ? <Text style={styles.headText}>{props.title}</Text> : undefined}
|
|
56
65
|
{props.icon ? <Image source={icon} style={{ width: cx(60), aspectRatio: 2.14, marginRight: cx(10) }} /> : undefined}
|
|
57
66
|
</View>
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
onValueChange={props.onSwitch} />
|
|
67
|
+
<TouchableOpacity style={styles.checkbox} onPress={() => props.onSwitch(!props.enable)}>
|
|
68
|
+
<Image source={{ uri: res.ic_check}} width={cx(44)} height={cx(44)} style={[styles.checkbox, { tintColor: props.enable ? props.theme?.icon.primary : props.theme?.icon.disable}]} />
|
|
69
|
+
</TouchableOpacity>
|
|
62
70
|
</View>
|
|
63
71
|
<Spacer />
|
|
64
72
|
<View style={styles.gradientItem}>
|
|
@@ -149,31 +149,94 @@ export interface PowerDataItem {
|
|
|
149
149
|
value: number
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
152
|
+
// 常量抽离(便于维护)
|
|
153
|
+
const DATA_POINT_INTERVAL_SEC = 10; // 预设数据间隔(秒)
|
|
154
|
+
const TIME_UNIT = 'minute' as const; // 时间单位(与 interval 配合)
|
|
155
|
+
const RETRY_CONFIG = {
|
|
156
|
+
maxRetries: 5,
|
|
157
|
+
initialDelay: 1000,
|
|
158
|
+
maxDelay: 30000,
|
|
159
|
+
backoffFactor: 2,
|
|
160
|
+
} as const;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 获取设备功率数据(保留所有实际数据,补充10秒间隔预设数据)
|
|
164
|
+
* @param devId 设备ID
|
|
165
|
+
* @param powerDpCode 功率数据点编码
|
|
166
|
+
* @param interval 时间区间(分钟)
|
|
167
|
+
* @returns 按时间排序的完整数据(预设数据 + 所有实际数据)
|
|
168
|
+
*/
|
|
169
|
+
export async function getPowerData(
|
|
170
|
+
devId: string,
|
|
171
|
+
powerDpCode: string,
|
|
172
|
+
interval: number
|
|
173
|
+
): Promise<PowerDataItem[]> {
|
|
174
|
+
try {
|
|
175
|
+
const now = dayjs();
|
|
176
|
+
const startTime = now.add(-interval, TIME_UNIT); // 起始时间:当前时间 - interval 分钟
|
|
177
|
+
const endTime = now; // 结束时间:当前时间
|
|
178
|
+
const startTimeMs = startTime.valueOf();
|
|
179
|
+
const endTimeMs = endTime.valueOf();
|
|
180
|
+
|
|
181
|
+
// 1. 生成预设数据(10秒间隔,仅覆盖 [startTime, endTime] 区间)
|
|
182
|
+
const totalSeconds = interval * 60;
|
|
183
|
+
const expectedDataPoints = Math.floor(totalSeconds / DATA_POINT_INTERVAL_SEC);
|
|
184
|
+
const presetData: PowerDataItem[] = [];
|
|
185
|
+
for (let i = 0; i < expectedDataPoints; i++) {
|
|
186
|
+
const timePoint = startTime.add(i * DATA_POINT_INTERVAL_SEC, 'second');
|
|
187
|
+
const timeMs = timePoint.valueOf();
|
|
188
|
+
// 确保预设数据不超出查询区间(防止边界计算误差)
|
|
189
|
+
if (timeMs > endTimeMs) break;
|
|
190
|
+
presetData.push({
|
|
191
|
+
key: timePoint.format('HH:mm:ss'),
|
|
192
|
+
chartTitle: timePoint.format('MM/DD/YYYY HH:mm:ss'),
|
|
193
|
+
time: timeMs,
|
|
194
|
+
value: 0,
|
|
195
|
+
});
|
|
175
196
|
}
|
|
176
|
-
|
|
197
|
+
|
|
198
|
+
// 2. 请求并处理实际数据(保留所有实际数据,不过滤)
|
|
199
|
+
const dpResult = await getSpecifiedTimeDpReportLogs(
|
|
200
|
+
devId,
|
|
201
|
+
[powerDpCode],
|
|
202
|
+
'ASC',
|
|
203
|
+
startTimeMs.toString(),
|
|
204
|
+
endTimeMs.toString(),
|
|
205
|
+
RETRY_CONFIG
|
|
206
|
+
);
|
|
207
|
+
// 类型校验 + 格式转换(避免异常)
|
|
208
|
+
const validDpResult = Array.isArray(dpResult) ? (dpResult as DpReportSataData[]) : [];
|
|
209
|
+
const actualData: PowerDataItem[] = validDpResult
|
|
210
|
+
.map((dp) => {
|
|
211
|
+
const timeMs = dp.timeStamp * 1000; // 秒级转毫秒级
|
|
212
|
+
// 过滤超出查询区间的实际数据(可选,根据业务需求)
|
|
213
|
+
if (timeMs < startTimeMs || timeMs > endTimeMs) return null;
|
|
214
|
+
return {
|
|
215
|
+
key: dayjs.unix(dp.timeStamp).format('HH:mm:ss'), // 统一 key 格式
|
|
216
|
+
chartTitle: dayjs.unix(dp.timeStamp).format('MM/DD/YYYY HH:mm:ss'),
|
|
217
|
+
time: timeMs,
|
|
218
|
+
value: parseFloat(dp.value) / 10, // 业务数值转换
|
|
219
|
+
};
|
|
220
|
+
})
|
|
221
|
+
.filter((item): item is PowerDataItem => item !== null); // 过滤无效数据
|
|
222
|
+
|
|
223
|
+
// 3. 合并预设数据和实际数据(去重:实际数据优先覆盖预设数据)
|
|
224
|
+
// 用 Map 实现 O(n) 合并(key:时间戳,value:数据项,实际数据覆盖预设)
|
|
225
|
+
const mergedMap = new Map<number, PowerDataItem>();
|
|
226
|
+
// 先加预设数据(后续实际数据相同时间戳会覆盖)
|
|
227
|
+
presetData.forEach((item) => mergedMap.set(item.time, item));
|
|
228
|
+
// 再加实际数据(覆盖相同时间戳的预设数据)
|
|
229
|
+
actualData.forEach((item) => mergedMap.set(item.time, item));
|
|
230
|
+
|
|
231
|
+
// 4. 按时间戳排序(Map 迭代顺序是插入顺序,必须显式排序)
|
|
232
|
+
const result = Array.from(mergedMap.values()).sort((a, b) => a.time - b.time);
|
|
233
|
+
|
|
234
|
+
return result;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error(`[getPowerData] 失败:devId=${devId}, powerDpCode=${powerDpCode}`, error);
|
|
237
|
+
// 兜底返回空数组(或仅返回预设数据,根据业务容错需求调整)
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
177
240
|
}
|
|
178
241
|
|
|
179
242
|
export const exportEnergyCsv = (values: any[][], unit: string) => {
|
|
@@ -342,19 +342,6 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
|
|
|
342
342
|
<Text style={{ fontSize: cx(14), color: props.theme?.global.fontColor, }}>{I18n.getLang(isGeneration ? 'generation_data_description_text' : 'consumption_data_description_text')}</Text>
|
|
343
343
|
</View>
|
|
344
344
|
<Spacer />
|
|
345
|
-
{/* Today */}
|
|
346
|
-
<Card
|
|
347
|
-
style={styles.cardContainer}
|
|
348
|
-
>
|
|
349
|
-
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field1_headline_text')}</Text>
|
|
350
|
-
<Spacer height={cx(15)} />
|
|
351
|
-
<View style={{ flexDirection: 'row', alignItems: 'flex-end' }}>
|
|
352
|
-
<Text style={[styles.consumptionNum, { fontSize: cx(38), marginRight: cx(8) }]}>{localeNumber(state.todayElectricity)}</Text>
|
|
353
|
-
<Text style={[styles.consumptionNum, { fontSize: cx(22), marginBottom: cx(4) }]}>kWh</Text>
|
|
354
|
-
</View>
|
|
355
|
-
<Spacer height={cx(10)} />
|
|
356
|
-
</Card>
|
|
357
|
-
<Spacer />
|
|
358
345
|
<Card
|
|
359
346
|
style={styles.cardContainer}
|
|
360
347
|
onPress={() => {
|
|
@@ -373,7 +360,17 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
|
|
|
373
360
|
} as EnergyConsumptionChartProps)
|
|
374
361
|
}}
|
|
375
362
|
>
|
|
376
|
-
<
|
|
363
|
+
<View style={{
|
|
364
|
+
flexDirection: 'row',
|
|
365
|
+
justifyContent: 'space-between',
|
|
366
|
+
alignItems: 'center',
|
|
367
|
+
}}>
|
|
368
|
+
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field2_headline_text')}</Text>
|
|
369
|
+
<Image
|
|
370
|
+
source={{ uri: res.energy_consumption_chart}}
|
|
371
|
+
style={{ width: cx(16), height: cx(16), marginLeft: cx(8) }}
|
|
372
|
+
/>
|
|
373
|
+
</View>
|
|
377
374
|
<Spacer height={cx(15)} />
|
|
378
375
|
<View style={styles.consumedEnergyContent}>
|
|
379
376
|
<ConsumedEnergyItem
|
|
@@ -393,24 +390,32 @@ const EnergyConsumptionPage = (props: {theme?: ThemeType}) => {
|
|
|
393
390
|
style={styles.cardContainer}
|
|
394
391
|
>
|
|
395
392
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
396
|
-
<Text style={styles.cardTitle}>{I18n.getLang('
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}}
|
|
402
|
-
>
|
|
403
|
-
<Image
|
|
404
|
-
source={{uri: res.co2_icon}}
|
|
405
|
-
resizeMode="contain"
|
|
406
|
-
style={{ height: cx(20), width: cx(20), tintColor: props.theme?.button.primary }}
|
|
407
|
-
/>
|
|
408
|
-
</TouchableOpacity>}
|
|
393
|
+
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field1_headline_text')}</Text>
|
|
394
|
+
<View style={{ flexDirection: 'row', alignItems: 'flex-end', marginLeft: cx(10) }}>
|
|
395
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(30), marginRight: cx(8) }]}>{localeNumber(state.todayElectricity)}</Text>
|
|
396
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(20), marginBottom: cx(4) }]}>kWh</Text>
|
|
397
|
+
</View>
|
|
409
398
|
</View>
|
|
410
|
-
<
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
399
|
+
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
400
|
+
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
401
|
+
<Text style={styles.cardTitle}>{I18n.getLang('consumption_data_field3_headline_text')}</Text>
|
|
402
|
+
{ state.energyGeneration.history.length > 0 && <TouchableOpacity
|
|
403
|
+
onPress={() => {
|
|
404
|
+
state.showPopup = true
|
|
405
|
+
state.popupType = 'history'
|
|
406
|
+
}}
|
|
407
|
+
>
|
|
408
|
+
<Image
|
|
409
|
+
source={{uri: res.co2_icon}}
|
|
410
|
+
resizeMode="contain"
|
|
411
|
+
style={{ height: cx(20), width: cx(20), tintColor: props.theme?.button.primary }}
|
|
412
|
+
/>
|
|
413
|
+
</TouchableOpacity>}
|
|
414
|
+
</View>
|
|
415
|
+
<View style={{ flexDirection: 'row', alignItems: 'flex-end', marginLeft: cx(10) }}>
|
|
416
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(30), marginRight: cx(8) }]}>{localeNumber(totalElectricity)}</Text>
|
|
417
|
+
<Text style={[styles.consumptionNum, { fontSize: cx(20), marginBottom: cx(4) }]}>kWh</Text>
|
|
418
|
+
</View>
|
|
414
419
|
</View>
|
|
415
420
|
<Spacer />
|
|
416
421
|
{/* CO2 */}
|
|
@@ -1,166 +1,172 @@
|
|
|
1
|
-
import React, { useMemo } from 'react';
|
|
2
|
-
import { StyleSheet, Text, View, ViewProps, ViewStyle, Image } from 'react-native';
|
|
3
|
-
import {
|
|
4
|
-
import { hsv2Hex } from '@ledvance/base/src/utils';
|
|
5
|
-
import { cctToColor } from '@ledvance/base/src/utils/cctUtils';
|
|
6
|
-
import { mapFloatToRange } from '@ledvance/base/src/utils';
|
|
7
|
-
import Card from '@ledvance/base/src/components/Card';
|
|
8
|
-
import Spacer from '@ledvance/base/src/components/Spacer';
|
|
9
|
-
import MoodColorsLine from '@ledvance/base/src/components/MoodColorsLine';
|
|
10
|
-
import { MoodJumpGradientMode, MoodLampInfo, MoodUIInfo } from './Interface';
|
|
11
|
-
import I18n from '@ledvance/base/src/i18n';
|
|
12
|
-
import res from '@ledvance/base/src/res';
|
|
13
|
-
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
14
|
-
|
|
15
|
-
const cx = Utils.RatioUtils.convertX;
|
|
16
|
-
const { withTheme } = Utils.ThemeUtils
|
|
17
|
-
|
|
18
|
-
interface LightCategory {
|
|
19
|
-
isMixLight?: boolean
|
|
20
|
-
isStripLight?: boolean
|
|
21
|
-
isStringLight?: boolean
|
|
22
|
-
isCeilingLight?: boolean
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface MoodItemProps extends ViewProps {
|
|
26
|
-
theme?: ThemeType
|
|
27
|
-
enable: boolean;
|
|
28
|
-
isMix: boolean;
|
|
29
|
-
mood: MoodUIInfo;
|
|
30
|
-
style?: ViewStyle;
|
|
31
|
-
deviceTypeOption?: LightCategory
|
|
32
|
-
onPress?: () => void;
|
|
33
|
-
onSwitch: (enable: boolean) => void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const MoodItem = (props: MoodItemProps) => {
|
|
37
|
-
const { mood, isMix, deviceTypeOption } = props;
|
|
38
|
-
const isDynamic = useMemo(() => {
|
|
39
|
-
return mood.mainLamp.nodes?.length > 1 || mood.secondaryLamp.nodes?.length > 1;
|
|
40
|
-
}, [mood.mainLamp.nodes, mood.secondaryLamp.nodes]);
|
|
41
|
-
|
|
42
|
-
const gradientMode = useMemo(() => (
|
|
43
|
-
deviceTypeOption?.isStringLight ? MoodJumpGradientMode.StringGradient : deviceTypeOption?.isStripLight ? MoodJumpGradientMode.StripGradient : MoodJumpGradientMode.SourceGradient
|
|
44
|
-
), [MoodJumpGradientMode, deviceTypeOption])
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const styles = StyleSheet.create({
|
|
48
|
-
card: {
|
|
49
|
-
marginHorizontal: cx(24),
|
|
50
|
-
},
|
|
51
|
-
headline: {
|
|
52
|
-
flexDirection: 'row',
|
|
53
|
-
marginHorizontal: cx(16),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
)}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
/>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { StyleSheet, Text, View, ViewProps, ViewStyle, Image, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { Utils } from 'tuya-panel-kit';
|
|
4
|
+
import { hsv2Hex } from '@ledvance/base/src/utils';
|
|
5
|
+
import { cctToColor } from '@ledvance/base/src/utils/cctUtils';
|
|
6
|
+
import { mapFloatToRange } from '@ledvance/base/src/utils';
|
|
7
|
+
import Card from '@ledvance/base/src/components/Card';
|
|
8
|
+
import Spacer from '@ledvance/base/src/components/Spacer';
|
|
9
|
+
import MoodColorsLine from '@ledvance/base/src/components/MoodColorsLine';
|
|
10
|
+
import { MoodJumpGradientMode, MoodLampInfo, MoodUIInfo } from './Interface';
|
|
11
|
+
import I18n from '@ledvance/base/src/i18n';
|
|
12
|
+
import res from '@ledvance/base/src/res';
|
|
13
|
+
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
14
|
+
|
|
15
|
+
const cx = Utils.RatioUtils.convertX;
|
|
16
|
+
const { withTheme } = Utils.ThemeUtils
|
|
17
|
+
|
|
18
|
+
interface LightCategory {
|
|
19
|
+
isMixLight?: boolean
|
|
20
|
+
isStripLight?: boolean
|
|
21
|
+
isStringLight?: boolean
|
|
22
|
+
isCeilingLight?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface MoodItemProps extends ViewProps {
|
|
26
|
+
theme?: ThemeType
|
|
27
|
+
enable: boolean;
|
|
28
|
+
isMix: boolean;
|
|
29
|
+
mood: MoodUIInfo;
|
|
30
|
+
style?: ViewStyle;
|
|
31
|
+
deviceTypeOption?: LightCategory
|
|
32
|
+
onPress?: () => void;
|
|
33
|
+
onSwitch: (enable: boolean) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const MoodItem = (props: MoodItemProps) => {
|
|
37
|
+
const { mood, isMix, deviceTypeOption } = props;
|
|
38
|
+
const isDynamic = useMemo(() => {
|
|
39
|
+
return mood.mainLamp.nodes?.length > 1 || mood.secondaryLamp.nodes?.length > 1;
|
|
40
|
+
}, [mood.mainLamp.nodes, mood.secondaryLamp.nodes]);
|
|
41
|
+
|
|
42
|
+
const gradientMode = useMemo(() => (
|
|
43
|
+
deviceTypeOption?.isStringLight ? MoodJumpGradientMode.StringGradient : deviceTypeOption?.isStripLight ? MoodJumpGradientMode.StripGradient : MoodJumpGradientMode.SourceGradient
|
|
44
|
+
), [MoodJumpGradientMode, deviceTypeOption])
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
const styles = StyleSheet.create({
|
|
48
|
+
card: {
|
|
49
|
+
marginHorizontal: cx(24),
|
|
50
|
+
},
|
|
51
|
+
headline: {
|
|
52
|
+
flexDirection: 'row',
|
|
53
|
+
marginHorizontal: cx(16),
|
|
54
|
+
alignItems: 'center',
|
|
55
|
+
},
|
|
56
|
+
headText: {
|
|
57
|
+
flex: 1,
|
|
58
|
+
color: props.theme?.global.fontColor,
|
|
59
|
+
fontSize: cx(16),
|
|
60
|
+
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
61
|
+
lineHeight: cx(20),
|
|
62
|
+
},
|
|
63
|
+
checkbox: {
|
|
64
|
+
width: cx(45),
|
|
65
|
+
height: cx(45),
|
|
66
|
+
marginTop: cx(-5),
|
|
67
|
+
marginBottom: cx(-10),
|
|
68
|
+
fontWeight: 'bold',
|
|
69
|
+
},
|
|
70
|
+
moodTypeItem: {
|
|
71
|
+
flexDirection: 'row',
|
|
72
|
+
},
|
|
73
|
+
moodTypeLabel: {
|
|
74
|
+
marginStart: cx(16),
|
|
75
|
+
paddingHorizontal: cx(12.5),
|
|
76
|
+
backgroundColor: props.theme?.tag.background,
|
|
77
|
+
borderRadius: cx(8),
|
|
78
|
+
},
|
|
79
|
+
moodTypeLabelText: {
|
|
80
|
+
height: cx(16),
|
|
81
|
+
color: props.theme?.tag.fontColor,
|
|
82
|
+
fontSize: cx(10),
|
|
83
|
+
textAlignVertical: 'center',
|
|
84
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
85
|
+
lineHeight: cx(16),
|
|
86
|
+
},
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Card style={[styles.card, props.style]} onPress={props.onPress}>
|
|
91
|
+
<View>
|
|
92
|
+
<Spacer height={cx(16)} />
|
|
93
|
+
<View style={styles.headline}>
|
|
94
|
+
<Text style={styles.headText}>{mood.name}</Text>
|
|
95
|
+
<TouchableOpacity style={styles.checkbox} onPress={() => props.onSwitch(!props.enable)}>
|
|
96
|
+
<Image source={{ uri: res.ic_check}} width={cx(44)} height={cx(44)} style={[styles.checkbox, { tintColor: props.enable ? props.theme?.icon.primary : props.theme?.icon.disable}]} />
|
|
97
|
+
</TouchableOpacity>
|
|
98
|
+
</View>
|
|
99
|
+
<Spacer />
|
|
100
|
+
<MixMoodColorsLine mixSubLight={mood.mainLamp} isMix={isMix} type={(mood.mainLamp.mode === gradientMode && !deviceTypeOption?.isCeilingLight) ? 'gradient' : 'separate'}/>
|
|
101
|
+
{(deviceTypeOption?.isMixLight || (isMix && !!mood.secondaryLamp.nodes.length)) && (
|
|
102
|
+
<>
|
|
103
|
+
<Spacer height={cx(7)} />
|
|
104
|
+
<MixMoodColorsLine mixSubLight={mood.secondaryLamp} isMix={isMix} type={mood.secondaryLamp.mode === (deviceTypeOption?.isMixLight ? MoodJumpGradientMode.SourceGradient : MoodJumpGradientMode.StripGradient) ? 'gradient' : 'separate'}/>
|
|
105
|
+
</>
|
|
106
|
+
)}
|
|
107
|
+
<Spacer height={cx(12)} />
|
|
108
|
+
<View style={styles.moodTypeItem}>
|
|
109
|
+
<View style={styles.moodTypeLabel}>
|
|
110
|
+
<Text style={styles.moodTypeLabelText}>
|
|
111
|
+
{I18n.getLang(
|
|
112
|
+
isDynamic ? 'mood_overview_field_chip_2' : 'mood_overview_field_chip_text'
|
|
113
|
+
)}
|
|
114
|
+
</Text>
|
|
115
|
+
</View>
|
|
116
|
+
</View>
|
|
117
|
+
<Spacer height={cx(16)} />
|
|
118
|
+
</View>
|
|
119
|
+
</Card>
|
|
120
|
+
);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export default withTheme(MoodItem)
|
|
124
|
+
|
|
125
|
+
export function MixMoodColorsLine(props: { mixSubLight: MoodLampInfo; isMix: boolean, type: 'gradient' | 'separate' }) {
|
|
126
|
+
const { mixSubLight, isMix } = props;
|
|
127
|
+
const lightColors = !!(mixSubLight.enable && mixSubLight.nodes.length) ? mixSubLight.nodes?.map(n => {
|
|
128
|
+
const s = Math.round(mapFloatToRange(n.s / 100, 30, 100));
|
|
129
|
+
return n.isColorNode
|
|
130
|
+
? hsv2Hex(n.h, s, Math.round(mapFloatToRange(n.v / 100, 50, 100)))
|
|
131
|
+
: cctToColor(n.colorTemp.toFixed());
|
|
132
|
+
}) : ['#eee'];
|
|
133
|
+
|
|
134
|
+
const styles = StyleSheet.create({
|
|
135
|
+
gradientItem: {
|
|
136
|
+
flexDirection: 'row',
|
|
137
|
+
},
|
|
138
|
+
gradientItemIconView: {
|
|
139
|
+
width: cx(24),
|
|
140
|
+
height: cx(24),
|
|
141
|
+
justifyContent: 'center',
|
|
142
|
+
alignItems: 'center',
|
|
143
|
+
backgroundColor: '#aaa',
|
|
144
|
+
borderRadius: cx(8),
|
|
145
|
+
},
|
|
146
|
+
gradientItemIcon: {
|
|
147
|
+
width: cx(16),
|
|
148
|
+
height: cx(16),
|
|
149
|
+
tintColor: '#fff',
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<View style={styles.gradientItem}>
|
|
155
|
+
<Spacer height={0} width={cx(16)} />
|
|
156
|
+
<MoodColorsLine
|
|
157
|
+
nodeStyle={{ borderColor: '#ccc', borderWidth: 1 }}
|
|
158
|
+
width={isMix ? cx(264) : undefined}
|
|
159
|
+
type={props.type}
|
|
160
|
+
colors={lightColors}
|
|
161
|
+
/>
|
|
162
|
+
{isMix && (
|
|
163
|
+
<>
|
|
164
|
+
<Spacer height={0} width={cx(7)} />
|
|
165
|
+
<View style={styles.gradientItemIconView}>
|
|
166
|
+
<Image style={styles.gradientItemIcon} source={{uri: mixSubLight.enable ? res.light_on : res.light_off}} />
|
|
167
|
+
</View>
|
|
168
|
+
</>
|
|
169
|
+
)}
|
|
170
|
+
</View>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
@@ -18,7 +18,7 @@ import { getEndTime, getStartTime, sleepNode2Dp, useSleepMode, useWakeUp, wakeUp
|
|
|
18
18
|
import { SleepUIItem, WakeUpUIItem } from "./Interface";
|
|
19
19
|
import Card from "@ledvance/base/src/components/Card";
|
|
20
20
|
import { useParams } from "@ledvance/base/src/hooks/Hooks";
|
|
21
|
-
import { ApplyForItem } from "
|
|
21
|
+
import { ApplyForItem } from "@ledvance/base/src/utils/interface";
|
|
22
22
|
import InfoText from "@ledvance/base/src/components/InfoText";
|
|
23
23
|
import ThemeType from '@ledvance/base/src/config/themeType'
|
|
24
24
|
import { useConflictTask } from "hooks/DeviceDpStateHooks";
|
|
@@ -171,7 +171,7 @@ const SwitchInching = (props: { theme?: ThemeType }) => {
|
|
|
171
171
|
const newSwitchInchingItem = {
|
|
172
172
|
...state.switchInchingItem,
|
|
173
173
|
enable: v,
|
|
174
|
-
time
|
|
174
|
+
time: time < 2 ? 2 : time
|
|
175
175
|
}
|
|
176
176
|
if (v) {
|
|
177
177
|
const switchingTask = {
|
|
@@ -228,6 +228,7 @@ const SwitchInching = (props: { theme?: ThemeType }) => {
|
|
|
228
228
|
]}
|
|
229
229
|
setHour={m => updateTime(m, undefined)}
|
|
230
230
|
setMinute={s => updateTime(undefined, s)}
|
|
231
|
+
minMinute={timeRef.current.minute === '00' ? 2 : 0}
|
|
231
232
|
maxHour={61}
|
|
232
233
|
/>
|
|
233
234
|
</View>
|
|
@@ -3,6 +3,7 @@ import { Timer, TimerActions } from './Interface';
|
|
|
3
3
|
import { parseJSON } from '@tuya/tuya-panel-lamp-sdk/lib/utils';
|
|
4
4
|
import { ColorList } from '@ledvance/base/src/components/StripAdjustView';
|
|
5
5
|
import {AdjustType} from "@ledvance/base/src/utils/interface";
|
|
6
|
+
import { TimeScheduleDetailPageParams } from './TimeScheduleDetailPage'
|
|
6
7
|
|
|
7
8
|
export const defDeviceData = {
|
|
8
9
|
h: 0,
|
|
@@ -38,8 +39,10 @@ export const defMoodStripDeviceData = {
|
|
|
38
39
|
adjustType: AdjustType.COLOUR
|
|
39
40
|
};
|
|
40
41
|
|
|
41
|
-
export const defShutterDeviceData = {
|
|
42
|
-
|
|
42
|
+
export const defShutterDeviceData = (props: TimeScheduleDetailPageParams) => {
|
|
43
|
+
return {
|
|
44
|
+
percentControl: (props.suggestValue !== undefined && !props.suggestValue) ? 0 : 100
|
|
45
|
+
}
|
|
43
46
|
};
|
|
44
47
|
|
|
45
48
|
export const defOsramFanLightDeviceData = {
|
|
@@ -240,7 +240,7 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
|
|
|
240
240
|
|
|
241
241
|
const renderSkillGroup = (skills: ApplyForItem[], i18nString: string) => {
|
|
242
242
|
if (!skills.length) return null;
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
return (
|
|
245
245
|
<>
|
|
246
246
|
<Text style={{ fontSize: cx(14), color: props.theme?.global.fontColor }}>
|
|
@@ -711,7 +711,7 @@ const getDefaultManual = (props: TimeScheduleDetailPageParams): ComponentConfig
|
|
|
711
711
|
[DeviceType.MixLight]: defMixDeviceData,
|
|
712
712
|
[DeviceType.FanLight]: defFanLightDeviceData,
|
|
713
713
|
[DeviceType.MoodStrip]: defMoodStripDeviceData,
|
|
714
|
-
[DeviceType.Shutter]: defShutterDeviceData,
|
|
714
|
+
[DeviceType.Shutter]: defShutterDeviceData(props),
|
|
715
715
|
[DeviceType.OsramFanLight]: defOsramFanLightDeviceData,
|
|
716
716
|
[DeviceType.PowerStrip]: defDeviceData,
|
|
717
717
|
[DeviceType.LightSource]: defDeviceData,
|