@ledvance/ui-biz-bundle 1.1.6 → 1.1.8

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.8",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -0,0 +1,232 @@
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, nToHS, parseJSON, toFixed } 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
+ import { stripDp2Obj } from "@ledvance/ui-biz-bundle/src/modules/scene/SceneAction";
14
+
15
+ export interface ExtraParams extends FlagPageProps, FlagOption {
16
+ }
17
+ interface FlagState {
18
+ id?: number
19
+ colors?: string[]
20
+ }
21
+ const featureId = 'Flag_data'
22
+
23
+ type UseFlagType = (flagCode: string, extra: ExtraParams) => [FlagState, (flagItem: FlagItemInfo) => Promise<any>]
24
+
25
+ export const useFlag: UseFlagType = (flagCode, extra) => {
26
+ const [dps, setDps] = useDps()
27
+ const dp = dps[flagCode]
28
+ const memoId = useMemo(() => {
29
+ if (extra.drawToolLight) {
30
+ return {
31
+ colors: extra.drawToolLight.drawToolDp2Obj(dp)
32
+ }
33
+ }
34
+ return {
35
+ id: dp2Obj(dp, extra)?.id
36
+ }
37
+ }, [])
38
+ const [flagState, setFlagState] = useState(memoId)
39
+
40
+ useUpdateEffect(() => {
41
+ if (extra.drawToolLight) {
42
+ setFlagState({
43
+ colors: extra.drawToolLight.drawToolDp2Obj(dp)
44
+ })
45
+ } else {
46
+ setFlagState({
47
+ id: dp2Obj(dp, extra)?.id
48
+ })
49
+ }
50
+ }, [dp])
51
+
52
+
53
+ const setFlagFn = (flagItem: FlagItemInfo) => {
54
+ if (extra.drawToolLight) {
55
+ const hex = extra.drawToolLight.drawToolObj2dp(flagItem.colors.map(item => hsv2Hex(item.h, item.s, item.v)))
56
+ return setDps({ [flagCode]: hex })
57
+ } else {
58
+ const hex = obj2Dp(flagItem, extra)
59
+ return setDps({ [flagCode]: hex, [extra.workModeCode]: WORK_MODE.SCENE, [extra.switchLedCode]: true })
60
+ }
61
+ }
62
+ return [flagState, setFlagFn]
63
+ }
64
+
65
+ export interface FlagOption {
66
+ isMixLight?: boolean
67
+ isStringLight?: boolean
68
+ workModeCode: string
69
+ }
70
+
71
+ export function obj2Dp(flagItem: FlagItemInfo, option?: FlagOption): string {
72
+ const version = '00'
73
+ const idHex = nToHS(flagItem.id)
74
+ if (option?.isMixLight) {
75
+ const whiteEnable = '01'
76
+ const whiteNum = '01'
77
+ const whiteStatus = '02'
78
+ const whiteHex = whiteEnable + whiteNum + whiteStatus + flagItem.whiteColors.map(colors => {
79
+ const speed = '00'
80
+ const mode = '00'
81
+ const bHex = nToHS(colors.brightness * 10, 4)
82
+ const tHex = nToHS(colors.colorTemp * 10, 4)
83
+ return speed + speed + mode + bHex + tHex
84
+ }).join('')
85
+ const colorEnable = '01'
86
+ const colorNum = nToHS(flagItem.colors.length)
87
+ const colorStatus = '03'
88
+ const colorHex = colorEnable + colorNum + colorStatus + flagItem.colors.map(item => {
89
+ const speed = nToHS(flagItem.speed)
90
+ const mode = nToHS(flagItem.mode)
91
+ const hHex = nToHS(item.h, 4)
92
+ const sHex = nToHS(item.s * 10, 4)
93
+ const vHex = nToHS(item.v * 10, 4)
94
+ return speed + speed + mode + hHex + sHex + vHex
95
+ }).join('')
96
+ return version + idHex + whiteHex + colorHex
97
+ } else if (option?.isStringLight) {
98
+ const version = '00'
99
+ const idHex = nToHS(flagItem.id)
100
+ const expand = 0
101
+ const reserved1 = 0
102
+ const reserved2 = 0
103
+ const loop = 0
104
+ const excessive = 0
105
+ const direction = 0
106
+ const segmented = 0
107
+ const modeHex = nToHS(10)
108
+ const intervalTimeHex = nToHS(flagItem.speed)
109
+ const changeTimeHex = nToHS(flagItem.speed)
110
+ const optionAHex = nToHS(
111
+ parseInt(
112
+ `${segmented}${loop}${excessive}${direction}${toFixed(
113
+ expand.toString(2),
114
+ 2
115
+ )}${reserved1}${reserved2}`,
116
+ 2
117
+ )
118
+ );
119
+ const optionBHex = nToHS(0)
120
+ const optionCHex = nToHS(0)
121
+ const nodeHex = flagItem.colors.map(node => {
122
+ return `${nToHS(node.v)}${nToHS(node.h, 4)}${nToHS(node.s)}${nToHS(0, 4)}${nToHS(0, 4)}`
123
+ }).join('')
124
+ return version + idHex + modeHex + intervalTimeHex + changeTimeHex + optionAHex + optionBHex + optionCHex + nodeHex
125
+ } else {
126
+ const switchingIntervalHex = nToHS(flagItem.speed)
127
+ const transitionTimeHex = nToHS(flagItem.speed)
128
+ const transitionModeHex = nToHS(flagItem.mode)
129
+ const hex = idHex + flagItem.colors.map(color => {
130
+ const hHex = nToHS(Math.round(color.h), 4)
131
+ const sHex = nToHS(Math.round(color.s * 10), 4)
132
+ const vHex = nToHS(Math.round(color.v * 10), 4)
133
+ const brightnessHex = '0000'
134
+ const colorTempHex = '0000'
135
+ return switchingIntervalHex + transitionTimeHex + transitionModeHex + hHex + sHex + vHex + brightnessHex + colorTempHex
136
+ }).join('')
137
+ return hex
138
+ }
139
+ }
140
+
141
+ export function dp2Obj(dp: string, option?: FlagOption): FlagItemInfo | undefined {
142
+ if (!dp) return
143
+ const result = {} as FlagItemInfo
144
+ if (option?.isMixLight) {
145
+ result.version = hex2Int(dp.slice(0, 2))
146
+ result.id = hex2Int(dp.slice(2, 4))
147
+ let lampHex = dp.slice(16)
148
+ result.whiteColors = [
149
+ { brightness: hex2Int(lampHex.slice(0, 4)) / 10, colorTemp: hex2Int(lampHex.slice(4, 8)) / 10 }
150
+ ]
151
+ lampHex = lampHex.slice(14)
152
+ result.colors = spliceByStep(lampHex, 18).map(lamp => {
153
+ result.speed = hex2Int(lamp.slice(0, 2))
154
+ result.mode = hex2Int(lamp.slice(4, 6))
155
+ return {
156
+ h: hex2Int(lamp.slice(6, 10)),
157
+ s: hex2Int(lamp.slice(10, 14)) / 10,
158
+ v: hex2Int(lamp.slice(14, 18)) / 10
159
+ }
160
+ })
161
+ return result
162
+ } else if (option?.isStringLight) {
163
+ const { speed, mode, id, nodes } = stripDp2Obj(dp, true)
164
+ const colors = nodes.map(node => ({
165
+ ...node,
166
+ s: node.s / 10,
167
+ v: node.v / 10
168
+ }))
169
+ return {
170
+ id,
171
+ mode,
172
+ speed,
173
+ whiteColors: [{ brightness: 100, colorTemp: 0 }],
174
+ colors
175
+ }
176
+ } else {
177
+ const id = hex2Int(dp.slice(0, 2))
178
+ const sliceDp = dp.slice(2)
179
+ let mode = SceneNodeTransitionMode.Jump
180
+ let speed = 70
181
+ const colors = spliceByStep(sliceDp, 26).map(nodeHex => {
182
+ speed = hex2Int(nodeHex.slice(0, 2))
183
+ mode = hex2Int(nodeHex.slice(4, 6))
184
+ const h = hex2Int(nodeHex.slice(6, 10))
185
+ const s = hex2Int(nodeHex.slice(10, 14))
186
+ const v = hex2Int(nodeHex.slice(14, 18))
187
+ return {
188
+ h,
189
+ s: s / 10,
190
+ v: v / 10
191
+ }
192
+ })
193
+ const whiteColors = [{ brightness: 100, colorTemp: 0 }]
194
+ return {
195
+ id,
196
+ mode,
197
+ speed,
198
+ colors,
199
+ whiteColors
200
+ }
201
+ }
202
+
203
+ }
204
+
205
+
206
+ export async function getRemoteFlag(devId: string) {
207
+ const res = await NativeApi.getJson(devId, featureId)
208
+ const isNormalData = Array.isArray(parseJSON(res?.data))
209
+ if (res.success && isNormalData) {
210
+ return {
211
+ success: true,
212
+ data: JSON.parse(res.data)
213
+ }
214
+ } else {
215
+ if (res.msg?.includes('资源未找到') || !isNormalData) {
216
+ const res = await NativeApi.putJson(devId, featureId, JSON.stringify(defFlagList))
217
+ if (res.success) {
218
+ return {
219
+ success: true,
220
+ data: cloneDeep(defFlagList)
221
+ }
222
+ }
223
+ return { success: false }
224
+ }
225
+ return { success: false }
226
+ }
227
+ }
228
+
229
+ export function saveFlag(devId: string, flagInfo: FlagUiInfo[]) {
230
+ return NativeApi.putJson(devId, featureId, JSON.stringify(flagInfo))
231
+ }
232
+
@@ -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
+ loading={state.loading}
76
+ backDialogTitle={
77
+ I18n.getLang(params.mode === 'add' ?
78
+ 'flag_canceladding' :
79
+ 'flag_canceledit')
80
+ }
81
+ backDialogContent={
82
+ I18n.getLang('flag_cancelinfo')
83
+ }
84
+ headlineText={I18n.getLang(params.mode === 'add' ? 'flag_addanewflag' : 'flag_edittheflag')}
85
+ rightButtonIcon={getButtonStatus() ? res.ic_uncheck : res.ic_check}
86
+ rightButtonDisabled={getButtonStatus()}
87
+ rightButtonIconClick={async () => {
88
+ if (state.loading) return
89
+ state.loading = true
90
+ const res = await params.modDeleteFlag(params.mode, state.mood)
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,296 @@
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
+ }
23
+
24
+ export interface FlagUiInfo extends FlagItemInfo{
25
+ name: string
26
+ }
27
+
28
+ export const defFlagList: FlagUiInfo[] = [
29
+ {
30
+ id: 255,
31
+ version: 0,
32
+ mode: SceneNodeTransitionMode.Jump,
33
+ speed: 70,
34
+ name: I18n.getLang('country_DE'),
35
+ whiteColors: [
36
+ { brightness: 100, colorTemp: 0},
37
+ ],
38
+ colors: [
39
+ {h: 48, s: 100, v: 100},
40
+ {h: 360, s: 100, v: 86},
41
+ {h: 0, s: 0, v:0}],
42
+ },
43
+ {
44
+ id: 254,
45
+ version: 0,
46
+ mode: SceneNodeTransitionMode.Jump,
47
+ speed: 70,
48
+ name: I18n.getLang('country_BE'),
49
+ whiteColors: [
50
+ { brightness: 100, colorTemp: 0},
51
+ ],
52
+ colors: [{h: 350, s: 92, v: 78}, {h: 48, s: 100, v: 100}, {h: 25, s: 15, v: 17}]
53
+ },
54
+ {
55
+ id: 253,
56
+ version: 0,
57
+ mode: SceneNodeTransitionMode.Jump,
58
+ speed: 70,
59
+ name: I18n.getLang('country_FR'),
60
+ whiteColors: [
61
+ { brightness: 100, colorTemp: 0},
62
+ ],
63
+ colors: [{h: 355, s: 82, v: 92}, {h: 0, s: 0, v: 100}, {h: 212, s: 100, v: 32}]
64
+ },
65
+ {
66
+ id: 252,
67
+ version: 0,
68
+ mode: SceneNodeTransitionMode.Jump,
69
+ speed: 70,
70
+ name: I18n.getLang('country_PT'),
71
+ whiteColors: [
72
+ { brightness: 100, colorTemp: 0},
73
+ ],
74
+ colors: [{h: 4, s: 87, v: 85}, {h: 4, s: 87, v: 85}, {h: 150, s: 96, v: 41}]
75
+ },
76
+ {
77
+ id: 251,
78
+ version: 0,
79
+ mode: SceneNodeTransitionMode.Jump,
80
+ speed: 70,
81
+ name: I18n.getLang('country_scotland'),
82
+ whiteColors: [
83
+ { brightness: 100, colorTemp: 0},
84
+ ],
85
+ colors: [{h: 209, s: 100, v: 72}, {h: 0, s: 0, v: 100}, {h: 209, s: 100, v: 72}]
86
+ },
87
+ {
88
+ id: 250,
89
+ version: 0,
90
+ mode: SceneNodeTransitionMode.Jump,
91
+ speed: 70,
92
+ name: I18n.getLang('country_ES'),
93
+ whiteColors: [
94
+ { brightness: 100, colorTemp: 0},
95
+ ],
96
+ colors: [{h: 357, s: 87, v: 66}, {h: 47, s: 100, v: 94}, {h: 357, s: 87, v: 66}]
97
+ },
98
+ {
99
+ id: 249,
100
+ version: 0,
101
+ mode: SceneNodeTransitionMode.Jump,
102
+ speed: 70,
103
+ name: I18n.getLang('country_TR'),
104
+ whiteColors: [
105
+ { brightness: 100, colorTemp: 0},
106
+ ],
107
+ colors: [{h: 350, s: 92, v: 78}, {h: 350, s: 92, v: 78}, {h: 0, s: 0, v: 100}]
108
+ },
109
+ {
110
+ id: 248,
111
+ version: 0,
112
+ mode: SceneNodeTransitionMode.Jump,
113
+ speed: 70,
114
+ name: I18n.getLang('country_AT'),
115
+ whiteColors: [
116
+ { brightness: 100, colorTemp: 0},
117
+ ],
118
+ colors: [{h: 355, s: 78, v: 93}, {h: 0, s: 0, v: 100}, {h: 355, s: 78, v: 93}]
119
+ },
120
+ {
121
+ id: 247,
122
+ version: 0,
123
+ mode: SceneNodeTransitionMode.Jump,
124
+ speed: 70,
125
+ name: I18n.getLang('country_england'),
126
+ whiteColors: [
127
+ { brightness: 100, colorTemp: 0},
128
+ ],
129
+ colors: [{h: 0, s: 0, v: 100}, {h: 353, s: 91, v: 80}, {h: 0, s: 0, v: 100}]
130
+ },
131
+ {
132
+ id: 246,
133
+ version: 0,
134
+ mode: SceneNodeTransitionMode.Jump,
135
+ speed: 70,
136
+ name: I18n.getLang('country_HU'),
137
+ whiteColors: [
138
+ { brightness: 100, colorTemp: 0},
139
+ ],
140
+ colors: [{h: 133, s: 36, v: 43}, {h: 0, s: 0, v: 100}, {h: 354, s: 80, v: 80}]
141
+ },
142
+ {
143
+ id: 245,
144
+ version: 0,
145
+ mode: SceneNodeTransitionMode.Jump,
146
+ speed: 70,
147
+ name: I18n.getLang('country_SK'),
148
+ whiteColors: [
149
+ { brightness: 100, colorTemp: 0},
150
+ ],
151
+ colors: [{h: 357, s: 88, v: 93}, {h: 213, s: 93, v: 63}, {h: 0, s: 0, v: 100}]
152
+ },
153
+ {
154
+ id: 244,
155
+ version: 0,
156
+ mode: SceneNodeTransitionMode.Jump,
157
+ speed: 70,
158
+ name: I18n.getLang('country_AL'),
159
+ whiteColors: [
160
+ { brightness: 100, colorTemp: 0},
161
+ ],
162
+ colors: [{h: 4, s: 87, v: 85}, {h: 0, s: 0, v:0}, {h: 4, s: 87, v: 85}]
163
+ },
164
+ {
165
+ id: 243,
166
+ version: 0,
167
+ mode: SceneNodeTransitionMode.Jump,
168
+ speed: 70,
169
+ name: I18n.getLang('country_DK'),
170
+ whiteColors: [
171
+ { brightness: 100, colorTemp: 0},
172
+ ],
173
+ colors: [{h: 350, s: 92, v: 78}, {h: 0, s: 0, v:0}, {h: 350, s: 92, v: 78}]
174
+ },
175
+ {
176
+ id: 242,
177
+ version: 0,
178
+ mode: SceneNodeTransitionMode.Jump,
179
+ speed: 70,
180
+ name: I18n.getLang('country_NL'),
181
+ whiteColors: [
182
+ { brightness: 100, colorTemp: 0},
183
+ ],
184
+ colors: [{h: 217, s: 100, v: 64}, {h: 0, s: 0, v:0}, {h: 350, s: 92, v: 78}]
185
+ },
186
+ {
187
+ id: 241,
188
+ version: 0,
189
+ mode: SceneNodeTransitionMode.Jump,
190
+ speed: 70,
191
+ name: I18n.getLang('country_RO'),
192
+ whiteColors: [
193
+ { brightness: 100, colorTemp: 0},
194
+ ],
195
+ colors: [{h: 353, s: 91, v: 80}, {h: 48, s: 91, v: 98}, {h: 219, s: 100, v: 49}]
196
+ },
197
+ {
198
+ id: 240,
199
+ version: 0,
200
+ mode: SceneNodeTransitionMode.Jump,
201
+ speed: 70,
202
+ name: I18n.getLang('country_CH'),
203
+ whiteColors: [
204
+ { brightness: 100, colorTemp: 0},
205
+ ],
206
+ colors: [{h: 4, s: 87, v: 85}, {h: 0, s: 0, v: 100}, {h: 4, s: 87, v: 85}]
207
+ },
208
+ {
209
+ id: 239,
210
+ version: 0,
211
+ mode: SceneNodeTransitionMode.Jump,
212
+ speed: 70,
213
+ name: I18n.getLang('country_RS'),
214
+ whiteColors: [
215
+ { brightness: 100, colorTemp: 0},
216
+ ],
217
+ colors: [{h: 0, s: 0, v: 100}, {h: 210, s: 89, v: 46}, {h: 357, s: 72, v: 77}]
218
+ },
219
+ {
220
+ id: 238,
221
+ version: 0,
222
+ mode: SceneNodeTransitionMode.Jump,
223
+ speed: 70,
224
+ name: I18n.getLang('country_IT'),
225
+ whiteColors: [
226
+ { brightness: 100, colorTemp: 0},
227
+ ],
228
+ colors: [{h: 366, s: 83, v: 80}, {h: 212, s: 4, v: 100}, {h: 149, s: 100, v: 54}]
229
+ },
230
+ {
231
+ id: 237,
232
+ version: 0,
233
+ mode: SceneNodeTransitionMode.Jump,
234
+ speed: 70,
235
+ name: I18n.getLang('country_CZ'),
236
+ whiteColors: [
237
+ { brightness: 100, colorTemp: 0},
238
+ ],
239
+ colors: [{h: 358, s: 90, v: 84}, {h: 0, s: 0, v: 100}, {h: 211, s: 86, v: 49}]
240
+ },
241
+ {
242
+ id: 236,
243
+ version: 0,
244
+ mode: SceneNodeTransitionMode.Jump,
245
+ speed: 70,
246
+ name: I18n.getLang('country_SI'),
247
+ whiteColors: [
248
+ { brightness: 100, colorTemp: 0},
249
+ ],
250
+ colors: [{h: 360, s: 100, v: 100}, {h: 217, s: 100, v: 64}, {h: 0, s: 0, v: 100}]
251
+ },
252
+ {
253
+ id: 235,
254
+ version: 0,
255
+ mode: SceneNodeTransitionMode.Jump,
256
+ speed: 70,
257
+ name: I18n.getLang('country_HR'),
258
+ whiteColors: [
259
+ { brightness: 100, colorTemp: 0},
260
+ ],
261
+ colors: [{h: 0, s: 0, v: 100}, {h: 220, s: 89, v: 54}, {h: 2, s: 89, v: 90}]
262
+ },
263
+ {
264
+ id: 234,
265
+ version: 0,
266
+ mode: SceneNodeTransitionMode.Jump,
267
+ speed: 70,
268
+ name: I18n.getLang('country_SE'),
269
+ whiteColors: [
270
+ { brightness: 100, colorTemp: 0},
271
+ ],
272
+ colors: [{h: 201, s: 100, v: 65}, {h: 48, s: 99, v: 99}, {h: 201, s: 100, v: 65}]
273
+ },
274
+ {
275
+ id: 233,
276
+ version: 0,
277
+ mode: SceneNodeTransitionMode.Jump,
278
+ speed: 70,
279
+ name: I18n.getLang('country_NO'),
280
+ whiteColors: [
281
+ { brightness: 100, colorTemp: 0},
282
+ ],
283
+ colors: [{h: 0, s: 0, v: 100}, {h: 218, s: 100, v: 35}, {h: 347, s: 93, v: 72}]
284
+ },
285
+ {
286
+ id: 232,
287
+ version: 0,
288
+ mode: SceneNodeTransitionMode.Jump,
289
+ speed: 70,
290
+ name: I18n.getLang('country_PL'),
291
+ whiteColors: [
292
+ { brightness: 100, colorTemp: 0},
293
+ ],
294
+ colors: [{h: 348, s: 90, v: 86}, {h: 0, s: 0, v: 100}]
295
+ },
296
+ ]
@@ -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,203 @@
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
+ isStringLight?: boolean
28
+ isSupportMixScene?: boolean
29
+ drawToolLight?: {
30
+ drawToolCode: string
31
+ drawToolObj2dp: (colors: string[]) => string
32
+ drawToolDp2Obj: (dp: string) => string[]
33
+ }
34
+ getRemoteMoodList?: (devId: string) => Promise<Result<any>>
35
+ sceneDataCode?: string
36
+ workModeCode: string
37
+ switchLedCode: string
38
+ }
39
+
40
+ const FlagPage = () => {
41
+ const params = useRoute().params as FlagPageProps
42
+ const devInfo = useDeviceInfo()
43
+ const devId = useDeviceId()
44
+ const navigation = useNavigation()
45
+ const [, setDps] = useDps()
46
+ const [flagState, setFlag] = useFlag((params.sceneDataCode || params?.drawToolLight?.drawToolCode)!!, {
47
+ isMixLight: params.isSupportMixScene,
48
+ isStringLight: params.isStringLight,
49
+ ...params
50
+ })
51
+ const state = useReactive({
52
+ loading: true,
53
+ flags: [] as FlagUiInfo[],
54
+ moods: [] as any[]
55
+ })
56
+ const flagId = useMemo(() =>{
57
+ if(flagState.colors !== undefined){
58
+ const flag = state.flags.find(item => {
59
+ const hexColors = item.colors.map(c => hsv2Hex(c.h, c.s, c.v).toLocaleUpperCase())
60
+ return isEqual(hexColors, flagState.colors)
61
+ })
62
+ return flag?.id
63
+ }
64
+ if(flagState.id !== undefined){
65
+ return flagState
66
+ }
67
+ return -1
68
+ }, [JSON.stringify(flagState), JSON.stringify(state.flags)])
69
+
70
+
71
+ useEffect(() => {
72
+ getRemoteFlagInfo().then()
73
+ if(params.getRemoteMoodList){
74
+ params.getRemoteMoodList(devId).then(res =>{
75
+ if(res.success && Array.isArray(res.data)){
76
+ state.moods = res.data
77
+ }
78
+ })
79
+ }
80
+ }, [])
81
+
82
+ const getRemoteFlagInfo = async () => {
83
+ const res = await getRemoteFlag(devId)
84
+ if (res.success) {
85
+ state.flags = cloneDeep(res.data) || []
86
+ }
87
+ }
88
+
89
+ const navigationRoute = (mode: 'add' | 'edit', currentMood?: FlagUiInfo) => {
90
+ const path = ui_biz_routerKey.ui_biz_flag_page_edit
91
+ navigation.navigate(path, {
92
+ mode,
93
+ moods: state.flags,
94
+ currentMood,
95
+ moduleParams: params,
96
+ modDeleteFlag
97
+ })
98
+ }
99
+
100
+ const modDeleteFlag = async (mode: 'add' | 'edit' | 'del', currentMood: FlagUiInfo) => {
101
+ const checkedMood: FlagUiInfo = {
102
+ ...currentMood,
103
+ }
104
+
105
+ let newScene: FlagUiInfo[] = []
106
+ if (mode === 'add') {
107
+ newScene = [
108
+ checkedMood,
109
+ ...state.flags,
110
+ ]
111
+ } else if (mode === 'del') {
112
+ newScene = state.flags.filter(item => item.id !== checkedMood.id)
113
+ } else {
114
+ newScene = state.flags.map(item => {
115
+ if (item.id === checkedMood.id) {
116
+ return checkedMood
117
+ }
118
+ return item
119
+ })
120
+ }
121
+ const mood = mode === 'del' ? (newScene.length === 0 ? undefined : newScene[0]) : checkedMood
122
+ const res = await saveFlag(devId, cloneDeep(newScene))
123
+ if (res.success) {
124
+ state.flags = cloneDeep(newScene)
125
+ if(currentMood.id === flagState.id){
126
+ return {
127
+ success: true
128
+ }
129
+ }
130
+ if(mood){
131
+ setFlag(mood)
132
+ }else{
133
+ setDps({[params.workModeCode!!]: params.isSupportColor ? WORK_MODE.COLOUR : WORK_MODE.WHITE})
134
+ }
135
+ return {
136
+ success: true
137
+ }
138
+ }
139
+ return {
140
+ success: false
141
+ }
142
+ }
143
+
144
+ return (
145
+ <Page
146
+ headlineText={I18n.getLang('Feature_devicepanel_flags')}
147
+ backText={devInfo.name}
148
+ headlineIcon={res.add}
149
+ onHeadlineIconClick={() => {
150
+ const useIds = map([
151
+ ...state.flags,
152
+ ...state.moods
153
+ ], 'id')
154
+ console.log(useIds, '< --- useIds')
155
+ const idRange = range(0, 256)
156
+ const unuseId = last(difference(idRange, useIds))
157
+ if(unuseId !== undefined){
158
+ navigationRoute('add', newFlag(unuseId))
159
+ }
160
+ }}
161
+ >
162
+ <FlatList
163
+ data={state.flags}
164
+ renderItem={({ item }) => <FlagItem
165
+ enable={flagId === item.id}
166
+ title={item.name}
167
+ colors={item.colors.map(item => hsv2Hex(item.h, item.s, item.v))}
168
+ onSwitch={async (enable) => {
169
+ if (enable) {
170
+ await setFlag(item)
171
+ }
172
+ }}
173
+ onPress={() => {
174
+ navigationRoute('edit', item)
175
+ }}
176
+ />}
177
+ keyExtractor={item => item.name}
178
+ ListHeaderComponent={() => (<Spacer height={cx(10)} />)}
179
+ ItemSeparatorComponent={() => (<Spacer />)}
180
+ ListFooterComponent={() => (<Spacer />)}
181
+ />
182
+ </Page>
183
+ )
184
+ }
185
+
186
+ export const newFlag = (id: number) => {
187
+ return {
188
+ version: 0,
189
+ id,
190
+ name: '',
191
+ mode: SceneNodeTransitionMode.Jump,
192
+ speed: 70,
193
+ colors: [
194
+ { h: 48, s: 100, v: 100 },
195
+ { h: 360, s: 100, v: 86 },
196
+ ],
197
+ whiteColors: [{ brightness: 100, colorTemp: 0 }],
198
+ fanEnable: undefined,
199
+ fanSpeed: undefined
200
+ }
201
+ }
202
+
203
+ 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
  ]