@ledvance/ui-biz-bundle 1.0.2 → 1.0.4
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/.babelrc +31 -31
- package/.eslintignore +5 -5
- package/.eslintrc.js +27 -27
- package/.prettierrc.js +1 -1
- package/.versionrc +5 -5
- package/package.json +72 -72
- package/rn-cli.config.js +8 -8
- package/src/modules/history/HistoryPage.d.ts +2 -2
- package/src/modules/history/HistoryPage.tsx +254 -254
- package/src/modules/history/SwitchHistoryPageActions.d.ts +13 -13
- package/src/modules/history/SwitchHistoryPageActions.ts +53 -53
- package/src/modules/hooks/DeviceDpStateHooks.ts +27 -0
- package/src/modules/mood/MixLightActions.ts +82 -0
- package/src/modules/mood/MixLightSceneActions.ts +259 -0
- package/src/modules/mood/MixMoodItem.tsx +138 -0
- package/src/modules/mood/MixScene.tsx +131 -0
- package/src/modules/mood/MixSceneBeans.ts +62 -0
- package/src/modules/mood/MoodAction.ts +222 -0
- package/src/modules/mood/MoodItem.tsx +113 -0
- package/src/modules/mood/SceneInfo.ts +319 -0
- package/src/modules/timeSchedule/DeviceState.tsx +54 -0
- package/src/modules/timeSchedule/LdvScheduleItem.tsx +125 -0
- package/src/modules/timeSchedule/ManualSetting.tsx +69 -0
- package/src/modules/timeSchedule/MoodSetting.tsx +66 -0
- package/src/modules/timeSchedule/ScheduleScene.tsx +138 -0
- package/src/modules/timeSchedule/SingleLightView.tsx +254 -0
- package/src/modules/timeSchedule/TimeScheduleEditpage.tsx +480 -0
- package/src/modules/timeSchedule/TimeSchedulePage.tsx +323 -0
- package/src/modules/timeSchedule/mix/MixLightBean.ts +10 -0
- package/src/modules/timeSchedule/mix/MixLightView.tsx +221 -0
- package/src/modules/timeSchedule/utils.ts +7 -0
- package/src/modules/timer/TimerPage.tsx +409 -406
- package/src/modules/timer/{timerPageAction.ts → TimerPageAction.ts} +91 -91
- package/tsconfig.json +50 -50
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NativeApi } from "@ledvance/base/src/api/native"
|
|
2
|
+
export const WHITE = 'white'
|
|
3
|
+
export const COLOUR = 'colour'
|
|
4
|
+
export const SCENE = 'scene'
|
|
5
|
+
export const MUSIC = 'music'
|
|
6
|
+
|
|
7
|
+
export const setBiorhythmDp = (deviceId: string, value: string, dpCodes: Record<string, string>) => {
|
|
8
|
+
return NativeApi.setDp(deviceId, dpCodes.rhythm_mode, value)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const setMixRgbcwDp = (deviceId: string, value: string, enable: boolean | undefined, dpCodes: Record<string, string>) => {
|
|
12
|
+
const dps: { [p: string]: any } = {
|
|
13
|
+
[dpCodes.mix_rgbcw]: value,
|
|
14
|
+
}
|
|
15
|
+
if (enable != undefined) {
|
|
16
|
+
dps[dpCodes.switch_led] = enable
|
|
17
|
+
}
|
|
18
|
+
return NativeApi.setDps(deviceId, dps)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const setSceneDp = (deviceId: string, value: string, dpCodes: Record<string, string>) => {
|
|
22
|
+
return NativeApi.setDps(deviceId, { [dpCodes.switch_led]: true, [dpCodes.work_mode]: 'scene', [dpCodes.scene_data]: value })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const setMixSceneDp = (deviceId: string, value: string, dpCodes: Record<string, string>) => {
|
|
26
|
+
return NativeApi.setDps(deviceId, { [dpCodes.work_mode]: 'scene', [dpCodes.mix_light_scene]: value })
|
|
27
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { MixLightBean } from '../timeSchedulecopy/mix/MixLightBean'
|
|
2
|
+
import { spliceByStep } from '@ledvance/base/src/utils/common';
|
|
3
|
+
import { asyncSetDps, useDp } from '@ledvance/base/src/models/modules/NativePropsSlice';
|
|
4
|
+
import { Dispatch, useState } from 'react'
|
|
5
|
+
import { useDispatch } from 'react-redux'
|
|
6
|
+
import { useUpdateEffect } from 'ahooks'
|
|
7
|
+
import { setMixRgbcwDp } from '../hooks/DeviceDpStateHooks'
|
|
8
|
+
import { Result } from '@ledvance/base/src/models/modules/Result'
|
|
9
|
+
|
|
10
|
+
export function useMixRgbcw(dpCodes: Record<string,string>): [MixLightBean, SetMixLightResultType] {
|
|
11
|
+
const [dp]:any = useDp(dpCodes.mix_rgbcw)
|
|
12
|
+
const setMixLightFn = setMixLight(useDispatch())
|
|
13
|
+
const [mixLightState, setMixLightState] = useState(dp2Obj(dp))
|
|
14
|
+
useUpdateEffect(() => {
|
|
15
|
+
const newMixLightState = dp2Obj(dp)
|
|
16
|
+
setMixLightState(newMixLightState)
|
|
17
|
+
console.log('长链接MIX', newMixLightState)
|
|
18
|
+
}, [dp])
|
|
19
|
+
return [mixLightState, setMixLightFn]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type SetMixLightResultType = (deviceId: string, mixLightBean: MixLightBean, dpCodes: Record<string,string>) => Promise<Result<any>>
|
|
23
|
+
|
|
24
|
+
function setMixLight(dispatch: Dispatch<any>): SetMixLightResultType {
|
|
25
|
+
return (deviceId: string, mixLightBean: MixLightBean, dpCodes) => asyncSetDps(dispatch, async () => {
|
|
26
|
+
const dpValue = obj2Dp(mixLightBean)
|
|
27
|
+
const enable = mixLightBean.whiteLightSwitch === mixLightBean.colorLightSwitch ? mixLightBean.whiteLightSwitch : undefined
|
|
28
|
+
const controlResult: any = await setMixRgbcwDp(deviceId, dpValue, enable, dpCodes)
|
|
29
|
+
return {
|
|
30
|
+
result: { success: controlResult.result },
|
|
31
|
+
dps: { [dpCodes.mix_rgbcw]: dpValue },
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function obj2Dp(obj: MixLightBean): string {
|
|
37
|
+
const powerSwitchDpValueArray = ['0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0']
|
|
38
|
+
if (obj.whiteLightSwitch) {
|
|
39
|
+
powerSwitchDpValueArray[15] = '1'
|
|
40
|
+
}
|
|
41
|
+
if (obj.colorLightSwitch) {
|
|
42
|
+
powerSwitchDpValueArray[14] = '1'
|
|
43
|
+
}
|
|
44
|
+
if (obj.mixRgbcwEnabled) {
|
|
45
|
+
powerSwitchDpValueArray[13] = '1'
|
|
46
|
+
}
|
|
47
|
+
const powerSwitchDpValueBinary = powerSwitchDpValueArray.join('')
|
|
48
|
+
const powerSwitchDpValue = parseInt(powerSwitchDpValueBinary, 2).toString(16).padStart(4, '0')
|
|
49
|
+
const hueDpValue = obj.hue.toString(16).padStart(4, '0')
|
|
50
|
+
const satDpValue = (obj.sat * 10).toString(16).padStart(4, '0')
|
|
51
|
+
const lightnessDpValue = (obj.lightness * 10).toString(16).padStart(4, '0')
|
|
52
|
+
const brightnessDpValue = (obj.brightness * 10).toString(16).padStart(4, '0')
|
|
53
|
+
const colorTempDpValue = (obj.colorTempPercent * 10).toString(16).padStart(4, '0')
|
|
54
|
+
return powerSwitchDpValue + hueDpValue + satDpValue + lightnessDpValue + brightnessDpValue + colorTempDpValue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function dp2Obj(dp: string): MixLightBean {
|
|
58
|
+
if (!dp) {
|
|
59
|
+
return {
|
|
60
|
+
whiteLightSwitch: true,
|
|
61
|
+
colorLightSwitch: true,
|
|
62
|
+
mixRgbcwEnabled: true,
|
|
63
|
+
hue: 360,
|
|
64
|
+
sat: 100,
|
|
65
|
+
lightness: 100,
|
|
66
|
+
brightness: 100,
|
|
67
|
+
colorTempPercent: 100,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const dpValueArray = spliceByStep(dp, 4)
|
|
71
|
+
const powerSwitch = parseInt(dpValueArray[0], 16).toString(2).padStart(16, '0')
|
|
72
|
+
return {
|
|
73
|
+
whiteLightSwitch: powerSwitch[15] === '1',
|
|
74
|
+
colorLightSwitch: powerSwitch[14] === '1',
|
|
75
|
+
mixRgbcwEnabled: powerSwitch[13] === '1',
|
|
76
|
+
hue: parseInt(dpValueArray[1], 16), // 色相 0-360
|
|
77
|
+
sat: parseInt(dpValueArray[2], 16) / 10, // 饱和度 0-100
|
|
78
|
+
lightness: parseInt(dpValueArray[3], 16) / 10, // 明度 0-100
|
|
79
|
+
brightness: parseInt(dpValueArray[4], 16) / 10, // 亮度 0-100
|
|
80
|
+
colorTempPercent: parseInt(dpValueArray[5], 16) / 10, // 色温 0-100
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { getFeature, putFeature } from '@ledvance/base/src/api/native';
|
|
2
|
+
import { setMixSceneDp } from '../hooks/DeviceDpStateHooks'
|
|
3
|
+
import {
|
|
4
|
+
MixMood,
|
|
5
|
+
MixSceneInfo,
|
|
6
|
+
MixSceneLampInfo,
|
|
7
|
+
MixSceneNodeInfo,
|
|
8
|
+
RemoteMixScene,
|
|
9
|
+
} from './MixSceneBeans'
|
|
10
|
+
import I18n from '@ledvance/base/src/i18n'
|
|
11
|
+
import res from '@ledvance/base/src/res';
|
|
12
|
+
import { NativeResult, Result } from '@ledvance/base/src/models/modules/Result';
|
|
13
|
+
import { asyncSetDps, useDp } from '@ledvance/base/src/models/modules/NativePropsSlice';
|
|
14
|
+
import { Dispatch, useState } from 'react'
|
|
15
|
+
import { useUpdateEffect } from 'ahooks'
|
|
16
|
+
import { useDispatch } from 'react-redux'
|
|
17
|
+
import { SceneNodeTransitionMode } from './SceneInfo'
|
|
18
|
+
|
|
19
|
+
const MixLightSceneListFeatureId = 'MixLightSceneList'
|
|
20
|
+
|
|
21
|
+
export function useMixScene(dpCodes: Record<string, string>): [number | undefined, SetMixSceneType] {
|
|
22
|
+
const [dp]:any = useDp(dpCodes.mix_light_scene)
|
|
23
|
+
const [mixSceneState, setMixSceneState] = useState<MixSceneInfo | undefined>(dp2Obj(dp))
|
|
24
|
+
useUpdateEffect(() => {
|
|
25
|
+
setMixSceneState(dp2Obj(dp))
|
|
26
|
+
}, [dp])
|
|
27
|
+
return [mixSceneState?.id, setMixScene(useDispatch())]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type SetMixSceneType = (deviceId: string, mixScene: MixSceneInfo, dpCodes: Record<string, string>) => Promise<Result<any>>
|
|
31
|
+
|
|
32
|
+
function setMixScene(dispatch: Dispatch<any>): SetMixSceneType {
|
|
33
|
+
return (deviceId: string, mixScene: MixSceneInfo, dpCodes) => {
|
|
34
|
+
return asyncSetDps(dispatch, async () => {
|
|
35
|
+
const dpValue = obj2Dp(mixScene)
|
|
36
|
+
const controlResult: any = await setMixSceneDp(deviceId, dpValue, dpCodes)
|
|
37
|
+
return {
|
|
38
|
+
result: { success: controlResult.result },
|
|
39
|
+
dps: { [dpCodes.work_mode]: 'scene', [dpCodes.mix_light_scene]: dpValue },
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function getMixLightSceneList(deviceId: string): Promise<Result<MixMood[]>> {
|
|
46
|
+
const res: NativeResult<MixMood[]> = await getFeature(deviceId, MixLightSceneListFeatureId)
|
|
47
|
+
if (!(!!res.data)) {
|
|
48
|
+
const setDefRes = await putFeature(deviceId, MixLightSceneListFeatureId, getDefMixLightSceneList())
|
|
49
|
+
if (setDefRes.result) {
|
|
50
|
+
return getMixLightSceneList(deviceId)
|
|
51
|
+
}
|
|
52
|
+
return { success: false }
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
data: res.data.map(scene => {
|
|
57
|
+
return {
|
|
58
|
+
...scene,
|
|
59
|
+
...dp2Obj(scene.value),
|
|
60
|
+
}
|
|
61
|
+
}),
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function saveMixScene(
|
|
66
|
+
deviceId: string,
|
|
67
|
+
isDelete: boolean,
|
|
68
|
+
name: string,
|
|
69
|
+
mixSceneObj: MixSceneInfo,
|
|
70
|
+
sceneList: MixMood[],
|
|
71
|
+
): Promise<Result<any>> {
|
|
72
|
+
if (!isDelete) {
|
|
73
|
+
mixSceneObj.lamps.forEach(lamp => {
|
|
74
|
+
if (lamp.enable) {
|
|
75
|
+
if (lamp.nodes[0].changeType === SceneNodeTransitionMode.Static) {
|
|
76
|
+
lamp.nodes = [lamp.nodes[0]]
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
lamp.nodes = []
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
const newSceneList: RemoteMixScene[] = isDelete ? sceneList : sceneList.map(scene => {
|
|
84
|
+
return {
|
|
85
|
+
name: scene.id === mixSceneObj.id ? name : scene.name,
|
|
86
|
+
image: scene.image,
|
|
87
|
+
value: scene.id === mixSceneObj.id ? obj2Dp(mixSceneObj) : scene.value,
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
return setMixLightSceneList(deviceId, newSceneList)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function setMixLightSceneList(deviceId: string, sceneList: RemoteMixScene[]): Promise<Result<any>> {
|
|
94
|
+
const res = await putFeature(deviceId, MixLightSceneListFeatureId, sceneList)
|
|
95
|
+
return {
|
|
96
|
+
success: res.result,
|
|
97
|
+
msg: res.msg,
|
|
98
|
+
data: res.data,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 混光场景命令对象转换为dp数据
|
|
104
|
+
* @param obj
|
|
105
|
+
*/
|
|
106
|
+
export function obj2Dp(obj: MixSceneInfo) {
|
|
107
|
+
const versionHex = obj.version.toString(16).padStart(2, '0')
|
|
108
|
+
const sceneNoHex = obj.id.toString(16).padStart(2, '0')
|
|
109
|
+
const lampsHex = obj.lamps.map(lamp => {
|
|
110
|
+
let lampHex = lamp.enable ? '01' : '00'
|
|
111
|
+
const nodes = lamp.nodes || []
|
|
112
|
+
lampHex += nodes.length.toString(16).padStart(2, '0')
|
|
113
|
+
if (nodes.length === 0 || !lamp.enable) {
|
|
114
|
+
return lampHex
|
|
115
|
+
}
|
|
116
|
+
lampHex += lamp.type.toString(16).padStart(2, '0')
|
|
117
|
+
lampHex += nodes.map(node => {
|
|
118
|
+
let nodeHex = ''
|
|
119
|
+
nodeHex += node.intervalTime.toString(16).padStart(2, '0')
|
|
120
|
+
nodeHex += node.changeTime.toString(16).padStart(2, '0')
|
|
121
|
+
nodeHex += node.changeType.toString(16).padStart(2, '0')
|
|
122
|
+
switch (lamp.type) { // 1:W 只有亮度,2:CW 亮度+色温,3:RGB HSV,4:RGBC HSV+色温,5:RGBCW HSV+色温+亮度
|
|
123
|
+
case 1:
|
|
124
|
+
nodeHex += (node.brightness * 10).toString(16).padStart(4, '0')
|
|
125
|
+
break
|
|
126
|
+
case 2:
|
|
127
|
+
nodeHex += (node.brightness * 10).toString(16).padStart(4, '0')
|
|
128
|
+
nodeHex += (node.colorTemp * 10).toString(16).padStart(4, '0')
|
|
129
|
+
break
|
|
130
|
+
case 3:
|
|
131
|
+
nodeHex += node.hue.toString(16).padStart(4, '0')
|
|
132
|
+
nodeHex += (node.sat * 10).toString(16).padStart(4, '0')
|
|
133
|
+
nodeHex += (node.lightness * 10).toString(16).padStart(4, '0')
|
|
134
|
+
break
|
|
135
|
+
case 4:
|
|
136
|
+
nodeHex += node.hue.toString(16).padStart(4, '0')
|
|
137
|
+
nodeHex += (node.sat * 10).toString(16).padStart(4, '0')
|
|
138
|
+
nodeHex += (node.lightness * 10).toString(16).padStart(4, '0')
|
|
139
|
+
nodeHex += (node.colorTemp * 10).toString(16).padStart(4, '0')
|
|
140
|
+
break
|
|
141
|
+
case 5:
|
|
142
|
+
nodeHex += node.hue.toString(16).padStart(4, '0')
|
|
143
|
+
nodeHex += (node.sat * 10).toString(16).padStart(4, '0')
|
|
144
|
+
nodeHex += (node.lightness * 10).toString(16).padStart(4, '0')
|
|
145
|
+
nodeHex += (node.brightness * 10).toString(16).padStart(4, '0')
|
|
146
|
+
nodeHex += (node.colorTemp * 10).toString(16).padStart(4, '0')
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
return nodeHex
|
|
150
|
+
}).join('')
|
|
151
|
+
return lampHex
|
|
152
|
+
}).join('')
|
|
153
|
+
return versionHex + sceneNoHex + lampsHex
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* dp数据转换为混光场景对象
|
|
158
|
+
* @returns MixSceneInfo
|
|
159
|
+
*/
|
|
160
|
+
export function dp2Obj(dp: string): MixSceneInfo | undefined {
|
|
161
|
+
if (!(!!dp)) {
|
|
162
|
+
return undefined
|
|
163
|
+
}
|
|
164
|
+
const result = {} as MixSceneInfo
|
|
165
|
+
result.version = parseInt(dp.slice(0, 2), 16)
|
|
166
|
+
result.id = parseInt(dp.slice(2, 4), 16)
|
|
167
|
+
result.lamps = []
|
|
168
|
+
let lampsHex = dp.slice(4)
|
|
169
|
+
while (lampsHex.length != 0) {
|
|
170
|
+
const lamp = { nodes: [] as MixSceneNodeInfo[] } as MixSceneLampInfo
|
|
171
|
+
lamp.enable = parseInt(lampsHex.slice(0, 2), 16) === 1
|
|
172
|
+
lampsHex = lampsHex.slice(2)
|
|
173
|
+
const nodeCount = parseInt(lampsHex.slice(0, 2), 16)
|
|
174
|
+
lampsHex = lampsHex.slice(2)
|
|
175
|
+
if (nodeCount === 0) {
|
|
176
|
+
result.lamps.push(lamp)
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
lamp.type = parseInt(lampsHex.slice(0, 2), 16)
|
|
180
|
+
lampsHex = lampsHex.slice(2)
|
|
181
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
182
|
+
const node = {} as MixSceneNodeInfo
|
|
183
|
+
node.intervalTime = parseInt(lampsHex.slice(0, 2), 16)
|
|
184
|
+
node.changeTime = parseInt(lampsHex.slice(2, 4), 16)
|
|
185
|
+
node.changeType = parseInt(lampsHex.slice(4, 6), 16)
|
|
186
|
+
lampsHex = lampsHex.slice(6)
|
|
187
|
+
switch (lamp.type) {
|
|
188
|
+
case 1:
|
|
189
|
+
node.brightness = parseInt(lampsHex.slice(0, 4), 16) / 10
|
|
190
|
+
lampsHex = lampsHex.slice(4)
|
|
191
|
+
break
|
|
192
|
+
case 2:
|
|
193
|
+
node.brightness = parseInt(lampsHex.slice(0, 4), 16) / 10
|
|
194
|
+
node.colorTemp = parseInt(lampsHex.slice(4, 8), 16) / 10
|
|
195
|
+
lampsHex = lampsHex.slice(8)
|
|
196
|
+
break
|
|
197
|
+
case 3:
|
|
198
|
+
node.hue = parseInt(lampsHex.slice(0, 4), 16)
|
|
199
|
+
node.sat = parseInt(lampsHex.slice(4, 8), 16) / 10
|
|
200
|
+
node.lightness = parseInt(lampsHex.slice(8, 12), 16) / 10
|
|
201
|
+
lampsHex = lampsHex.slice(12)
|
|
202
|
+
break
|
|
203
|
+
case 4:
|
|
204
|
+
node.hue = parseInt(lampsHex.slice(0, 4), 16)
|
|
205
|
+
node.sat = parseInt(lampsHex.slice(4, 8), 16) / 10
|
|
206
|
+
node.lightness = parseInt(lampsHex.slice(8, 12), 16) / 10
|
|
207
|
+
node.colorTemp = parseInt(lampsHex.slice(12, 16), 16) / 10
|
|
208
|
+
lampsHex = lampsHex.slice(16)
|
|
209
|
+
break
|
|
210
|
+
case 5:
|
|
211
|
+
node.hue = parseInt(lampsHex.slice(0, 4), 16)
|
|
212
|
+
node.sat = parseInt(lampsHex.slice(4, 8), 16) / 10
|
|
213
|
+
node.lightness = parseInt(lampsHex.slice(8, 12), 16) / 10
|
|
214
|
+
node.brightness = parseInt(lampsHex.slice(12, 16), 16) / 10
|
|
215
|
+
node.colorTemp = parseInt(lampsHex.slice(16, 20), 16) / 10
|
|
216
|
+
lampsHex = lampsHex.slice(20)
|
|
217
|
+
break
|
|
218
|
+
}
|
|
219
|
+
lamp.nodes.push(node)
|
|
220
|
+
}
|
|
221
|
+
result.lamps.push(lamp)
|
|
222
|
+
}
|
|
223
|
+
return result
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function getDefMixLightSceneList(): RemoteMixScene[] {
|
|
227
|
+
return [
|
|
228
|
+
{
|
|
229
|
+
name: I18n.getLang('mesh_device_detail_lighting_goodnight'),
|
|
230
|
+
image: res.scene_goodnight,
|
|
231
|
+
value: '00000101020e0d0000c800000000',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: I18n.getLang('mesh_device_detail_lighting_read'),
|
|
235
|
+
image: res.scene_reading,
|
|
236
|
+
value: '00010101020e0d0003e801f40000',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: I18n.getLang('mesh_device_detail_lighting_work'),
|
|
240
|
+
image: res.scene_work,
|
|
241
|
+
value: '00020101020e0d0003e803e80000',
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: I18n.getLang('mesh_device_detail_lighting_leisure'),
|
|
245
|
+
image: res.scene_leisure,
|
|
246
|
+
value: '00030101020e0d0001f401f40000',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: I18n.getLang('mesh_device_detail_lighting_color_mode'),
|
|
250
|
+
image: res.scene_custom1,
|
|
251
|
+
value: '00040000010603464601000003e803e8464601007803e803e846460100f003e803e8464601003d03e803e846460100ae03e803e8464601011303e803e8',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
name: I18n.getLang('mesh_device_detail_lighting_white_mode'),
|
|
255
|
+
image: res.scene_custom2,
|
|
256
|
+
value: '000501030246460103e8000a46460103e8015446460103e803e80000',
|
|
257
|
+
},
|
|
258
|
+
]
|
|
259
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Card from '@ledvance/base/src/components/Card'
|
|
3
|
+
import { SwitchButton, Utils } from 'tuya-panel-kit'
|
|
4
|
+
import { Image, StyleSheet, Text, View, ViewProps } from 'react-native'
|
|
5
|
+
import {
|
|
6
|
+
getMainLight,
|
|
7
|
+
getSecondaryLight,
|
|
8
|
+
isStaticMixMood,
|
|
9
|
+
MixMood,
|
|
10
|
+
MixSceneLampInfo,
|
|
11
|
+
} from './MixSceneBeans'
|
|
12
|
+
import { hsv2Hex } from '@ledvance/base/src/utils'
|
|
13
|
+
import { cctToColor } from '@ledvance/base/src/utils/cctUtils'
|
|
14
|
+
import Spacer from '@ledvance/base/src/components/Spacer'
|
|
15
|
+
import MoodColorsLine from '@ledvance/base/src/components/MoodColorsLine'
|
|
16
|
+
import { SceneNodeTransitionMode } from './SceneInfo'
|
|
17
|
+
import I18n from '@ledvance/base/src/i18n'
|
|
18
|
+
import { mapFloatToRange } from '@ledvance/base/src/utils'
|
|
19
|
+
|
|
20
|
+
const cx = Utils.RatioUtils.convertX
|
|
21
|
+
|
|
22
|
+
const lightOn = require('../res/light_on.png')
|
|
23
|
+
const lightOff = require('../res/light_off.png')
|
|
24
|
+
|
|
25
|
+
interface MixMoodItemProps extends ViewProps {
|
|
26
|
+
enable: boolean
|
|
27
|
+
mixMood: MixMood
|
|
28
|
+
onPress?: () => void
|
|
29
|
+
onSwitch: (enable: boolean) => void
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const MixMoodItem = (props: MixMoodItemProps) => {
|
|
33
|
+
const { mixMood } = props
|
|
34
|
+
const mainLight = getMainLight(mixMood)
|
|
35
|
+
const secondaryLight = getSecondaryLight(mixMood)
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Card style={styles.card} onPress={props.onPress}>
|
|
39
|
+
<View>
|
|
40
|
+
<Spacer height={cx(16)} />
|
|
41
|
+
<View style={styles.headline}>
|
|
42
|
+
<Text style={styles.headText}>{mixMood.name}</Text>
|
|
43
|
+
<SwitchButton value={props.enable} onValueChange={props.onSwitch} thumbStyle={{ elevation: 0 }} />
|
|
44
|
+
</View>
|
|
45
|
+
<Spacer />
|
|
46
|
+
<MixMoodColorsLine mixSubLight={mainLight} colorLight={false} />
|
|
47
|
+
<Spacer height={cx(7)} />
|
|
48
|
+
<MixMoodColorsLine mixSubLight={secondaryLight} colorLight={true} />
|
|
49
|
+
<Spacer height={cx(12)} />
|
|
50
|
+
<View style={styles.moodTypeItem}>
|
|
51
|
+
<View style={styles.moodTypeLabel}>
|
|
52
|
+
<Text style={styles.moodTypeLabelText}>
|
|
53
|
+
{I18n.getLang(isStaticMixMood(mixMood) ? 'mood_overview_field_chip_text' : 'mood_overview_field_chip_2')}
|
|
54
|
+
</Text>
|
|
55
|
+
</View>
|
|
56
|
+
</View>
|
|
57
|
+
<Spacer height={cx(16)} />
|
|
58
|
+
</View>
|
|
59
|
+
</Card>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default MixMoodItem
|
|
64
|
+
|
|
65
|
+
export function MixMoodColorsLine(props: { mixSubLight: MixSceneLampInfo, colorLight: boolean }) {
|
|
66
|
+
const { mixSubLight, colorLight } = props
|
|
67
|
+
const lightColors = mixSubLight.nodes?.map(n => {
|
|
68
|
+
return colorLight ? hsv2Hex(n.hue, Math.round(n.sat), Math.round(mapFloatToRange(n.lightness / 100, 50, 100)))
|
|
69
|
+
: cctToColor(n.colorTemp.toFixed())
|
|
70
|
+
})
|
|
71
|
+
return (
|
|
72
|
+
<View style={styles.gradientItem}>
|
|
73
|
+
<Spacer height={0} width={cx(16)} />
|
|
74
|
+
<MoodColorsLine
|
|
75
|
+
width={cx(264)}
|
|
76
|
+
type={mixSubLight.enable && mixSubLight.nodes[0].changeType === SceneNodeTransitionMode.Gradient ? 'gradient' : 'separate'}
|
|
77
|
+
colors={mixSubLight.enable ? lightColors : ['#eee']} />
|
|
78
|
+
<Spacer height={0} width={cx(7)} />
|
|
79
|
+
<View style={styles.gradientItemIconView}>
|
|
80
|
+
<Image style={styles.gradientItemIcon} source={mixSubLight.enable ? lightOn : lightOff} />
|
|
81
|
+
</View>
|
|
82
|
+
<Spacer height={0} width={cx(16)} />
|
|
83
|
+
</View>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const styles = StyleSheet.create({
|
|
88
|
+
card: {
|
|
89
|
+
marginHorizontal: cx(24),
|
|
90
|
+
},
|
|
91
|
+
headline: {
|
|
92
|
+
flexDirection: 'row',
|
|
93
|
+
marginHorizontal: cx(16),
|
|
94
|
+
},
|
|
95
|
+
headText: {
|
|
96
|
+
flex: 1,
|
|
97
|
+
color: '#000',
|
|
98
|
+
fontSize: cx(16),
|
|
99
|
+
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
100
|
+
lineHeight: cx(20),
|
|
101
|
+
},
|
|
102
|
+
gradientItem: {
|
|
103
|
+
flexDirection: 'row',
|
|
104
|
+
},
|
|
105
|
+
gradientItemIconView: {
|
|
106
|
+
width: cx(24),
|
|
107
|
+
height: cx(24),
|
|
108
|
+
justifyContent: 'center',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
backgroundColor: '#aaa',
|
|
111
|
+
borderRadius: cx(8),
|
|
112
|
+
},
|
|
113
|
+
gradientItemIcon: {
|
|
114
|
+
width: cx(16),
|
|
115
|
+
height: cx(16),
|
|
116
|
+
tintColor: '#fff',
|
|
117
|
+
},
|
|
118
|
+
gradient: {
|
|
119
|
+
borderRadius: cx(8),
|
|
120
|
+
},
|
|
121
|
+
moodTypeItem: {
|
|
122
|
+
flexDirection: 'row',
|
|
123
|
+
},
|
|
124
|
+
moodTypeLabel: {
|
|
125
|
+
marginStart: cx(16),
|
|
126
|
+
paddingHorizontal: cx(12.5),
|
|
127
|
+
backgroundColor: '#E6E7E8',
|
|
128
|
+
borderRadius: cx(8),
|
|
129
|
+
},
|
|
130
|
+
moodTypeLabelText: {
|
|
131
|
+
height: cx(16),
|
|
132
|
+
color: '#000000DD',
|
|
133
|
+
fontSize: cx(10),
|
|
134
|
+
textAlignVertical: 'center',
|
|
135
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
136
|
+
lineHeight: cx(16),
|
|
137
|
+
},
|
|
138
|
+
})
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import React, { useCallback, useEffect } from 'react'
|
|
2
|
+
import { useDeviceInfo } from '@ledvance/base/src/models/modules/NativePropsSlice'
|
|
3
|
+
import I18n from '@ledvance/base/src/i18n'
|
|
4
|
+
import res from '@res'
|
|
5
|
+
import { isStaticMixMood, MixMood } from './MixSceneBeans'
|
|
6
|
+
import { useReactive } from 'ahooks'
|
|
7
|
+
import { FlatList, StyleSheet, View } from 'react-native'
|
|
8
|
+
import Tag from '@ledvance/base/src/components/Tag'
|
|
9
|
+
import Spacer from '@ledvance/base/src/components/Spacer'
|
|
10
|
+
import InfoText from '@ledvance/base/src/components/InfoText'
|
|
11
|
+
import { Utils } from 'tuya-panel-kit'
|
|
12
|
+
import MixMoodItem from './MixMoodItem'
|
|
13
|
+
import { getMixLightSceneList } from './MixLightSceneActions'
|
|
14
|
+
|
|
15
|
+
const cx = Utils.RatioUtils.convertX
|
|
16
|
+
|
|
17
|
+
interface MixUIState {
|
|
18
|
+
showAddMixMoodDialog: boolean
|
|
19
|
+
staticTagChecked: boolean
|
|
20
|
+
dynamicTagChecked: boolean
|
|
21
|
+
currentMixMood?: MixMood
|
|
22
|
+
mixMoods: MixMood[]
|
|
23
|
+
filteredMoods: MixMood[]
|
|
24
|
+
flag: symbol
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const MixScene = ({ setActionScene, mixScene }) => {
|
|
28
|
+
const deviceInfo = useDeviceInfo()
|
|
29
|
+
|
|
30
|
+
const state = useReactive<MixUIState>({
|
|
31
|
+
showAddMixMoodDialog: false,
|
|
32
|
+
staticTagChecked: true,
|
|
33
|
+
dynamicTagChecked: true,
|
|
34
|
+
mixMoods: [],
|
|
35
|
+
filteredMoods: [],
|
|
36
|
+
flag: Symbol(),
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const initMixLightSceneList = useCallback(async () => {
|
|
40
|
+
const res = await getMixLightSceneList(deviceInfo.devId)
|
|
41
|
+
if (res.success) {
|
|
42
|
+
state.mixMoods = res.data || []
|
|
43
|
+
const itemSence = state.mixMoods?.find(mix => mix.value === mixScene)
|
|
44
|
+
setActionScene(itemSence || state.mixMoods[0])
|
|
45
|
+
state.currentMixMood = itemSence || state.mixMoods[0]
|
|
46
|
+
}
|
|
47
|
+
}, [])
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
initMixLightSceneList().then()
|
|
51
|
+
}, [state.flag])
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
state.filteredMoods = state.mixMoods.filter(item => {
|
|
55
|
+
return (state.staticTagChecked && state.dynamicTagChecked) ||
|
|
56
|
+
(state.staticTagChecked && isStaticMixMood(item)) ||
|
|
57
|
+
(state.dynamicTagChecked && !isStaticMixMood(item))
|
|
58
|
+
})
|
|
59
|
+
}, [state.staticTagChecked, state.dynamicTagChecked, state.mixMoods])
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<View style={styles.tagLine}>
|
|
64
|
+
<Tag
|
|
65
|
+
checked={state.staticTagChecked}
|
|
66
|
+
text={I18n.getLang('mood_overview_filter_name_text1')}
|
|
67
|
+
onCheckedChange={checked => {
|
|
68
|
+
state.staticTagChecked = checked
|
|
69
|
+
}} />
|
|
70
|
+
<Spacer width={cx(8)} height={0} />
|
|
71
|
+
<Tag
|
|
72
|
+
checked={state.dynamicTagChecked}
|
|
73
|
+
text={I18n.getLang('mood_overview_filter_name_text2')}
|
|
74
|
+
onCheckedChange={checked => {
|
|
75
|
+
state.dynamicTagChecked = checked
|
|
76
|
+
}} />
|
|
77
|
+
</View>
|
|
78
|
+
<Spacer height={cx(10)} />
|
|
79
|
+
<FlatList
|
|
80
|
+
data={state.filteredMoods}
|
|
81
|
+
renderItem={({ item }) =>
|
|
82
|
+
<MixMoodItem
|
|
83
|
+
enable={item.id === state.currentMixMood?.id}
|
|
84
|
+
mixMood={item}
|
|
85
|
+
onSwitch={async enable => {
|
|
86
|
+
if (enable) {
|
|
87
|
+
state.currentMixMood = item
|
|
88
|
+
setActionScene(item)
|
|
89
|
+
}
|
|
90
|
+
}} />
|
|
91
|
+
}
|
|
92
|
+
ListHeaderComponent={() => (<Spacer height={cx(10)} />)}
|
|
93
|
+
ItemSeparatorComponent={() => (<Spacer />)}
|
|
94
|
+
ListFooterComponent={() => (
|
|
95
|
+
<View style={styles.infoLine}>
|
|
96
|
+
<Spacer />
|
|
97
|
+
<InfoText
|
|
98
|
+
icon={res.ic_info}
|
|
99
|
+
text={I18n.getLang('mood_overview_information_text')} />
|
|
100
|
+
<Spacer height={cx(40)} />
|
|
101
|
+
</View>
|
|
102
|
+
)}
|
|
103
|
+
keyExtractor={item => `${item.id}`} />
|
|
104
|
+
</>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const styles = StyleSheet.create({
|
|
109
|
+
tagLine: {
|
|
110
|
+
flexDirection: 'row',
|
|
111
|
+
marginHorizontal: cx(24),
|
|
112
|
+
marginTop: cx(24),
|
|
113
|
+
},
|
|
114
|
+
infoLine: {
|
|
115
|
+
marginHorizontal: cx(24),
|
|
116
|
+
},
|
|
117
|
+
addMixMoodDialog: {
|
|
118
|
+
width: cx(171),
|
|
119
|
+
height: cx(90.5),
|
|
120
|
+
marginStart: cx(156),
|
|
121
|
+
marginTop: cx(105),
|
|
122
|
+
backgroundColor: '#fff',
|
|
123
|
+
},
|
|
124
|
+
popoverItem: {
|
|
125
|
+
width: cx(171),
|
|
126
|
+
height: cx(45),
|
|
127
|
+
alignItems: 'flex-start',
|
|
128
|
+
},
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
export default MixScene
|