@ledvance/ui-biz-bundle 1.1.6 → 1.1.7

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.1.6",
7
+ "version": "1.1.7",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -0,0 +1,205 @@
1
+ import { useDps } from "@ledvance/base/src/models/modules/NativePropsSlice";
2
+ import { FlagPageProps } from "./FlagPage";
3
+ import { SceneNodeTransitionMode } from "@ledvance/ui-biz-bundle/src/modules/scene/SceneInfo";
4
+ import { WORK_MODE, parseJSON } from "@tuya/tuya-panel-lamp-sdk/lib/utils";
5
+ import { cloneDeep } from "lodash";
6
+ import { FlagItemInfo, FlagUiInfo, defFlagList } from "./FlagInfo";
7
+ import { hex2Int } from "@ledvance/base/src/utils/common";
8
+ import { spliceByStep } from "@ledvance/base/src/utils/common";
9
+ import { useMemo, useState } from "react";
10
+ import { useUpdateEffect } from "ahooks";
11
+ import { NativeApi } from "@ledvance/base/src/api/native";
12
+ import { hsv2Hex } from "@ledvance/base/src/utils";
13
+
14
+ export interface ExtraParams extends FlagPageProps, FlagOption {
15
+ }
16
+ interface FlagState {
17
+ id?: number
18
+ colors?: string[]
19
+ }
20
+ const featureId = 'Flag_data'
21
+
22
+ type UseFlagType = (flagCode: string, extra: ExtraParams) => [FlagState, (flagItem: FlagItemInfo) => Promise<any>]
23
+
24
+ export const useFlag: UseFlagType = (flagCode, extra) => {
25
+ const [dps, setDps] = useDps()
26
+ const dp = dps[flagCode]
27
+ const memoId = useMemo(() => {
28
+ if (extra.drawToolLight) {
29
+ return {
30
+ colors: extra.drawToolLight.drawToolDp2Obj(dp)
31
+ }
32
+ }
33
+ return {
34
+ id: dp2Obj(dp, extra)?.id
35
+ }
36
+ }, [])
37
+ const [flagState, setFlagState] = useState(memoId)
38
+
39
+ useUpdateEffect(() => {
40
+ if (extra.drawToolLight) {
41
+ setFlagState({
42
+ colors: extra.drawToolLight.drawToolDp2Obj(dp)
43
+ })
44
+ } else {
45
+ setFlagState({
46
+ id: dp2Obj(dp, extra)?.id
47
+ })
48
+ }
49
+ }, [dp])
50
+
51
+
52
+ const setFlagFn = (flagItem: FlagItemInfo) => {
53
+ if (extra.drawToolLight) {
54
+ const hex = extra.drawToolLight.drawToolObj2dp(flagItem.colors.map(item => hsv2Hex(item.h, item.s, item.v)))
55
+ return setDps({ [flagCode]: hex })
56
+ } else {
57
+ const hex = obj2Dp(flagItem, extra)
58
+ return setDps({ [flagCode]: hex, [extra.workModeCode]: WORK_MODE.SCENE })
59
+ }
60
+ }
61
+ return [flagState, setFlagFn]
62
+ }
63
+
64
+ export interface FlagOption {
65
+ isFan?: boolean
66
+ isUVCFan?: boolean
67
+ isMixLight?: boolean
68
+ workModeCode: string
69
+ }
70
+
71
+ export function obj2Dp(flagItem: FlagItemInfo, option?: FlagOption): string {
72
+ let fanEnableHex = ''
73
+ let fanSpeedHex = ''
74
+ const version = '00'
75
+ const idHex = flagItem.id.toString(16).padStart(2, '0')
76
+ if (option?.isMixLight) {
77
+ const whiteEnable = '01'
78
+ const whiteNum = '01'
79
+ const whiteStatus = '02'
80
+ const whiteHex = whiteEnable + whiteNum + whiteStatus + flagItem.whiteColors.map(colors => {
81
+ const speed = '00'
82
+ const mode = '00'
83
+ const bHex = (colors.brightness * 10).toString(16).padStart(4, '0')
84
+ const tHex = (colors.colorTemp * 10).toString(16).padStart(4, '0')
85
+ return speed + speed + mode + bHex + tHex
86
+ }).join('')
87
+ const colorEnable = '01'
88
+ const colorNum = flagItem.colors.length.toString(16).padStart(2, '0')
89
+ const colorStatus = '03'
90
+ const colorHex = colorEnable + colorNum + colorStatus + flagItem.colors.map(item => {
91
+ const speed = flagItem.speed.toString(16).padStart(2, '0')
92
+ const mode = flagItem.mode.toString(16).padStart(2, '0')
93
+ const hHex = item.h.toString(16).padStart(4, '0')
94
+ const sHex = (item.s * 10).toString(16).padStart(4, '0')
95
+ const vHex = (item.v * 10).toString(16).padStart(4, '0')
96
+ return speed + speed + mode + hHex + sHex + vHex
97
+ }).join('')
98
+ return version + idHex + whiteHex + colorHex
99
+ } else {
100
+ if (option?.isFan) {
101
+ fanEnableHex = (flagItem.fanEnable ? 1 : 0).toString(16).padStart(2, '0')
102
+ fanSpeedHex = (flagItem.fanSpeed || 1).toString(16).padStart(2, '0')
103
+ }
104
+ const switchingIntervalHex = (option?.isUVCFan ? 101 - flagItem.speed : flagItem.speed).toString(16).padStart(2, '0')
105
+ const transitionTimeHex = (option?.isUVCFan ? 101 - flagItem.speed : flagItem.speed).toString(16).padStart(2, '0')
106
+ const transitionModeHex = flagItem.mode.toString(16).padStart(2, '0')
107
+ const hex = idHex + fanEnableHex + fanSpeedHex + flagItem.colors.map(color => {
108
+ const hHex = Math.round(color.h).toString(16).padStart(4, '0')
109
+ const sHex = Math.round(color.s * 10).toString(16).padStart(4, '0')
110
+ const vHex = Math.round(color.v * 10).toString(16).padStart(4, '0')
111
+ const brightnessHex = '0000'
112
+ const colorTempHex = '0000'
113
+ return switchingIntervalHex + transitionTimeHex + transitionModeHex + hHex + sHex + vHex + brightnessHex + colorTempHex
114
+ }).join('')
115
+ return hex
116
+ }
117
+ }
118
+
119
+ export function dp2Obj(dp: string, option?: FlagOption): FlagItemInfo | undefined {
120
+ if (!dp) return
121
+ const result = {} as FlagItemInfo
122
+ if (option?.isMixLight) {
123
+ result.version = hex2Int(dp.slice(0, 2))
124
+ result.id = hex2Int(dp.slice(2, 4))
125
+ let lampHex = dp.slice(16)
126
+ result.whiteColors = [
127
+ { brightness: hex2Int(lampHex.slice(0, 4)) / 10, colorTemp: hex2Int(lampHex.slice(4, 8)) / 10 }
128
+ ]
129
+ lampHex = lampHex.slice(14)
130
+ result.colors = spliceByStep(lampHex, 18).map(lamp => {
131
+ result.speed = hex2Int(lamp.slice(0, 2))
132
+ result.mode = hex2Int(lamp.slice(4, 6))
133
+ return {
134
+ h: hex2Int(lamp.slice(6, 10)),
135
+ s: hex2Int(lamp.slice(10, 14)) / 10,
136
+ v: hex2Int(lamp.slice(14, 18)) / 10
137
+ }
138
+ })
139
+ return result
140
+ } else {
141
+ const id = hex2Int(dp.slice(0, 2))
142
+ let fanEnable: any = undefined
143
+ let fanSpeed: any = undefined
144
+ if (option?.isFan) {
145
+ fanEnable = hex2Int(dp.slice(2, 4)) === 1
146
+ fanSpeed = hex2Int(dp.slice(4, 6))
147
+ }
148
+ const c = option?.isFan ? 6 : 2
149
+ const sliceDp = dp.slice(c)
150
+ let mode = SceneNodeTransitionMode.Jump
151
+ let speed = 70
152
+ const colors = spliceByStep(sliceDp, 26).map(nodeHex => {
153
+ speed = option?.isUVCFan ? 101 - hex2Int(nodeHex.slice(0, 2)) : hex2Int(nodeHex.slice(0, 2))
154
+ mode = hex2Int(nodeHex.slice(4, 6))
155
+ const h = hex2Int(nodeHex.slice(6, 10))
156
+ const s = hex2Int(nodeHex.slice(10, 14))
157
+ const v = hex2Int(nodeHex.slice(14, 18))
158
+ return {
159
+ h,
160
+ s: s / 10,
161
+ v: v / 10
162
+ }
163
+ })
164
+ const whiteColors = [{ brightness: 100, colorTemp: 0 }]
165
+ return {
166
+ id,
167
+ mode,
168
+ speed,
169
+ fanEnable,
170
+ fanSpeed,
171
+ colors,
172
+ whiteColors
173
+ }
174
+ }
175
+
176
+ }
177
+
178
+
179
+ export async function getRemoteFlag(devId: string) {
180
+ const res = await NativeApi.getJson(devId, featureId)
181
+ const isNormalData = Array.isArray(parseJSON(res?.data))
182
+ if (res.success && isNormalData) {
183
+ return {
184
+ success: true,
185
+ data: JSON.parse(res.data)
186
+ }
187
+ } else {
188
+ if (res.msg?.includes('资源未找到') || !isNormalData) {
189
+ const res = await NativeApi.putJson(devId, featureId, JSON.stringify(defFlagList))
190
+ if (res.success) {
191
+ return {
192
+ success: true,
193
+ data: cloneDeep(defFlagList)
194
+ }
195
+ }
196
+ return { success: false }
197
+ }
198
+ return { success: false }
199
+ }
200
+ }
201
+
202
+ export function saveFlag(devId: string, flagInfo: FlagUiInfo[]) {
203
+ return NativeApi.putJson(devId, featureId, JSON.stringify(flagInfo))
204
+ }
205
+
@@ -0,0 +1,432 @@
1
+ import React, { useCallback, useEffect, useMemo } from 'react'
2
+ import I18n from '@ledvance/base/src/i18n'
3
+ import { useNavigation, useRoute } from '@react-navigation/native'
4
+ import Page from '@ledvance/base/src/components/Page'
5
+ import res from '@ledvance/base/src/res'
6
+ import { ScrollView, View, FlatList, StyleSheet, Image, TouchableOpacity, Text } from 'react-native'
7
+ import Spacer from '@ledvance/base/src/components/Spacer'
8
+ import { useReactive } from 'ahooks'
9
+ import { Utils } from 'tuya-panel-kit'
10
+ import TextField from '@ledvance/base/src/components/TextField'
11
+ import Card from '@ledvance/base/src/components/Card'
12
+ import LdvSlider from '@ledvance/base/src/components/ldvSlider'
13
+ import TextButton from '@ledvance/base/src/components/TextButton'
14
+ import { hex2Hsv, hsv2Hex, mapFloatToRange } from '@ledvance/base/src/utils'
15
+ import { cloneDeep, find, isEqual } from 'lodash'
16
+ import { FlagUiInfo } from './FlagInfo'
17
+ import ColorAdjustView from '@ledvance/base/src/components/ColorAdjustView'
18
+ import { Result } from '@ledvance/base/src/models/modules/Result'
19
+ import { FlagOption } from './FlagActions'
20
+ import { FlagPageProps } from './FlagPage'
21
+ import ColorTempAdjustView from '@ledvance/base/src/components/ColorTempAdjustView'
22
+ import { showDialog } from '@ledvance/base/src/utils/common'
23
+ import { cctToColor } from '@ledvance/base/src/utils/cctUtils'
24
+
25
+ const cx = Utils.RatioUtils.convertX
26
+
27
+ export interface FlagEditParams {
28
+ mode: 'add' | 'edit'
29
+ currentMood: FlagUiInfo
30
+ moods: FlagUiInfo[]
31
+ moduleParams: FlagPageProps
32
+ modDeleteFlag: (mode: 'add' | 'edit' | 'del', currentMood: FlagUiInfo, options?: FlagOption) => Promise<Result<any>>
33
+ }
34
+
35
+ const FlagEditPage = () => {
36
+ const navigation = useNavigation()
37
+ const params = cloneDeep(useRoute().params as FlagEditParams)
38
+ const state = useReactive({
39
+ showAddMoodPopover: true,
40
+ mood: params.currentMood,
41
+ currentWhiteNode: params.currentMood.whiteColors[params.currentMood.whiteColors.length - 1]!,
42
+ currentNode: params.currentMood.colors[params.currentMood.colors.length - 1],
43
+ whitePaintBucketIdx: params.currentMood.colors.length - 1,
44
+ colorPaintBucketIdx: params.currentMood.colors.length - 1,
45
+ whitePaintBucketSelected: true,
46
+ colorPaintBucketSelected: false,
47
+ loading: false
48
+ })
49
+ useEffect(() => {
50
+ }, [])
51
+
52
+ const getButtonStatus = () => {
53
+ return (params.mode === 'edit' && isEqual(state.mood, params.currentMood)) ||
54
+ !(!!state.mood.name) ||
55
+ nameRepeat ||
56
+ state.mood.name.length > 32
57
+ }
58
+
59
+ const getColorBlockColor = useCallback((isMainLight?: boolean) => {
60
+ if(isMainLight){
61
+ return cctToColor(state.currentWhiteNode.colorTemp, Math.max(...[state.currentWhiteNode.brightness, 50]))
62
+ }
63
+ const s = Math.round(mapFloatToRange(state.currentNode.s / 100, 30, 100))
64
+ return hsv2Hex(state.currentNode.h, s, 100)
65
+ }, [state.currentNode, state.currentWhiteNode])
66
+
67
+ const nameRepeat = useMemo(() => {
68
+ return !!find(params.moods, m => (m.id !== state.mood.id && m.name === state.mood.name))
69
+ }, [state.mood.name])
70
+
71
+ return (
72
+ <Page
73
+ backText={I18n.getLang('mesh_device_detail_mode')}
74
+ showBackDialog={true}
75
+ backDialogTitle={
76
+ I18n.getLang(params.mode === 'add' ?
77
+ 'flag_canceladding' :
78
+ 'flag_canceledit')
79
+ }
80
+ backDialogContent={
81
+ I18n.getLang('flag_cancelinfo')
82
+ }
83
+ headlineText={I18n.getLang(params.mode === 'add' ? 'flag_addanewflag' : 'flag_edittheflag')}
84
+ rightButtonIcon={getButtonStatus() ? res.ic_uncheck : res.ic_check}
85
+ rightButtonDisabled={getButtonStatus()}
86
+ rightButtonIconClick={async () => {
87
+ if (state.loading) return
88
+ state.loading = true
89
+ const res = await params.modDeleteFlag(params.mode, state.mood)
90
+ console.log(res, '< --- resss')
91
+ if (res.success) {
92
+ state.loading = false
93
+ navigation.goBack()
94
+ }
95
+ }}>
96
+ <ScrollView
97
+ style={{ flex: 1 }}
98
+ nestedScrollEnabled={true}>
99
+ <View style={styles.root}>
100
+ <TextField
101
+ style={styles.name}
102
+ value={state.mood.name}
103
+ placeholder={I18n.getLang('edit_static_mood_inputfield_topic_text')}
104
+ onChangeText={text => {
105
+ state.mood.name = text
106
+ }}
107
+ maxLength={33}
108
+ showError={state.mood.name.length > 32 || nameRepeat}
109
+ tipColor={nameRepeat ? '#f00' : undefined}
110
+ tipIcon={nameRepeat ? res.ic_text_field_input_error : undefined}
111
+ errorText={I18n.getLang(nameRepeat ? 'string_light_pp_field_sm_add_error1' : 'add_new_dynamic_mood_alert_text')} />
112
+ {params.moduleParams.isSupportMixScene && <><Card style={styles.adjustCard}>
113
+ <Spacer height={cx(16)} />
114
+ <View style={styles.lightLine}>
115
+ <Text style={styles.light}>
116
+ {I18n.getLang('light_sources_tile_main_lighting_headline')}
117
+ </Text>
118
+ <View style={[styles.preview, { backgroundColor: getColorBlockColor(true) }]} />
119
+ </View>
120
+ <Spacer />
121
+ <ColorTempAdjustView
122
+ isSupportBrightness={!!params.moduleParams.isSupportTemperature}
123
+ isSupportTemperature={!!params.moduleParams.isSupportTemperature}
124
+ colorTemp={state.currentWhiteNode.colorTemp}
125
+ brightness={state.currentWhiteNode.brightness}
126
+ onCCTChange={(cct) => {
127
+ state.currentWhiteNode.colorTemp = cct
128
+ }}
129
+ onCCTChangeComplete={(cct) => {
130
+ state.currentWhiteNode.colorTemp = cct
131
+ state.mood.whiteColors = state.mood.whiteColors.map((item, idx) => {
132
+ if (idx === state.whitePaintBucketIdx) {
133
+ return {
134
+ ...state.mood.whiteColors[idx],
135
+ colorTemp: cct
136
+ }
137
+ }
138
+ return item
139
+ })
140
+ }}
141
+ onBrightnessChange={() => { }}
142
+ onBrightnessChangeComplete={(bright) => {
143
+ state.currentWhiteNode.brightness = bright
144
+ state.mood.whiteColors = state.mood.whiteColors.map((item, idx) => {
145
+ if (idx === state.whitePaintBucketIdx) {
146
+ return {
147
+ ...state.mood.whiteColors[idx],
148
+ brightness: bright
149
+ }
150
+ }
151
+ return item
152
+ })
153
+ }}
154
+ />
155
+ <Spacer height={cx(16)} />
156
+ </Card>
157
+ <Spacer />
158
+ </>}
159
+ <Card style={styles.adjustCard}>
160
+ <Spacer height={cx(16)} />
161
+ <View style={styles.lightLine}>
162
+ <Text style={styles.light}>
163
+ {I18n.getLang(params.moduleParams.isSupportMixScene ? 'light_sources_tile_sec_lighting_headline' : 'light_sources_tile_tw_lighting_headline')}
164
+ </Text>
165
+ <View style={[styles.preview, { backgroundColor: getColorBlockColor() }]} />
166
+ </View>
167
+ <Spacer height={cx(10)} />
168
+ <LdvSlider
169
+ title={I18n.getLang('add_new_dynamic_mood_lights_field_speed_topic_text')}
170
+ value={state.mood.speed}
171
+ onValueChange={value => {
172
+ state.mood.speed = value
173
+ }}
174
+ onSlidingComplete={value => {
175
+ state.mood.speed = value
176
+ }} />
177
+ <Spacer height={cx(16)} />
178
+ <View style={styles.nodesAdjust}>
179
+ <View style={styles.adjustButtons}>
180
+ <TouchableOpacity
181
+ onPress={() => {
182
+ state.colorPaintBucketSelected = true
183
+ }}>
184
+ <Image
185
+ style={[styles.adjustButton, { tintColor: state.colorPaintBucketSelected ? '#f60' : '#666' }]}
186
+ source={res.ic_paint_bucket} />
187
+ </TouchableOpacity>
188
+ <TouchableOpacity
189
+ onPress={() => {
190
+ state.colorPaintBucketSelected = false
191
+ }}>
192
+ <Image
193
+ style={[styles.adjustButton, { tintColor: state.colorPaintBucketSelected ? '#666' : '#f60' }]}
194
+ source={res.ic_colorize} />
195
+ </TouchableOpacity>
196
+ </View>
197
+ <FlatList
198
+ data={state.mood.colors}
199
+ style={styles.nodeList}
200
+ renderItem={({ item, index }) => {
201
+ return (
202
+ <View style={styles.nodeItem}>
203
+ <TouchableOpacity
204
+ style={[
205
+ styles.nodeBlock,
206
+ {
207
+ backgroundColor: hsv2Hex(item.h, item.s, item.v),
208
+ },
209
+ ]}
210
+ onPress={() => {
211
+ state.currentNode = item
212
+ state.colorPaintBucketIdx = index
213
+ }} />
214
+ <TouchableOpacity
215
+ style={styles.nodeDeleteBtn}
216
+ disabled={state.mood.colors.length < 3}
217
+ onPress={() => {
218
+ state.mood.colors.splice(index, 1)
219
+ state.currentNode = hex2Hsv(state.mood.colors[state.mood.colors.length - 1])!
220
+ }}>
221
+ <Image
222
+ style={[
223
+ styles.nodeDeleteIcon,
224
+ {
225
+ tintColor: state.mood.colors.length < 3 ? '#ccc' : '#666',
226
+ },
227
+ ]}
228
+ source={res.ic_mood_del} />
229
+ </TouchableOpacity>
230
+ </View>
231
+ )
232
+ }}
233
+ keyExtractor={(_, index) => `${index}`}
234
+ ItemSeparatorComponent={() => <Spacer height={cx(12)} />}
235
+ ListFooterComponent={() => {
236
+ if (state.mood.colors.length >= 8) {
237
+ return (<></>)
238
+ }
239
+ return (
240
+ <View>
241
+ <Spacer height={cx(12)} />
242
+ <TouchableOpacity
243
+ style={styles.nodeAddBtn}
244
+ onPress={() => {
245
+ const node = {
246
+ ...state.currentNode,
247
+ }
248
+ state.mood.colors.push(node)
249
+ state.currentNode = node
250
+ state.colorPaintBucketIdx = state.mood.colors.length - 1
251
+ }}>
252
+ <Image
253
+ style={{
254
+ width: cx(18),
255
+ height: cx(18),
256
+ tintColor: '#000',
257
+ }}
258
+ source={{ uri: res.add }} />
259
+ </TouchableOpacity>
260
+ </View>
261
+ )
262
+ }} />
263
+ </View>
264
+ <Spacer />
265
+ <View style={styles.lightLine}>
266
+ <Text style={styles.light}>
267
+ {I18n.getLang('add_new_dynamic_mood_lights_field_headline2_text')}
268
+ </Text>
269
+ <View style={[styles.preview, { backgroundColor: getColorBlockColor() }]} />
270
+ </View>
271
+ <Spacer />
272
+ <ColorAdjustView
273
+ h={state.currentNode.h}
274
+ s={state.currentNode.s}
275
+ v={state.currentNode.v}
276
+ reserveSV={true}
277
+ onHSVChange={(h, s, v) => {
278
+ if (state.colorPaintBucketSelected) {
279
+ state.mood.colors = state.mood.colors.map(() => (
280
+ { h, s, v }
281
+ ))
282
+ } else {
283
+ state.currentNode.h = h
284
+ state.currentNode.s = s
285
+ state.currentNode.v = v
286
+ }
287
+ }}
288
+ onHSVChangeComplete={(h, s, v) => {
289
+ if (state.colorPaintBucketSelected) {
290
+ state.mood.colors = state.mood.colors.map(() => (
291
+ { h, s, v }
292
+ ))
293
+ } else {
294
+ state.currentNode.h = h
295
+ state.currentNode.s = s
296
+ state.currentNode.v = v
297
+ state.mood.colors = state.mood.colors.map((item, idx) => {
298
+ if (idx === state.colorPaintBucketIdx) {
299
+ return { h, s, v }
300
+ }
301
+ return item
302
+ })
303
+ }
304
+ }}
305
+ />
306
+ <Spacer height={cx(16)} />
307
+ </Card>
308
+ <Spacer />
309
+ {params.mode === 'edit' &&
310
+ <View style={{ marginTop: cx(20), marginHorizontal: cx(24) }}>
311
+ <TextButton
312
+ style={styles.deleteBtn}
313
+ textStyle={styles.deleteBtnText}
314
+ text={I18n.getLang('flag_deleteflag')}
315
+ onPress={() => {
316
+ showDialog({
317
+ method: 'confirm',
318
+ title: I18n.getLang('flag_deletepopup'),
319
+ subTitle: I18n.getLang('strip_light_static_mood_edit_dialog_text'),
320
+ onConfirm: async (_, { close }) => {
321
+ close()
322
+ if (state.loading) return
323
+ state.loading = true
324
+ const res = await params.modDeleteFlag('del', state.mood)
325
+ if (res.success) {
326
+ state.loading = false
327
+ navigation.goBack()
328
+ }
329
+ }
330
+ })
331
+ }} />
332
+ </View>}
333
+ <Spacer />
334
+ </View>
335
+ </ScrollView>
336
+ </Page>
337
+ )
338
+ }
339
+
340
+ const styles = StyleSheet.create({
341
+ root: {
342
+ flex: 1,
343
+ flexDirection: 'column',
344
+ },
345
+ name: {
346
+ marginHorizontal: cx(24),
347
+ },
348
+ adjustCard: {
349
+ marginVertical: cx(12),
350
+ marginHorizontal: cx(24),
351
+ },
352
+ fanAdjustCard: {
353
+ marginHorizontal: cx(24),
354
+ },
355
+ lightLine: {
356
+ flexDirection: 'row',
357
+ marginHorizontal: cx(16),
358
+ },
359
+ light: {
360
+ color: '#000',
361
+ fontSize: cx(18),
362
+ fontFamily: 'helvetica_neue_lt_std_bd',
363
+ },
364
+ transitionMode: {
365
+ marginHorizontal: cx(16),
366
+ },
367
+ preview: {
368
+ width: cx(20),
369
+ height: cx(20),
370
+ marginStart: cx(12),
371
+ borderRadius: cx(4),
372
+ },
373
+ nodesAdjust: {
374
+ flexDirection: 'row',
375
+ alignItems: 'center',
376
+ },
377
+ adjustButtons: {
378
+ width: cx(44),
379
+ marginStart: cx(16),
380
+ },
381
+ adjustButton: {
382
+ width: cx(44),
383
+ height: cx(44),
384
+ },
385
+ nodeList: {
386
+ flex: 1,
387
+ marginHorizontal: cx(16),
388
+ },
389
+ nodeItem: {
390
+ flexDirection: 'row',
391
+ alignItems: 'center',
392
+ },
393
+ nodeBlock: {
394
+ flex: 1,
395
+ height: cx(40),
396
+ borderRadius: cx(8),
397
+ },
398
+ nodeDeleteBtn: {
399
+ width: cx(24),
400
+ height: cx(30),
401
+ justifyContent: 'center',
402
+ alignItems: 'center',
403
+ },
404
+ nodeDeleteIcon: {
405
+ width: cx(16),
406
+ height: cx(16),
407
+ },
408
+ nodeAddBtn: {
409
+ height: cx(40),
410
+ justifyContent: 'center',
411
+ alignItems: 'center',
412
+ marginEnd: cx(26),
413
+ borderRadius: cx(8),
414
+ borderWidth: cx(1),
415
+ borderStyle: 'dashed',
416
+ borderColor: '#666',
417
+ backgroundColor: '#f6f6f6',
418
+ },
419
+ deleteBtn: {
420
+ width: '100%',
421
+ height: cx(50),
422
+ backgroundColor: '#666',
423
+ borderRadius: cx(8),
424
+ },
425
+ deleteBtnText: {
426
+ color: '#fff',
427
+ fontSize: cx(16),
428
+ fontFamily: 'helvetica_neue_lt_std_bd',
429
+ },
430
+ })
431
+
432
+ export default FlagEditPage
@@ -0,0 +1,298 @@
1
+ import I18n from "@ledvance/base/src/i18n";
2
+ import { SceneNodeTransitionMode } from "@ledvance/ui-biz-bundle/src/modules/scene/SceneInfo";
3
+
4
+ type HSV = {
5
+ h: number
6
+ s: number
7
+ v: number
8
+ }
9
+
10
+ type BT = {
11
+ brightness: number
12
+ colorTemp: number
13
+ }
14
+
15
+ export interface FlagItemInfo {
16
+ id: number
17
+ version?: number
18
+ mode: number
19
+ speed: number
20
+ colors: HSV[]
21
+ whiteColors: BT []
22
+ fanEnable?: boolean
23
+ fanSpeed?: number
24
+ }
25
+
26
+ export interface FlagUiInfo extends FlagItemInfo{
27
+ name: string
28
+ }
29
+
30
+ export const defFlagList: FlagUiInfo[] = [
31
+ {
32
+ id: 255,
33
+ version: 0,
34
+ mode: SceneNodeTransitionMode.Jump,
35
+ speed: 70,
36
+ name: I18n.getLang('country_DE'),
37
+ whiteColors: [
38
+ { brightness: 100, colorTemp: 0},
39
+ ],
40
+ colors: [
41
+ {h: 48, s: 100, v: 100},
42
+ {h: 360, s: 100, v: 86},
43
+ {h: 0, s: 0, v:0}],
44
+ },
45
+ {
46
+ id: 254,
47
+ version: 0,
48
+ mode: SceneNodeTransitionMode.Jump,
49
+ speed: 70,
50
+ name: I18n.getLang('country_BE'),
51
+ whiteColors: [
52
+ { brightness: 100, colorTemp: 0},
53
+ ],
54
+ colors: [{h: 350, s: 92, v: 78}, {h: 48, s: 100, v: 100}, {h: 25, s: 15, v: 17}]
55
+ },
56
+ {
57
+ id: 253,
58
+ version: 0,
59
+ mode: SceneNodeTransitionMode.Jump,
60
+ speed: 70,
61
+ name: I18n.getLang('country_FR'),
62
+ whiteColors: [
63
+ { brightness: 100, colorTemp: 0},
64
+ ],
65
+ colors: [{h: 355, s: 82, v: 92}, {h: 0, s: 0, v: 100}, {h: 212, s: 100, v: 32}]
66
+ },
67
+ {
68
+ id: 252,
69
+ version: 0,
70
+ mode: SceneNodeTransitionMode.Jump,
71
+ speed: 70,
72
+ name: I18n.getLang('country_PT'),
73
+ whiteColors: [
74
+ { brightness: 100, colorTemp: 0},
75
+ ],
76
+ colors: [{h: 4, s: 87, v: 85}, {h: 4, s: 87, v: 85}, {h: 150, s: 96, v: 41}]
77
+ },
78
+ {
79
+ id: 251,
80
+ version: 0,
81
+ mode: SceneNodeTransitionMode.Jump,
82
+ speed: 70,
83
+ name: I18n.getLang('country_scotland'),
84
+ whiteColors: [
85
+ { brightness: 100, colorTemp: 0},
86
+ ],
87
+ colors: [{h: 209, s: 100, v: 72}, {h: 0, s: 0, v: 100}, {h: 209, s: 100, v: 72}]
88
+ },
89
+ {
90
+ id: 250,
91
+ version: 0,
92
+ mode: SceneNodeTransitionMode.Jump,
93
+ speed: 70,
94
+ name: I18n.getLang('country_ES'),
95
+ whiteColors: [
96
+ { brightness: 100, colorTemp: 0},
97
+ ],
98
+ colors: [{h: 357, s: 87, v: 66}, {h: 47, s: 100, v: 94}, {h: 357, s: 87, v: 66}]
99
+ },
100
+ {
101
+ id: 249,
102
+ version: 0,
103
+ mode: SceneNodeTransitionMode.Jump,
104
+ speed: 70,
105
+ name: I18n.getLang('country_TR'),
106
+ whiteColors: [
107
+ { brightness: 100, colorTemp: 0},
108
+ ],
109
+ colors: [{h: 350, s: 92, v: 78}, {h: 350, s: 92, v: 78}, {h: 0, s: 0, v: 100}]
110
+ },
111
+ {
112
+ id: 248,
113
+ version: 0,
114
+ mode: SceneNodeTransitionMode.Jump,
115
+ speed: 70,
116
+ name: I18n.getLang('country_AT'),
117
+ whiteColors: [
118
+ { brightness: 100, colorTemp: 0},
119
+ ],
120
+ colors: [{h: 355, s: 78, v: 93}, {h: 0, s: 0, v: 100}, {h: 355, s: 78, v: 93}]
121
+ },
122
+ {
123
+ id: 247,
124
+ version: 0,
125
+ mode: SceneNodeTransitionMode.Jump,
126
+ speed: 70,
127
+ name: I18n.getLang('country_england'),
128
+ whiteColors: [
129
+ { brightness: 100, colorTemp: 0},
130
+ ],
131
+ colors: [{h: 0, s: 0, v: 100}, {h: 353, s: 91, v: 80}, {h: 0, s: 0, v: 100}]
132
+ },
133
+ {
134
+ id: 246,
135
+ version: 0,
136
+ mode: SceneNodeTransitionMode.Jump,
137
+ speed: 70,
138
+ name: I18n.getLang('country_HU'),
139
+ whiteColors: [
140
+ { brightness: 100, colorTemp: 0},
141
+ ],
142
+ colors: [{h: 133, s: 36, v: 43}, {h: 0, s: 0, v: 100}, {h: 354, s: 80, v: 80}]
143
+ },
144
+ {
145
+ id: 245,
146
+ version: 0,
147
+ mode: SceneNodeTransitionMode.Jump,
148
+ speed: 70,
149
+ name: I18n.getLang('country_SK'),
150
+ whiteColors: [
151
+ { brightness: 100, colorTemp: 0},
152
+ ],
153
+ colors: [{h: 357, s: 88, v: 93}, {h: 213, s: 93, v: 63}, {h: 0, s: 0, v: 100}]
154
+ },
155
+ {
156
+ id: 244,
157
+ version: 0,
158
+ mode: SceneNodeTransitionMode.Jump,
159
+ speed: 70,
160
+ name: I18n.getLang('country_AL'),
161
+ whiteColors: [
162
+ { brightness: 100, colorTemp: 0},
163
+ ],
164
+ colors: [{h: 4, s: 87, v: 85}, {h: 0, s: 0, v:0}, {h: 4, s: 87, v: 85}]
165
+ },
166
+ {
167
+ id: 243,
168
+ version: 0,
169
+ mode: SceneNodeTransitionMode.Jump,
170
+ speed: 70,
171
+ name: I18n.getLang('country_DK'),
172
+ whiteColors: [
173
+ { brightness: 100, colorTemp: 0},
174
+ ],
175
+ colors: [{h: 350, s: 92, v: 78}, {h: 0, s: 0, v:0}, {h: 350, s: 92, v: 78}]
176
+ },
177
+ {
178
+ id: 242,
179
+ version: 0,
180
+ mode: SceneNodeTransitionMode.Jump,
181
+ speed: 70,
182
+ name: I18n.getLang('country_NL'),
183
+ whiteColors: [
184
+ { brightness: 100, colorTemp: 0},
185
+ ],
186
+ colors: [{h: 217, s: 100, v: 64}, {h: 0, s: 0, v:0}, {h: 350, s: 92, v: 78}]
187
+ },
188
+ {
189
+ id: 241,
190
+ version: 0,
191
+ mode: SceneNodeTransitionMode.Jump,
192
+ speed: 70,
193
+ name: I18n.getLang('country_RO'),
194
+ whiteColors: [
195
+ { brightness: 100, colorTemp: 0},
196
+ ],
197
+ colors: [{h: 353, s: 91, v: 80}, {h: 48, s: 91, v: 98}, {h: 219, s: 100, v: 49}]
198
+ },
199
+ {
200
+ id: 240,
201
+ version: 0,
202
+ mode: SceneNodeTransitionMode.Jump,
203
+ speed: 70,
204
+ name: I18n.getLang('country_CH'),
205
+ whiteColors: [
206
+ { brightness: 100, colorTemp: 0},
207
+ ],
208
+ colors: [{h: 4, s: 87, v: 85}, {h: 0, s: 0, v: 100}, {h: 4, s: 87, v: 85}]
209
+ },
210
+ {
211
+ id: 239,
212
+ version: 0,
213
+ mode: SceneNodeTransitionMode.Jump,
214
+ speed: 70,
215
+ name: I18n.getLang('country_RS'),
216
+ whiteColors: [
217
+ { brightness: 100, colorTemp: 0},
218
+ ],
219
+ colors: [{h: 0, s: 0, v: 100}, {h: 210, s: 89, v: 46}, {h: 357, s: 72, v: 77}]
220
+ },
221
+ {
222
+ id: 238,
223
+ version: 0,
224
+ mode: SceneNodeTransitionMode.Jump,
225
+ speed: 70,
226
+ name: I18n.getLang('country_IT'),
227
+ whiteColors: [
228
+ { brightness: 100, colorTemp: 0},
229
+ ],
230
+ colors: [{h: 366, s: 83, v: 80}, {h: 212, s: 4, v: 100}, {h: 149, s: 100, v: 54}]
231
+ },
232
+ {
233
+ id: 237,
234
+ version: 0,
235
+ mode: SceneNodeTransitionMode.Jump,
236
+ speed: 70,
237
+ name: I18n.getLang('country_CZ'),
238
+ whiteColors: [
239
+ { brightness: 100, colorTemp: 0},
240
+ ],
241
+ colors: [{h: 358, s: 90, v: 84}, {h: 0, s: 0, v: 100}, {h: 211, s: 86, v: 49}]
242
+ },
243
+ {
244
+ id: 236,
245
+ version: 0,
246
+ mode: SceneNodeTransitionMode.Jump,
247
+ speed: 70,
248
+ name: I18n.getLang('country_SI'),
249
+ whiteColors: [
250
+ { brightness: 100, colorTemp: 0},
251
+ ],
252
+ colors: [{h: 360, s: 100, v: 100}, {h: 217, s: 100, v: 64}, {h: 0, s: 0, v: 100}]
253
+ },
254
+ {
255
+ id: 235,
256
+ version: 0,
257
+ mode: SceneNodeTransitionMode.Jump,
258
+ speed: 70,
259
+ name: I18n.getLang('country_HR'),
260
+ whiteColors: [
261
+ { brightness: 100, colorTemp: 0},
262
+ ],
263
+ colors: [{h: 0, s: 0, v: 100}, {h: 220, s: 89, v: 54}, {h: 2, s: 89, v: 90}]
264
+ },
265
+ {
266
+ id: 234,
267
+ version: 0,
268
+ mode: SceneNodeTransitionMode.Jump,
269
+ speed: 70,
270
+ name: I18n.getLang('country_SE'),
271
+ whiteColors: [
272
+ { brightness: 100, colorTemp: 0},
273
+ ],
274
+ colors: [{h: 201, s: 100, v: 65}, {h: 48, s: 99, v: 99}, {h: 201, s: 100, v: 65}]
275
+ },
276
+ {
277
+ id: 233,
278
+ version: 0,
279
+ mode: SceneNodeTransitionMode.Jump,
280
+ speed: 70,
281
+ name: I18n.getLang('country_NO'),
282
+ whiteColors: [
283
+ { brightness: 100, colorTemp: 0},
284
+ ],
285
+ colors: [{h: 0, s: 0, v: 100}, {h: 218, s: 100, v: 35}, {h: 347, s: 93, v: 72}]
286
+ },
287
+ {
288
+ id: 232,
289
+ version: 0,
290
+ mode: SceneNodeTransitionMode.Jump,
291
+ speed: 70,
292
+ name: I18n.getLang('country_PL'),
293
+ whiteColors: [
294
+ { brightness: 100, colorTemp: 0},
295
+ ],
296
+ colors: [{h: 348, s: 90, v: 86}, {h: 0, s: 0, v: 100}]
297
+ },
298
+ ]
@@ -0,0 +1,84 @@
1
+ import { StyleSheet, View, Text, ViewStyle } from 'react-native'
2
+ import React from 'react'
3
+ import Card from '@ledvance/base/src/components/Card'
4
+ import { SwitchButton, Utils } from 'tuya-panel-kit'
5
+ import MoodColorsLine from '@ledvance/base/src/components/MoodColorsLine'
6
+ import Spacer from '@ledvance/base/src/components/Spacer'
7
+
8
+ const cx = Utils.RatioUtils.convertX
9
+
10
+ interface RecommendMoodItemProps {
11
+ enable: boolean
12
+ title: string
13
+ colors: string[]
14
+ style?: ViewStyle
15
+ onPress?: () => void
16
+ onSwitch: (enable: boolean) => void
17
+ }
18
+
19
+ export default function FlagItem(props: RecommendMoodItemProps) {
20
+ return (
21
+ <Card
22
+ style={[styles.card, props.style]}
23
+ onPress={props.onPress}>
24
+ <View>
25
+ <Spacer height={cx(16)} />
26
+ <View style={styles.headline}>
27
+ <Text style={styles.headText}>{props.title}</Text>
28
+ <SwitchButton
29
+ thumbStyle={{ elevation: 0 }}
30
+ value={props.enable}
31
+ onValueChange={props.onSwitch} />
32
+ </View>
33
+ <Spacer />
34
+ <View style={styles.gradientItem}>
35
+ <MoodColorsLine
36
+ type={'separate'}
37
+ nodeStyle={{ borderColor: '#ccc', borderWidth: 1 }}
38
+ colors={props.colors} />
39
+ </View>
40
+ <Spacer height={cx(16)} />
41
+ </View>
42
+ </Card>
43
+ )
44
+ }
45
+
46
+ const styles = StyleSheet.create({
47
+ card: {
48
+ marginHorizontal: cx(24),
49
+ },
50
+ headline: {
51
+ flexDirection: 'row',
52
+ marginHorizontal: cx(16),
53
+ },
54
+ headText: {
55
+ flex: 1,
56
+ color: '#000',
57
+ fontSize: cx(16),
58
+ fontFamily: 'helvetica_neue_lt_std_bd',
59
+ lineHeight: cx(20),
60
+ },
61
+ gradientItem: {
62
+ alignItems: 'center',
63
+ },
64
+ gradient: {
65
+ borderRadius: cx(8),
66
+ },
67
+ moodTypeItem: {
68
+ flexDirection: 'row',
69
+ },
70
+ moodTypeLabel: {
71
+ marginStart: cx(16),
72
+ paddingHorizontal: cx(12.5),
73
+ backgroundColor: '#E6E7E8',
74
+ borderRadius: cx(8),
75
+ },
76
+ moodTypeLabelText: {
77
+ height: cx(16),
78
+ color: '#000000DD',
79
+ fontSize: cx(10),
80
+ textAlignVertical: 'center',
81
+ fontFamily: 'helvetica_neue_lt_std_roman',
82
+ lineHeight: cx(16),
83
+ },
84
+ })
@@ -0,0 +1,200 @@
1
+ import React, { useEffect, useMemo } from "react";
2
+ import Page from "@ledvance/base/src/components/Page";
3
+ import { useDeviceId, useDeviceInfo } from "@ledvance/base/src/models/modules/NativePropsSlice";
4
+ import { FlatList } from "react-native";
5
+ import Spacer from "@ledvance/base/src/components/Spacer";
6
+ import { Utils } from "tuya-panel-kit";
7
+ import FlagItem from "./FlagItem";
8
+ import { FlagUiInfo } from "./FlagInfo";
9
+ import { getRemoteFlag, saveFlag, useFlag } from "./FlagActions";
10
+ import { useRoute, useNavigation } from '@react-navigation/core'
11
+ import I18n from "@ledvance/base/src/i18n";
12
+ import { useReactive } from "ahooks";
13
+ import { cloneDeep, difference, isEqual, last, map, range } from "lodash";
14
+ import { ui_biz_routerKey} from "../../navigation/Routers";
15
+ import res from "@ledvance/base/src/res";
16
+ import { hsv2Hex } from "@ledvance/base/src/utils";
17
+ import { SceneNodeTransitionMode } from "@ledvance/ui-biz-bundle/src/modules/scene/SceneInfo";
18
+ import { Result } from "@ledvance/base/src/models/modules/Result";
19
+ import { useDps } from "@ledvance/base/src/models/modules/NativePropsSlice";
20
+ import { WORK_MODE } from "@tuya/tuya-panel-lamp-sdk/lib/utils";
21
+ const cx = Utils.RatioUtils.convertX
22
+
23
+ export interface FlagPageProps {
24
+ isSupportColor?: boolean
25
+ isSupportBrightness?: boolean
26
+ isSupportTemperature?: boolean
27
+ isSupportFan?: boolean
28
+ isSupportUVCFan?: boolean
29
+ isSupportMixScene?: boolean
30
+ drawToolLight?: {
31
+ drawToolCode: string
32
+ drawToolObj2dp: (colors: string[]) => string
33
+ drawToolDp2Obj: (dp: string) => string[]
34
+ }
35
+ getRemoteMoodList?: (devId: string) => Promise<Result<any>>
36
+ sceneDataCode?: string
37
+ workModeCode: string
38
+ switchLed?: string
39
+ }
40
+
41
+ const FlagPage = () => {
42
+ const params = useRoute().params as FlagPageProps
43
+ const devInfo = useDeviceInfo()
44
+ const devId = useDeviceId()
45
+ const navigation = useNavigation()
46
+ const [, setDps] = useDps()
47
+ const [flagState, setFlag] = useFlag((params.sceneDataCode || params?.drawToolLight?.drawToolCode)!!, {
48
+ isFan: params.isSupportFan,
49
+ isUVCFan: params.isSupportUVCFan,
50
+ isMixLight: params.isSupportMixScene,
51
+ ...params
52
+ })
53
+ const state = useReactive({
54
+ loading: true,
55
+ flags: [] as FlagUiInfo[],
56
+ moods: [] as any[]
57
+ })
58
+ const flagId = useMemo(() =>{
59
+ if(flagState.colors !== undefined){
60
+ const flag = state.flags.find(item => {
61
+ const hexColors = item.colors.map(c => hsv2Hex(c.h, c.s, c.v).toLocaleUpperCase())
62
+ return isEqual(hexColors, flagState.colors)
63
+ })
64
+ return flag?.id
65
+ }
66
+ if(flagState.id !== undefined){
67
+ return flagState
68
+ }
69
+ return -1
70
+ }, [JSON.stringify(flagState), JSON.stringify(state.flags)])
71
+
72
+
73
+ useEffect(() => {
74
+ getRemoteFlagInfo().then()
75
+ if(params.getRemoteMoodList){
76
+ params.getRemoteMoodList(devId).then(res =>{
77
+ if(res.success && Array.isArray(res.data)){
78
+ state.moods = res.data
79
+ }
80
+ })
81
+ }
82
+ }, [])
83
+
84
+ const getRemoteFlagInfo = async () => {
85
+ const res = await getRemoteFlag(devId)
86
+ if (res.success) {
87
+ state.flags = cloneDeep(res.data) || []
88
+ }
89
+ }
90
+
91
+ const navigationRoute = (mode: 'add' | 'edit', currentMood?: FlagUiInfo) => {
92
+ const path = ui_biz_routerKey.ui_biz_flag_page_edit
93
+ navigation.navigate(path, {
94
+ mode,
95
+ moods: state.flags,
96
+ currentMood,
97
+ moduleParams: params,
98
+ modDeleteFlag
99
+ })
100
+ }
101
+
102
+ const modDeleteFlag = async (mode: 'add' | 'edit' | 'del', currentMood: FlagUiInfo) => {
103
+ const checkedMood: FlagUiInfo = {
104
+ ...currentMood,
105
+ }
106
+
107
+ let newScene: FlagUiInfo[] = []
108
+ if (mode === 'add') {
109
+ newScene = [
110
+ checkedMood,
111
+ ...state.flags,
112
+ ]
113
+ } else if (mode === 'del') {
114
+ newScene = state.flags.filter(item => item.id !== checkedMood.id)
115
+ } else {
116
+ newScene = state.flags.map(item => {
117
+ if (item.id === checkedMood.id) {
118
+ return checkedMood
119
+ }
120
+ return item
121
+ })
122
+ }
123
+ const mood = mode === 'del' ? (newScene.length === 0 ? undefined : newScene[0]) : checkedMood
124
+ const res = await saveFlag(devId, cloneDeep(newScene))
125
+ if (res.success) {
126
+ state.flags = cloneDeep(newScene)
127
+ if(mood){
128
+ setFlag(mood)
129
+ }else{
130
+ setDps({[params.workModeCode!!]: params.isSupportColor ? WORK_MODE.COLOUR : WORK_MODE.WHITE})
131
+ }
132
+ return {
133
+ success: true
134
+ }
135
+ }
136
+ return {
137
+ success: false
138
+ }
139
+ }
140
+
141
+ return (
142
+ <Page
143
+ headlineText={I18n.getLang('Feature_devicepanel_flags')}
144
+ backText={devInfo.name}
145
+ headlineIcon={res.add}
146
+ onHeadlineIconClick={() => {
147
+ const useIds = map([
148
+ ...state.flags,
149
+ ...state.moods
150
+ ], 'id')
151
+ console.log(useIds, '< --- useIds')
152
+ const idRange = range(0, 256)
153
+ const unuseId = last(difference(idRange, useIds))
154
+ if(unuseId !== undefined){
155
+ navigationRoute('add', newFlag(unuseId))
156
+ }
157
+ }}
158
+ >
159
+ <FlatList
160
+ data={state.flags}
161
+ renderItem={({ item }) => <FlagItem
162
+ enable={flagId === item.id}
163
+ title={item.name}
164
+ colors={item.colors.map(item => hsv2Hex(item.h, item.s, item.v))}
165
+ onSwitch={async (enable) => {
166
+ if (enable) {
167
+ await setFlag(item)
168
+ }
169
+ }}
170
+ onPress={() => {
171
+ navigationRoute('edit', item)
172
+ }}
173
+ />}
174
+ keyExtractor={item => item.name}
175
+ ListHeaderComponent={() => (<Spacer height={cx(10)} />)}
176
+ ItemSeparatorComponent={() => (<Spacer />)}
177
+ ListFooterComponent={() => (<Spacer />)}
178
+ />
179
+ </Page>
180
+ )
181
+ }
182
+
183
+ export const newFlag = (id: number) => {
184
+ return {
185
+ version: 0,
186
+ id,
187
+ name: '',
188
+ mode: SceneNodeTransitionMode.Jump,
189
+ speed: 70,
190
+ colors: [
191
+ { h: 48, s: 100, v: 100 },
192
+ { h: 360, s: 100, v: 86 },
193
+ ],
194
+ whiteColors: [{ brightness: 100, colorTemp: 0 }],
195
+ fanEnable: undefined,
196
+ fanSpeed: undefined
197
+ }
198
+ }
199
+
200
+ export default FlagPage
@@ -21,6 +21,8 @@ import RandomTimePage from 'modules/randomTime/RandomTimePage'
21
21
  import RandomTimeDetailPage from '../modules/randomTime/RandomTimeDetailPage'
22
22
  import HistoryPage from '../modules/history/HistoryPage'
23
23
  import PowerOnBehaviorPage from '../modules/powerOnBehavior/PowerOnBehaviorPage'
24
+ import FlagPage from '../modules/flags/FlagPage'
25
+ import FlagEditPage from '../modules/flags/FlagEditPage'
24
26
 
25
27
  export const ui_biz_routerKey = {
26
28
  'ui_biz_time_schedule': 'ui_biz_time_schedule',
@@ -44,7 +46,9 @@ export const ui_biz_routerKey = {
44
46
  'ui_biz_random_time': 'ui_biz_random_time',
45
47
  'ui_biz_random_time_edit': 'ui_biz_random_time_edit',
46
48
  'ui_biz_history': 'ui_biz_history',
47
- 'ui_biz_power_behavior': 'ui_biz_power_behavior'
49
+ 'ui_biz_power_behavior': 'ui_biz_power_behavior',
50
+ 'ui_biz_flag_page': 'ui_biz_flag_page',
51
+ 'ui_biz_flag_page_edit': 'ui_biz_flag_page_edit'
48
52
  }
49
53
 
50
54
  export const BiologicalRouters: NavigationRoute[] = [
@@ -264,4 +268,23 @@ export const PowerOnBehaviorPageRouters: NavigationRoute[] = [
264
268
  showOfflineView: false,
265
269
  }
266
270
  }
271
+ ]
272
+
273
+ export const FlagPageRouters: NavigationRoute[] = [
274
+ {
275
+ name: ui_biz_routerKey.ui_biz_flag_page,
276
+ component: FlagPage,
277
+ options: {
278
+ hideTopbar: true,
279
+ showOfflineView: false,
280
+ }
281
+ },
282
+ {
283
+ name: ui_biz_routerKey.ui_biz_flag_page_edit,
284
+ component: FlagEditPage,
285
+ options: {
286
+ hideTopbar: true,
287
+ showOfflineView: false,
288
+ }
289
+ },
267
290
  ]