@ledvance/ui-biz-bundle 1.0.39 → 1.0.41

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "@ledvance/ui-biz-bundle",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.0.39",
7
+ "version": "1.0.41",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -28,6 +28,7 @@ export interface BiorhythmEditPageParams {
28
28
  isMixRGBWLamp: boolean
29
29
  isSupportTemperature: boolean
30
30
  isSupportBrightness: boolean
31
+ showDeleteBtn?: boolean
31
32
  }
32
33
 
33
34
  const BiorhythmEditPage = () => {
@@ -43,6 +44,7 @@ const BiorhythmEditPage = () => {
43
44
  isMixRGBWLamp,
44
45
  isSupportTemperature,
45
46
  isSupportBrightness,
47
+ showDeleteBtn
46
48
  } = route.params as BiorhythmEditPageParams
47
49
  const [hour, minute] = planData.startTime.split(':')
48
50
  const state = useReactive({
@@ -269,7 +271,7 @@ const BiorhythmEditPage = () => {
269
271
  </View>
270
272
  <View style={{height: cx(20)}}/>
271
273
  </View>
272
- {!isAdd &&
274
+ {!isAdd && showDeleteBtn &&
273
275
  <View
274
276
  style={{
275
277
  height: cx(50),
@@ -230,6 +230,10 @@ const BiorhythmPage = () => {
230
230
  return enable
231
231
  }
232
232
 
233
+ const showDeleteBtn = useMemo(() => {
234
+ return state.planList?.length > 1
235
+ }, [state.planList?.length])
236
+
233
237
  const {run} = useDebounceFn(requestSetBiorhythm, {wait: 500})
234
238
 
235
239
  useUpdateEffect(() => {
@@ -556,6 +560,7 @@ const BiorhythmPage = () => {
556
560
  isMixRGBWLamp: params.isMixRGBWLamp,
557
561
  isSupportTemperature: params.isSupportTemperature,
558
562
  isSupportBrightness: params.isSupportBrightness,
563
+ showDeleteBtn
559
564
  }
560
565
  navigation.navigate(ui_biz_routerKey.bi_biz_biological_edit, editPageParams)
561
566
  }}>
@@ -607,6 +612,7 @@ const BiorhythmPage = () => {
607
612
  isMixRGBWLamp: params.isMixRGBWLamp,
608
613
  isSupportTemperature: params.isSupportTemperature,
609
614
  isSupportBrightness: params.isSupportBrightness,
615
+ showDeleteBtn
610
616
  }
611
617
  navigation.navigate(ui_biz_routerKey.bi_biz_biological_edit, editPageParams)
612
618
  }}
@@ -770,3 +776,7 @@ const BiorhythmPage = () => {
770
776
  }
771
777
 
772
778
  export default BiorhythmPage
779
+ function useMemo(arg0: () => boolean, arg1: any[]) {
780
+ throw new Error('Function not implemented.')
781
+ }
782
+
@@ -1,271 +1,541 @@
1
- import React, {useCallback, useEffect} from 'react'
2
1
  import Page from '@ledvance/base/src/components/Page'
3
- import {Utils} from 'tuya-panel-kit'
4
- import {ScenePageUIState, SceneUIState} from '../scene/SceneInfo'
5
- import {getRemoteSceneList, useScene} from '../scene/SceneAction'
6
- import {SCENE, useWorkMode} from '../../hooks/DeviceDpStateHooks'
7
- import {useDeviceInfo} from '@ledvance/base/src/models/modules/NativePropsSlice'
8
- import {useReactive, useUpdateEffect} from 'ahooks'
9
2
  import Strings from '@ledvance/base/src/i18n'
3
+ import {StaticMoodEditorPageParams, StaticMoodEditorPageState} from './StaticMoodEditorPage'
4
+ import {useNavigation, useRoute} from '@react-navigation/native'
5
+ import {StackNavigationProp} from '@react-navigation/stack'
6
+ import React, {useCallback, useEffect, useMemo} from 'react'
7
+ import {useReactive} from 'ahooks'
8
+ import {COLOUR, useWorkMode, WHITE} from 'hooks/DeviceDpStateHooks'
9
+ import {hsv2Hex, mapFloatToRange} from '@ledvance/base/src/utils'
10
+ import {cctToColor} from '@ledvance/base/src/utils/cctUtils'
10
11
  import res from '@ledvance/base/src/res'
11
- import {FlatList, StyleSheet, View} from 'react-native'
12
- import Tag from '@ledvance/base/src/components/Tag'
12
+ import {cloneDeep, find, isEqual} from 'lodash'
13
+ import {FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
14
+ import TextField from '@ledvance/base/src/components/TextField'
15
+ import Card from '@ledvance/base/src/components/Card'
13
16
  import Spacer from '@ledvance/base/src/components/Spacer'
14
- import InfoText from '@ledvance/base/src/components/InfoText'
15
- import CustomListDialog from '@ledvance/base/src/components/CustomListDialog'
16
- import MoodItem from './MoodItem'
17
- import {toAddMoodPage, toDynamicMoodEditorPage, toStaticMoodEditorPage} from '../../navigation/tools'
18
- import {useNavigation, useRoute} from '@react-navigation/core'
19
-
17
+ import LampAdjustView from '@ledvance/base/src/components/LampAdjustView'
18
+ import {Utils} from 'tuya-panel-kit'
19
+ import LdvSlider from '@ledvance/base/src/components/ldvSlider'
20
+ import {saveScene, useScene} from '../scene/SceneAction'
21
+ import {useDeviceId, useFanMaxSpeed} from '@ledvance/base/src/models/modules/NativePropsSlice'
22
+ import TextButton from '@ledvance/base/src/components/TextButton'
23
+ import {SceneNodeInfo, SceneNodeTransitionMode} from '../scene/SceneInfo'
24
+ import TextFieldStyleButton from '@ledvance/base/src/components/TextFieldStyleButton'
25
+ import {SelectPageData, SelectPageParams} from '../select/SelectPage'
26
+ import {toSelectPage} from '../../navigation/tools'
27
+ import FanAdjustView from '@ledvance/base/src/components/FanAdjustView'
28
+ import {showDeleteMoodDialog} from './tools'
29
+ import {ui_biz_routerKey} from '../../navigation/Routers'
20
30
  const cx = Utils.RatioUtils.convertX
21
-
22
- interface MoodPageUIState extends ScenePageUIState {
23
- staticTagChecked: boolean
24
- dynamicTagChecked: boolean
25
- showAddMoodPopover: boolean
26
- originScene: SceneUIState[]
27
- filteredMoods: SceneUIState[]
28
- loading: boolean
31
+ interface DynamicMoodEditorPageState extends StaticMoodEditorPageState {
32
+ paintBucketSelected: boolean
29
33
  }
30
-
31
- export interface MoodPageProps {
32
- switchLedDpCode: string
33
- sceneDpCode: string
34
- workModeDpCode: string
35
- isRGBWLamp?: boolean
36
- isRGBLamp?: boolean
37
- isOnlyRGBLamp?: boolean
38
- isFanLamp?: boolean
39
- isTWLamp?: boolean
40
- isDIMLamp?: boolean
41
- isSupportColor: boolean
42
- isSupportTemperature: boolean
43
- isSupportBrightness: boolean
44
- }
45
-
46
- const MAX_MOOD_COUNT = 8
47
-
48
- const MoodPage = () => {
49
- const routeParams = useRoute().params as MoodPageProps
50
- const params: MoodPageProps = {
51
- ...routeParams,
52
- isRGBWLamp: routeParams.isRGBWLamp || false,
53
- isRGBLamp: routeParams.isRGBLamp || false,
54
- isOnlyRGBLamp: routeParams.isOnlyRGBLamp || false,
55
- isFanLamp: routeParams.isFanLamp || false,
56
- isTWLamp: routeParams.isTWLamp || false,
57
- isDIMLamp: routeParams.isDIMLamp || false,
58
- }
59
- const [sceneId, setScene] = useScene(params.sceneDpCode)
60
- const [workMode] = useWorkMode(params.workModeDpCode)
61
- const deviceInfo = useDeviceInfo()
62
- const navigation = useNavigation()
63
-
64
- const state = useReactive<MoodPageUIState>({
65
- currentScene: undefined,
66
- staticTagChecked: true,
67
- dynamicTagChecked: true,
68
- showAddMoodPopover: false,
69
- scenes: [],
70
- flag: Symbol(),
71
- originScene: [],
72
- filteredMoods: [],
73
- loading: false,
34
+ const DynamicMoodEditorPage = () => {
35
+ const navigation = useNavigation<StackNavigationProp<any>>()
36
+ const routeParams = useRoute().params as StaticMoodEditorPageParams
37
+ const params = cloneDeep(routeParams)
38
+ const moduleParams = params.moduleParams
39
+ const deviceId = useDeviceId()
40
+ const [moodId, setScene] = useScene(moduleParams.sceneDpCode)
41
+ const [, setWorkMode] = useWorkMode(moduleParams.workModeDpCode)
42
+ const state = useReactive<DynamicMoodEditorPageState>({
43
+ headline: '',
44
+ mood: params.currentMood,
45
+ currentNode: params.currentMood.nodes[params.currentMood.nodes.length - 1],
46
+ paintBucketSelected: false,
74
47
  })
75
-
76
- const getSceneList = useCallback(async (currentSceneId: number) => {
77
- setTimeout(async () => {
78
- const res = await getRemoteSceneList(
79
- deviceInfo.devId,
80
- params.isRGBWLamp,
81
- params.isRGBLamp,
82
- params.isOnlyRGBLamp,
83
- params.isFanLamp,
84
- params.isTWLamp,
85
- params.isDIMLamp,
86
- )
87
- if (res.success) {
88
- state.scenes = res.data || []
89
- state.currentScene = state.scenes.find(scene => scene.id === currentSceneId)
90
- }
91
- }, 500)
48
+ useEffect(() => {
49
+ state.headline = Strings.getLang(params.mode ? 'add_new_dynamic_mood_headline_text' : 'edit_static_mood_headline_text')
50
+ }, [params.mode])
51
+ const getColorBlockColor = useCallback(() => {
52
+ const s = Math.round(mapFloatToRange(state.currentNode.s / 100, 30, 100))
53
+ if (moduleParams.isOnlyRGBLamp) {
54
+ return hsv2Hex(state.currentNode.h, s, 100)
55
+ }
56
+ if (moduleParams.isTWLamp) {
57
+ return cctToColor(state.currentNode.colorTemp.toFixed())
58
+ }
59
+ if (moduleParams.isDIMLamp) {
60
+ return '#fff'
61
+ }
62
+ if (state.currentNode.isColorNode) {
63
+ return hsv2Hex(state.currentNode.h, s, 100)
64
+ }
65
+ if (moduleParams.isSupportTemperature) {
66
+ return cctToColor(state.currentNode.colorTemp.toFixed())
67
+ }
68
+ }, [state.currentNode, state.currentNode.colorTemp])
69
+ const getNodeColor = useCallback((node: SceneNodeInfo) => {
70
+ if (node.isColorNode) {
71
+ const s = Math.round(mapFloatToRange(node.s / 100, 30, 100))
72
+ return hsv2Hex(node.h, s, 100)
73
+ }
74
+ return cctToColor(node.colorTemp.toFixed())
92
75
  }, [])
93
-
94
- const onAddMoodDialogItemClick = useCallback((isStatic: boolean, _: number) => {
95
- if (!!state.scenes) {
96
- toAddMoodPage(
97
- navigation,
98
- {
99
- isStatic: isStatic,
100
- moods: state.scenes,
101
- moduleParams: params,
102
- onSave: () => {
103
- state.flag = Symbol()
104
- },
76
+ const onPost = useCallback(async (isDelete: boolean) => {
77
+ const currentMood = {
78
+ id: params.currentMood.id,
79
+ name: state.mood.name,
80
+ image: state.mood.image,
81
+ fanEnable: state.mood.fanEnable,
82
+ fanSpeed: state.mood.fanSpeed,
83
+ nodes: state.mood.nodes,
84
+ }
85
+ const list = params.mode === 'add' ? [...params.moods, currentMood] :
86
+ isDelete ? params.moods.filter(mood => mood.id !== currentMood.id) :
87
+ params.moods.map(mood => {
88
+ return mood.id === currentMood.id ? currentMood : mood
105
89
  })
90
+ const saveRes = await saveScene(
91
+ deviceId,
92
+ currentMood,
93
+ state.currentNode.transitionMode,
94
+ state.currentNode.transitionTime,
95
+ list,
96
+ moduleParams.isFanLamp!!,
97
+ )
98
+ if (saveRes.success) {
99
+ if (list.length > 0) {
100
+ if (isDelete && currentMood.id === moodId) {
101
+ const setSceneRes = await setScene(
102
+ deviceId,
103
+ list[0],
104
+ moduleParams.sceneDpCode,
105
+ moduleParams.workModeDpCode,
106
+ moduleParams.switchLedDpCode,
107
+ !!moduleParams.isFanLamp
108
+ )
109
+ console.log('设置修改后的场景结果', setSceneRes)
110
+ } else if (!isDelete) {
111
+ const setSceneRes = await setScene(
112
+ deviceId,
113
+ currentMood,
114
+ moduleParams.sceneDpCode,
115
+ moduleParams.workModeDpCode,
116
+ moduleParams.switchLedDpCode,
117
+ !!moduleParams.isFanLamp
118
+ )
119
+ console.log('设置修改后的场景结果', setSceneRes)
120
+ }
121
+ } else {
122
+ await setWorkMode(moduleParams.isOnlyRGBLamp ? COLOUR : WHITE)
123
+ console.log('Mood被清空,将work_mode设置成white')
124
+ }
106
125
  }
107
- state.showAddMoodPopover = false
108
- }, [state.scenes])
109
-
110
- useEffect(() => {
111
- state.filteredMoods = state.scenes.filter(item => {
112
- return (state.staticTagChecked && state.dynamicTagChecked) ||
113
- (!state.staticTagChecked && !state.dynamicTagChecked) ||
114
- (state.staticTagChecked && item.nodes.length < 2) ||
115
- (state.dynamicTagChecked && item.nodes.length > 1)
116
- })
117
- }, [state.staticTagChecked, state.dynamicTagChecked, state.scenes])
118
-
119
- useUpdateEffect(() => {
120
- state.currentScene = state.scenes.find(scene => scene.id === sceneId)
121
- }, [sceneId])
122
-
123
- useEffect(() => {
124
- getSceneList(sceneId).then()
125
- }, [state.flag, sceneId])
126
-
126
+ navigation.navigate(ui_biz_routerKey.ui_biz_mood)
127
+ routeParams.onSave()
128
+ }, [])
129
+ const getButtonStatus = () => {
130
+ return (params.mode === 'edit' && isEqual(state.mood, routeParams.currentMood)) ||
131
+ !(!!state.mood.name) ||
132
+ nameRepeat ||
133
+ state.mood.name.length > 32 ||
134
+ state.mood.nodes.length < 2
135
+ }
136
+ const nameRepeat = useMemo(() => {
137
+ return !!find(params.moods, m => (m.id !== state.mood.id && m.name === state.mood.name))
138
+ }, [state.mood.name])
127
139
  return (
128
- <>
129
- <Page
130
- backText={deviceInfo.name}
131
- headlineText={Strings.getLang('mood_overview_headline_text')}
132
- headlineIcon={state.scenes.length < MAX_MOOD_COUNT ? res.add : undefined}
133
- onHeadlineIconClick={() => {
134
- state.showAddMoodPopover = !state.showAddMoodPopover
135
- }}
136
- loading={state.loading}>
137
- <View style={styles.tagLine}>
138
- <Tag
139
- checked={state.staticTagChecked}
140
- text={Strings.getLang('mood_overview_filter_name_text1')}
141
- onCheckedChange={checked => {
142
- state.staticTagChecked = checked
143
- }}/>
144
- <Spacer width={cx(8)} height={0}/>
145
- <Tag
146
- checked={state.dynamicTagChecked}
147
- text={Strings.getLang('mood_overview_filter_name_text2')}
148
- onCheckedChange={checked => {
149
- state.dynamicTagChecked = checked
150
- }}/>
151
- </View>
152
- <Spacer height={cx(10)}/>
153
- {
154
- state.scenes.length >= MAX_MOOD_COUNT &&
155
- <View style={styles.infoLine}>
156
- <Spacer height={cx(10)}/>
157
- <InfoText
158
- icon={res.ic_warning_amber}
159
- text={Strings.getLang('mood_overview_warning_max_number_text')}
160
- contentColor={'#ff9500'}/>
161
- <Spacer height={cx(6)}/>
140
+ <Page
141
+ backText={Strings.getLang('mesh_device_detail_mode')}
142
+ showBackDialog={true}
143
+ backDialogTitle={
144
+ Strings.getLang(params.mode === 'add' ?
145
+ 'string_light_pp_dialog_sm_add_headline_c' :
146
+ 'manage_user_unsaved_changes_dialog_headline')
147
+ }
148
+ backDialogContent={
149
+ Strings.getLang(params.mode === 'add' ?
150
+ 'strip_light_static_mood_add_step_2_dialog_text' :
151
+ 'strip_light_static_mood_editor_step_2_dialog_text')
152
+ }
153
+ headlineText={state.headline}
154
+ rightButtonIcon={getButtonStatus() ? res.ic_uncheck : res.ic_check}
155
+ rightButtonDisabled={getButtonStatus()}
156
+ rightButtonIconClick={async () => {
157
+ await onPost(false)
158
+ }}>
159
+ <ScrollView
160
+ style={{flex: 1}}
161
+ nestedScrollEnabled={true}>
162
+ <View style={styles.root}>
163
+ <TextField
164
+ style={styles.name}
165
+ value={state.mood.name}
166
+ placeholder={Strings.getLang('edit_static_mood_inputfield_topic_text')}
167
+ onChangeText={text => {
168
+ state.mood.name = text
169
+ }}
170
+ showError={state.mood.name.length > 32 || nameRepeat}
171
+ tipColor={nameRepeat ? '#f00' : undefined}
172
+ tipIcon={nameRepeat ? res.ic_text_field_input_error : undefined}
173
+ errorText={Strings.getLang(nameRepeat ? 'string_light_pp_field_sm_add_error1' : 'add_new_dynamic_mood_alert_text')}/>
174
+ <Card style={styles.adjustCard}>
175
+ <Spacer height={cx(16)}/>
176
+ <View style={styles.lightLine}>
177
+ <Text style={styles.light}>
178
+ {Strings.getLang('light_sources_tile_tw_lighting_headline')}
179
+ </Text>
162
180
  </View>
163
- }
164
- <FlatList
165
- data={state.filteredMoods}
166
- renderItem={({item}) => {
167
- return (
168
- <MoodItem
169
- enable={workMode === SCENE && state.currentScene?.id === item.id}
170
- mood={item}
171
- onPress={() => {
172
- if (item.nodes.length > 1) {
173
- toDynamicMoodEditorPage(
174
- navigation,
175
- {
176
- mode: 'edit',
177
- currentMood: item,
178
- moods: state.scenes,
179
- moduleParams: params,
180
- onSave: () => {
181
- state.flag = Symbol()
182
- },
183
- })
184
- return
185
- }
186
- toStaticMoodEditorPage(
187
- navigation,
188
- {
189
- mode: 'edit',
190
- currentMood: item,
191
- moods: state.scenes,
192
- moduleParams: params,
193
- onSave: () => {
194
- state.flag = Symbol()
195
- },
181
+ <Spacer height={cx(18)}/>
182
+ <TextFieldStyleButton
183
+ style={styles.transitionMode}
184
+ text={getTransitionModeString(state.mood.nodes[0].transitionMode)}
185
+ placeholder={Strings.getLang('add_new_dynamic_mood_color_changing_mode_headline')}
186
+ onPress={() => {
187
+ const paramsSelect: SelectPageParams<SceneNodeTransitionMode> = {
188
+ title: Strings.getLang('add_new_dynamic_mood_color_changing_mode_headline'),
189
+ data: [
190
+ createSelectPageData(state.mood.nodes[0].transitionMode, SceneNodeTransitionMode.Gradient),
191
+ createSelectPageData(state.mood.nodes[0].transitionMode, SceneNodeTransitionMode.Jump),
192
+ ],
193
+ onSelect: selectPageData => {
194
+ state.mood.nodes.forEach(node => {
195
+ node.transitionMode = selectPageData.value
196
196
  })
197
+ },
198
+ }
199
+ toSelectPage(navigation, paramsSelect)
200
+ }}/>
201
+ <Spacer height={cx(10)}/>
202
+ <LdvSlider
203
+ title={Strings.getLang('add_new_dynamic_mood_lights_field_speed_topic_text')}
204
+ value={state.mood.nodes[0].transitionTime}
205
+ onValueChange={value => {
206
+ state.mood.nodes.forEach(node => {
207
+ node.transitionTime = value
208
+ node.switchingInterval = value
209
+ })
210
+ }}
211
+ onSlidingComplete={value => {
212
+ state.mood.nodes.forEach(node => {
213
+ node.transitionTime = value
214
+ node.switchingInterval = value
215
+ })
216
+ }}/>
217
+ <Spacer height={cx(16)}/>
218
+ <View style={styles.nodesAdjust}>
219
+ <View style={styles.adjustButtons}>
220
+ <TouchableOpacity
221
+ onPress={() => {
222
+ state.paintBucketSelected = true
223
+ }}>
224
+ <Image
225
+ style={[styles.adjustButton, {tintColor: state.paintBucketSelected ? '#f60' : '#666'}]}
226
+ source={res.ic_paint_bucket}/>
227
+ </TouchableOpacity>
228
+ <TouchableOpacity
229
+ onPress={() => {
230
+ state.paintBucketSelected = false
231
+ }}>
232
+ <Image
233
+ style={[styles.adjustButton, {tintColor: state.paintBucketSelected ? '#666' : '#f60'}]}
234
+ source={res.ic_colorize}/>
235
+ </TouchableOpacity>
236
+ </View>
237
+ <FlatList
238
+ data={state.mood.nodes}
239
+ style={styles.nodeList}
240
+ renderItem={({item, index}) => {
241
+ return (
242
+ <View style={styles.nodeItem}>
243
+ <TouchableOpacity
244
+ style={[
245
+ styles.nodeBlock,
246
+ {
247
+ backgroundColor: getNodeColor(item),
248
+ },
249
+ ]}
250
+ onPress={() => {
251
+ state.currentNode = item
252
+ }}/>
253
+ <TouchableOpacity
254
+ style={styles.nodeDeleteBtn}
255
+ disabled={state.mood.nodes.length < 3}
256
+ onPress={() => {
257
+ state.mood.nodes.splice(index, 1)
258
+ state.currentNode = state.mood.nodes[state.mood.nodes.length - 1]
259
+ }}>
260
+ <Image
261
+ style={[
262
+ styles.nodeDeleteIcon,
263
+ {
264
+ tintColor: state.mood.nodes.length < 3 ? '#ccc' : '#666',
265
+ },
266
+ ]}
267
+ source={res.ic_mood_del}/>
268
+ </TouchableOpacity>
269
+ </View>
270
+ )
197
271
  }}
198
- onSwitch={async _ => {
199
- if (workMode === SCENE && state.currentScene?.id === item.id) return
200
- state.loading = true
201
- await setScene(
202
- deviceInfo.devId,
203
- item,
204
- params.sceneDpCode,
205
- params.workModeDpCode,
206
- params.switchLedDpCode,
207
- !!params.isFanLamp
272
+ keyExtractor={(_, index) => `${index}`}
273
+ ItemSeparatorComponent={() => <Spacer height={cx(12)}/>}
274
+ ListFooterComponent={() => {
275
+ if (state.mood.nodes.length >= 8) {
276
+ return (<></>)
277
+ }
278
+ return (
279
+ <View>
280
+ <Spacer height={cx(12)}/>
281
+ <TouchableOpacity
282
+ style={styles.nodeAddBtn}
283
+ onPress={() => {
284
+ const node = {
285
+ ...state.currentNode,
286
+ }
287
+ state.mood.nodes.push(node)
288
+ state.currentNode = node
289
+ }}>
290
+ <Image
291
+ style={{
292
+ width: cx(18),
293
+ height: cx(18),
294
+ tintColor: '#000',
295
+ }}
296
+ source={{uri: res.add}}/>
297
+ </TouchableOpacity>
298
+ </View>
208
299
  )
209
- state.currentScene = item
210
- state.loading = false
211
300
  }}/>
212
- )
213
- }}
214
- ListHeaderComponent={() => (<Spacer height={cx(10)}/>)}
215
- ItemSeparatorComponent={() => (<Spacer/>)}
216
- ListFooterComponent={() => (
217
- <View style={styles.infoLine}>
218
- <Spacer/>
219
- <InfoText
220
- icon={res.ic_info}
221
- text={Strings.getLang('mood_overview_information_text')}/>
222
- <Spacer height={cx(40)}/>
223
301
  </View>
224
- )}
225
- keyExtractor={item => `${item.id}`}/>
226
- </Page>
227
- <CustomListDialog
228
- show={state.showAddMoodPopover}
229
- style={styles.addMoodPopover}
230
- itemStyle={styles.popoverItem}
231
- onDismiss={() => {
232
- state.showAddMoodPopover = false
233
- }}
234
- data={[
235
- {
236
- text: Strings.getLang('mood_overview_add_mood_text'),
237
- value: true,
238
- },
239
- {
240
- text: Strings.getLang('mood_overview_add_mood_text2'),
241
- value: false,
242
- },
243
- ]}
244
- onItemPress={onAddMoodDialogItemClick}/>
245
- </>
302
+ <Spacer/>
303
+ <View style={styles.lightLine}>
304
+ <Text style={styles.light}>
305
+ {Strings.getLang('add_new_dynamic_mood_lights_field_headline2_text')}
306
+ </Text>
307
+ <View style={[styles.preview, {backgroundColor: getColorBlockColor()}]}/>
308
+ </View>
309
+ <Spacer/>
310
+ <LampAdjustView
311
+ isRGBLamp={moduleParams.isRGBLamp!!}
312
+ isRGBWLamp={moduleParams.isRGBLamp!!}
313
+ isOnlyRGBLamp={moduleParams.isOnlyRGBLamp!!}
314
+ isDIMLamp={moduleParams.isDIMLamp!!}
315
+ isTWLamp={moduleParams.isTWLamp!!}
316
+ isSupportBrightness={moduleParams.isSupportBrightness}
317
+ isSupportTemperature={moduleParams.isSupportTemperature}
318
+ isColorMode={state.currentNode.isColorNode}
319
+ setIsColorMode={isColorMode => {
320
+ if (state.paintBucketSelected) {
321
+ state.mood.nodes.forEach(node => {
322
+ node.isColorNode = isColorMode
323
+ })
324
+ } else {
325
+ state.currentNode.isColorNode = isColorMode
326
+ }
327
+ }}
328
+ h={state.currentNode.h}
329
+ s={state.currentNode.s}
330
+ v={state.currentNode.v}
331
+ onHSVChange={(h, s, v) => {
332
+ if (state.paintBucketSelected) {
333
+ state.mood.nodes.forEach(node => {
334
+ node.isColorNode = true
335
+ node.h = h
336
+ node.s = s
337
+ node.v = v
338
+ })
339
+ } else {
340
+ state.currentNode.h = h
341
+ state.currentNode.s = s
342
+ state.currentNode.v = v
343
+ }
344
+ }}
345
+ onHSVChangeComplete={(h, s, v) => {
346
+ if (state.paintBucketSelected) {
347
+ state.mood.nodes.forEach(node => {
348
+ node.isColorNode = true
349
+ node.h = h
350
+ node.s = s
351
+ node.v = v
352
+ })
353
+ } else {
354
+ state.currentNode.h = h
355
+ state.currentNode.s = s
356
+ state.currentNode.v = v
357
+ }
358
+ }}
359
+ colorTemp={state.currentNode.colorTemp}
360
+ brightness={state.currentNode.brightness}
361
+ onCCTChange={cct => {
362
+ if (state.paintBucketSelected) {
363
+ state.mood.nodes.forEach(node => {
364
+ node.isColorNode = false
365
+ node.colorTemp = cct
366
+ })
367
+ } else {
368
+ state.currentNode.colorTemp = cct
369
+ }
370
+ }}
371
+ onCCTChangeComplete={cct => {
372
+ if (state.paintBucketSelected) {
373
+ state.mood.nodes.forEach(node => {
374
+ node.isColorNode = false
375
+ node.colorTemp = cct
376
+ })
377
+ } else {
378
+ state.currentNode.colorTemp = cct
379
+ }
380
+ }}
381
+ onBrightnessChange={brightness => {
382
+ if (state.paintBucketSelected) {
383
+ state.mood.nodes.forEach(node => {
384
+ node.isColorNode = false
385
+ node.brightness = brightness
386
+ })
387
+ } else {
388
+ state.currentNode.brightness = brightness
389
+ }
390
+ }}
391
+ onBrightnessChangeComplete={brightness => {
392
+ if (state.paintBucketSelected) {
393
+ state.mood.nodes.forEach(node => {
394
+ node.isColorNode = false
395
+ node.brightness = brightness
396
+ })
397
+ } else {
398
+ state.currentNode.brightness = brightness
399
+ }
400
+ }}/>
401
+ </Card>
402
+ <Spacer/>
403
+ {moduleParams.isFanLamp &&
404
+ <FanAdjustView
405
+ fanEnable={!!state.mood.fanEnable}
406
+ fanSpeed={state.mood.fanSpeed || 1}
407
+ maxFanSpeed={useFanMaxSpeed()}
408
+ onFanSwitch={fanEnable => {
409
+ state.mood.fanEnable = fanEnable
410
+ }}
411
+ onFanSpeedChange={fanSpeed => {
412
+ state.mood.fanSpeed = fanSpeed
413
+ }}
414
+ onFanSpeedChangeComplete={fanSpeed => {
415
+ state.mood.fanSpeed = fanSpeed
416
+ }}
417
+ style={styles.fanAdjustCard}/>}
418
+ {params.mode === 'edit' &&
419
+ <View style={{marginTop: cx(20), marginHorizontal: cx(24)}}>
420
+ <TextButton
421
+ style={styles.deleteBtn}
422
+ textStyle={styles.deleteBtnText}
423
+ text={Strings.getLang('edit_static_mood_button_delete_text')}
424
+ onPress={() => {
425
+ showDeleteMoodDialog(async (_, {close}) => {
426
+ close()
427
+ await onPost(true)
428
+ })
429
+ }}/>
430
+ </View>}
431
+ <Spacer/>
432
+ </View>
433
+ </ScrollView>
434
+ </Page>
246
435
  )
247
436
  }
248
-
249
437
  const styles = StyleSheet.create({
250
- tagLine: {
251
- flexDirection: 'row',
438
+ root: {
439
+ flex: 1,
440
+ flexDirection: 'column',
441
+ },
442
+ name: {
252
443
  marginHorizontal: cx(24),
253
444
  },
254
- infoLine: {
445
+ adjustCard: {
446
+ marginVertical: cx(12),
255
447
  marginHorizontal: cx(24),
256
448
  },
257
- addMoodPopover: {
258
- width: cx(171),
259
- height: cx(90.5),
260
- marginStart: cx(156),
261
- marginTop: cx(105),
262
- backgroundColor: '#fff',
449
+ fanAdjustCard: {
450
+ marginHorizontal: cx(24),
451
+ },
452
+ lightLine: {
453
+ flexDirection: 'row',
454
+ marginHorizontal: cx(16),
455
+ },
456
+ light: {
457
+ color: '#000',
458
+ fontSize: cx(18),
459
+ fontFamily: 'helvetica_neue_lt_std_bd',
460
+ },
461
+ transitionMode: {
462
+ marginHorizontal: cx(16),
463
+ },
464
+ preview: {
465
+ width: cx(20),
466
+ height: cx(20),
467
+ marginStart: cx(12),
468
+ borderRadius: cx(4),
469
+ },
470
+ nodesAdjust: {
471
+ flexDirection: 'row',
472
+ alignItems: 'center',
473
+ },
474
+ adjustButtons: {
475
+ width: cx(44),
476
+ marginStart: cx(16),
263
477
  },
264
- popoverItem: {
265
- width: cx(171),
266
- height: cx(45),
267
- alignItems: 'flex-start',
478
+ adjustButton: {
479
+ width: cx(44),
480
+ height: cx(44),
481
+ },
482
+ nodeList: {
483
+ flex: 1,
484
+ marginHorizontal: cx(16),
485
+ },
486
+ nodeItem: {
487
+ flexDirection: 'row',
488
+ alignItems: 'center',
489
+ },
490
+ nodeBlock: {
491
+ flex: 1,
492
+ height: cx(40),
493
+ borderRadius: cx(8),
494
+ },
495
+ nodeDeleteBtn: {
496
+ width: cx(24),
497
+ height: cx(30),
498
+ justifyContent: 'center',
499
+ alignItems: 'center',
500
+ },
501
+ nodeDeleteIcon: {
502
+ width: cx(16),
503
+ height: cx(16),
504
+ },
505
+ nodeAddBtn: {
506
+ height: cx(40),
507
+ justifyContent: 'center',
508
+ alignItems: 'center',
509
+ marginEnd: cx(26),
510
+ borderRadius: cx(8),
511
+ borderWidth: cx(1),
512
+ borderStyle: 'dashed',
513
+ borderColor: '#666',
514
+ backgroundColor: '#f6f6f6',
515
+ },
516
+ deleteBtn: {
517
+ width: '100%',
518
+ height: cx(50),
519
+ backgroundColor: '#666',
520
+ borderRadius: cx(8),
521
+ },
522
+ deleteBtnText: {
523
+ color: '#fff',
524
+ fontSize: cx(16),
525
+ fontFamily: 'helvetica_neue_lt_std_bd',
268
526
  },
269
527
  })
270
-
271
- export default MoodPage
528
+ export default DynamicMoodEditorPage
529
+ export function getTransitionModeString(transitionMode: SceneNodeTransitionMode): string {
530
+ if (transitionMode === SceneNodeTransitionMode.Jump) {
531
+ return Strings.getLang('other_lights_modes_jump_text')
532
+ }
533
+ return Strings.getLang('other_lights_modes_gradient_text')
534
+ }
535
+ export function createSelectPageData(transitionMode: SceneNodeTransitionMode, mode: SceneNodeTransitionMode): SelectPageData<SceneNodeTransitionMode> {
536
+ return {
537
+ text: getTransitionModeString(mode),
538
+ selected: transitionMode === mode,
539
+ value: mode,
540
+ }
541
+ }
@@ -102,15 +102,27 @@ const StaticMoodEditorPage = () => {
102
102
  )
103
103
  if (saveRes.success) {
104
104
  if (list.length > 0) {
105
- const setSceneRes = await setScene(
106
- deviceId,
107
- currentMood.id === moodId && isDelete ? list[0] : currentMood,
108
- moduleParams.sceneDpCode,
109
- moduleParams.workModeDpCode,
110
- moduleParams.switchLedDpCode,
111
- !!moduleParams.isFanLamp
112
- )
113
- console.log('设置修改后的场景结果', setSceneRes)
105
+ if (isDelete && currentMood.id === moodId) {
106
+ const setSceneRes = await setScene(
107
+ deviceId,
108
+ list[0],
109
+ moduleParams.sceneDpCode,
110
+ moduleParams.workModeDpCode,
111
+ moduleParams.switchLedDpCode,
112
+ !!moduleParams.isFanLamp
113
+ )
114
+ console.log('设置修改后的场景结果', setSceneRes)
115
+ } else if (!isDelete) {
116
+ const setSceneRes = await setScene(
117
+ deviceId,
118
+ currentMood,
119
+ moduleParams.sceneDpCode,
120
+ moduleParams.workModeDpCode,
121
+ moduleParams.switchLedDpCode,
122
+ !!moduleParams.isFanLamp
123
+ )
124
+ console.log('设置修改后的场景结果', setSceneRes)
125
+ }
114
126
  } else {
115
127
  await setWorkMode(moduleParams.isOnlyRGBLamp ? COLOUR : WHITE)
116
128
  console.log('Mood被清空,将work_mode设置成white')
@@ -8,163 +8,163 @@ const wakeUpPlanFeatureId = 'WakeUpPlan'
8
8
  // 接口失败重试
9
9
  let retryNumber = 0
10
10
  const putFeatureFn = async (devId, featureId, data) => {
11
- let status;
12
- await putFeature(devId, featureId, data).then(res => {
13
- if (!res?.result && retryNumber < 3) {
14
- retryNumber += 1
15
- putFeatureFn(devId, featureId, data).then()
16
- }
17
- if (res?.result) {
18
- retryNumber = 0
19
- status = res?.result
20
- }
21
- })
22
- return status
11
+ let status;
12
+ await putFeature(devId, featureId, data).then(res => {
13
+ if (!res?.result && retryNumber < 3) {
14
+ retryNumber += 1
15
+ putFeatureFn(devId, featureId, data).then()
16
+ }
17
+ if (res?.result) {
18
+ retryNumber = 0
19
+ status = res?.result
20
+ }
21
+ })
22
+ return status
23
23
  }
24
24
 
25
25
  export const useSleepPlan = (dpCodes: Record<string, string>) => {
26
- const deviceId = useDeviceId()
27
- const [uiData, setUiData] = useState([] as any)
28
- const [sleepPlan, setSleepPlan]:any = useDp(dpCodes.sleep_mode);
29
- // 获取云端数据
30
- useEffect(() => {
31
- getFeature(deviceId, sleepPlanFeatureId).then(res => {
32
- if (res?.result) {
33
- const data = res?.data
34
- let list = data?.map(item => { return { ...item, startTime: (item?.startTime || item?.v) && JSON.parse(item?.startTime || item?.v)?.dp || '' } })
35
- // 首次进入同步云端数据 (云端无数据)
36
- if (!list) {
37
- list = decodeSleepString(sleepPlan)
38
- setSleepCloudData(list, deviceId).then()
39
- setUiData(list)
40
- return
41
- }
42
- const dpData = decodeSleepString(sleepPlan)
43
- const sleepCloudData = highInTheCloudsSleepString(list)
44
- // 更新
45
- if (sleepCloudData?.length === dpData?.length) {
46
- const list = dpData?.map((item, index) => {
47
- return { ...item, name: sleepCloudData[index]?.name }
48
- })
49
- setSleepCloudData(list, deviceId).then()
50
- setUiData(list)
51
- return
52
- }
53
- setUiData(highInTheCloudsSleepString(list))
54
- }
55
- })
56
- }, [sleepPlan])
57
-
58
- const setSleepList = async (sleepPlan: any[]) =>{
59
- const sleepData = sleepPlan.map(item => ({
60
- name: item.name,
61
- startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
62
- }))
63
- let res
64
- const setCloudStatus = await putFeatureFn(deviceId, sleepPlanFeatureId, sleepData)
65
- if(setCloudStatus){
66
- const hex = encodeSleep(sleepPlan)
67
- res = await setSleepPlan(hex)
26
+ const deviceId = useDeviceId()
27
+ const [uiData, setUiData] = useState([] as any)
28
+ const [sleepPlan, setSleepPlan]: any = useDp(dpCodes.sleep_mode);
29
+ // 获取云端数据
30
+ useEffect(() => {
31
+ getFeature(deviceId, sleepPlanFeatureId).then(res => {
32
+ if (res?.result) {
33
+ const data = res?.data
34
+ let list = data?.map(item => { return { ...item, startTime: (item?.startTime || item?.v) && JSON.parse(item?.startTime || item?.v)?.dp || '' } })
35
+ // 首次进入同步云端数据 (云端无数据)
36
+ if (!list) {
37
+ list = decodeSleepString(sleepPlan)
38
+ setSleepCloudData(list, deviceId).then()
39
+ setUiData(list)
40
+ return
68
41
  }
69
- if (res && res?.result) {
70
- /// success
71
- return {
72
- result: { success: true },
73
- // dps: { [dpCodes.wakeup_mode]: hex },
74
- }
75
- } else {
76
- /// failure
77
- return {
78
- result: { success: false },
79
- }
42
+ const dpData = decodeSleepString(sleepPlan)
43
+ const sleepCloudData = highInTheCloudsSleepString(list)
44
+ // 更新
45
+ if (sleepCloudData?.length === dpData?.length) {
46
+ const list = dpData?.map((item, index) => {
47
+ return { ...item, name: sleepCloudData[index]?.name }
48
+ })
49
+ setSleepCloudData(list, deviceId).then()
50
+ setUiData(list)
51
+ return
80
52
  }
53
+ setUiData(highInTheCloudsSleepString(list))
54
+ }
55
+ })
56
+ }, [sleepPlan])
57
+
58
+ const setSleepList = async (sleepPlan: any[]) => {
59
+ const sleepData = sleepPlan.map(item => ({
60
+ name: item.name,
61
+ startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
62
+ }))
63
+ let res
64
+ const setCloudStatus = await putFeatureFn(deviceId, sleepPlanFeatureId, sleepData)
65
+ if (setCloudStatus) {
66
+ const hex = encodeSleep(sleepPlan)
67
+ res = await setSleepPlan(hex)
68
+ }
69
+ if (res && res?.result) {
70
+ /// success
71
+ return {
72
+ result: { success: true },
73
+ // dps: { [dpCodes.wakeup_mode]: hex },
74
+ }
75
+ } else {
76
+ /// failure
77
+ return {
78
+ result: { success: false },
79
+ }
81
80
  }
81
+ }
82
82
 
83
- return [uiData, setSleepList];
83
+ return [uiData, setSleepList];
84
84
  }
85
85
 
86
86
  export const useWakeUpPlan = (dpCodes: Record<string, string>) => {
87
- const deviceId = useDeviceId()
88
- const [uiData, setUiData] = useState([] as any)
89
- const [wakeUpPlan, setWakeUpPlan]:any = useDp(dpCodes.wakeup_mode)
90
- // 获取云端数据
91
- useEffect(() => {
92
- getFeature(deviceId, wakeUpPlanFeatureId).then(res => {
93
- if (res?.result) {
94
- const data = res?.data
95
- let list = data?.map(item => { return { ...item, startTime: (item?.startTime || item?.v) && JSON.parse(item?.startTime || item?.v)?.dp || '' } })
96
- // 首次进入同步云端数据 (云端无数据)
97
- if (!list) {
98
- list = decodeWakeUpString(wakeUpPlan)
99
- setWakeCloudData(list, deviceId).then()
100
- setUiData(list)
101
- return
102
- }
103
- const dpData = decodeWakeUpString(wakeUpPlan)
104
- const wakeCloudData = highInTheCloudsWakeString(list)
105
- // 更新
106
- if (wakeCloudData?.length === dpData?.length) {
107
- const list = dpData?.map((item, index) => {
108
- return { ...item, name: wakeCloudData[index]?.name }
109
- })
110
- setWakeCloudData(list, deviceId).then()
111
- setUiData(list)
112
- return
113
- }
114
- setUiData(highInTheCloudsWakeString(list))
115
- }
116
- })
117
- }, [wakeUpPlan])
118
-
119
- const setWakeUpList = async (wakeUpPlan) =>{
120
- const wakeUpData = wakeUpPlan.map(item => ({
121
- name: item.name,
122
- startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
123
- }))
124
- let res:any
125
- const setCloudStatus = await putFeatureFn(deviceId, wakeUpPlanFeatureId, wakeUpData)
126
- if(setCloudStatus){
127
- const hex = encodeWakeUp(wakeUpPlan)
128
- res = await setWakeUpPlan(hex)
87
+ const deviceId = useDeviceId()
88
+ const [uiData, setUiData] = useState([] as any)
89
+ const [wakeUpPlan, setWakeUpPlan]: any = useDp(dpCodes.wakeup_mode)
90
+ // 获取云端数据
91
+ useEffect(() => {
92
+ getFeature(deviceId, wakeUpPlanFeatureId).then(res => {
93
+ if (res?.result) {
94
+ const data = res?.data
95
+ let list = data?.map(item => { return { ...item, startTime: (item?.startTime || item?.v) && JSON.parse(item?.startTime || item?.v)?.dp || '' } })
96
+ // 首次进入同步云端数据 (云端无数据)
97
+ if (!list) {
98
+ list = decodeWakeUpString(wakeUpPlan)
99
+ setWakeCloudData(list, deviceId).then()
100
+ setUiData(list)
101
+ return
129
102
  }
130
- if (res && res?.result) {
131
- /// success
132
- return {
133
- result: { success: true },
134
- // dps: { [dpCodes.wakeup_mode]: hex },
135
- }
136
- } else {
137
- /// failure
138
- return {
139
- result: { success: false },
140
- }
103
+ const dpData = decodeWakeUpString(wakeUpPlan)
104
+ const wakeCloudData = highInTheCloudsWakeString(list)
105
+ // 更新
106
+ if (wakeCloudData?.length === dpData?.length) {
107
+ const list = dpData?.map((item, index) => {
108
+ return { ...item, name: wakeCloudData[index]?.name }
109
+ })
110
+ setWakeCloudData(list, deviceId).then()
111
+ setUiData(list)
112
+ return
141
113
  }
114
+ setUiData(highInTheCloudsWakeString(list))
115
+ }
116
+ })
117
+ }, [wakeUpPlan])
118
+
119
+ const setWakeUpList = async (wakeUpPlan) => {
120
+ const wakeUpData = wakeUpPlan.map(item => ({
121
+ name: item.name,
122
+ startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
123
+ }))
124
+ let res: any
125
+ const setCloudStatus = await putFeatureFn(deviceId, wakeUpPlanFeatureId, wakeUpData)
126
+ if (setCloudStatus) {
127
+ const hex = encodeWakeUp(wakeUpPlan)
128
+ res = await setWakeUpPlan(hex)
129
+ }
130
+ if (res && res?.result) {
131
+ /// success
132
+ return {
133
+ result: { success: true },
134
+ // dps: { [dpCodes.wakeup_mode]: hex },
135
+ }
136
+ } else {
137
+ /// failure
138
+ return {
139
+ result: { success: false },
140
+ }
142
141
  }
143
- return [uiData, setWakeUpList];
142
+ }
143
+ return [uiData, setWakeUpList];
144
144
  }
145
145
 
146
146
  // 设置云端数据 wakeUp
147
147
  const setWakeCloudData = async (list, devId) => {
148
- const listData: any = []
149
- list?.forEach(item => {
150
- listData?.push({
151
- name: item?.name,
152
- startTime: JSON.stringify({ dp: encodeSingleWakeUpPlan(item) })
153
- })
148
+ const listData: any = []
149
+ list?.forEach(item => {
150
+ listData?.push({
151
+ name: item?.name,
152
+ startTime: JSON.stringify({ dp: encodeSingleWakeUpPlan(item) })
154
153
  })
155
- const res = await putFeatureFn(devId, wakeUpPlanFeatureId, listData)
156
- return res
154
+ })
155
+ const res = await putFeatureFn(devId, wakeUpPlanFeatureId, listData)
156
+ return res
157
157
  }
158
158
 
159
159
  // 设置云端数据 sleep
160
160
  const setSleepCloudData = async (list, devId) => {
161
- const listData: any = []
162
- list.forEach(item => {
163
- listData?.push({
164
- name: item?.name,
165
- startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
166
- })
161
+ const listData: any = []
162
+ list.forEach(item => {
163
+ listData?.push({
164
+ name: item?.name,
165
+ startTime: JSON.stringify({ dp: encodeSingleSleepPlan(item) })
167
166
  })
168
- const res = await putFeatureFn(devId, sleepPlanFeatureId, listData)
169
- return res
167
+ })
168
+ const res = await putFeatureFn(devId, sleepPlanFeatureId, listData)
169
+ return res
170
170
  }
@@ -492,7 +492,10 @@ const SleepWakeUpDetailPage = () => {
492
492
  </View>
493
493
  }
494
494
  </View>
495
- <Text style={{ fontSize: cx(12), color: '#000000' }}>{I18n.getLang(state.durationStatus ? 'feature_summary_action_txt_12' : 'feature_summary_action_txt_1')}</Text>
495
+ <Text style={{ fontSize: cx(12), color: '#000000' }}>{I18n.getLang(
496
+ props.isSleep ? 'feature_summary_action_txt_2' :
497
+ (state.durationStatus ? 'feature_summary_action_txt_12' : 'feature_summary_action_txt_1')
498
+ )}</Text>
496
499
  <View style={styles.filletCorner}>
497
500
  <Text style={styles.rightTitle}>{formateDurationTime().endTime}</Text>
498
501
  </View>
@@ -97,7 +97,6 @@ export function encodeSingleSleepPlan(item) {
97
97
 
98
98
  const brightnessHex = getBrightnessHex(item.brightness)
99
99
  const temperatureHex = getTemperatureHex(item.temperature)
100
-
101
100
  let hex = enableHex + loopHex + fadeHex + timeHex + colorHex + satHex + valueHex + brightnessHex + temperatureHex
102
101
 
103
102
  return hex