@ledvance/group-ui-biz-bundle 1.0.0

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.
Files changed (40) hide show
  1. package/.babelrc +31 -0
  2. package/.eslintignore +6 -0
  3. package/.eslintrc.js +27 -0
  4. package/.prettierignore +0 -0
  5. package/.prettierrc.js +1 -0
  6. package/.versionrc +5 -0
  7. package/package.json +73 -0
  8. package/rn-cli.config.js +8 -0
  9. package/src/modules/mood/AddMoodPage.tsx +826 -0
  10. package/src/modules/mood/DynamicMoodEditorPage.tsx +547 -0
  11. package/src/modules/mood/MoodItem.tsx +114 -0
  12. package/src/modules/mood/MoodPage.tsx +332 -0
  13. package/src/modules/mood/RecommendMoodItem.tsx +75 -0
  14. package/src/modules/mood/SceneAction.ts +459 -0
  15. package/src/modules/mood/SceneInfo.ts +886 -0
  16. package/src/modules/mood/StaticMoodEditorPage.tsx +251 -0
  17. package/src/modules/mood/tools.ts +12 -0
  18. package/src/modules/select/SelectPage.d.ts +12 -0
  19. package/src/modules/select/SelectPage.tsx +139 -0
  20. package/src/modules/time_schedule/Interface.ts +85 -0
  21. package/src/modules/time_schedule/ScheduleCard.tsx +111 -0
  22. package/src/modules/time_schedule/TimeScheduleActions.ts +81 -0
  23. package/src/modules/time_schedule/TimeScheduleDetailPage.tsx +704 -0
  24. package/src/modules/time_schedule/TimeSchedulePage.tsx +246 -0
  25. package/src/modules/timer/TimerAction.d.ts +12 -0
  26. package/src/modules/timer/TimerAction.ts +150 -0
  27. package/src/modules/timer/TimerPage.d.ts +2 -0
  28. package/src/modules/timer/TimerPage.tsx +351 -0
  29. package/src/navigation/Routers.d.ts +5 -0
  30. package/src/navigation/Routers.ts +97 -0
  31. package/src/navigation/tools.d.ts +0 -0
  32. package/src/navigation/tools.ts +0 -0
  33. package/src/res/GroupBizRes.ts +4 -0
  34. package/src/res/materialiconsFilledCancel.png +0 -0
  35. package/src/res/materialiconsFilledCancel@2x.png +0 -0
  36. package/src/res/materialiconsFilledCancel@3x.png +0 -0
  37. package/src/res/materialiconsOutlinedArrowsNavAddBox.png +0 -0
  38. package/src/res/materialiconsOutlinedArrowsNavAddBox@2x.png +0 -0
  39. package/src/res/materialiconsOutlinedArrowsNavAddBox@3x.png +0 -0
  40. package/tsconfig.json +51 -0
@@ -0,0 +1,332 @@
1
+ import React, { useCallback, useEffect, useMemo } from 'react'
2
+ import Page from '@ledvance/base/src/components/Page'
3
+ import { Utils } from 'tuya-panel-kit'
4
+ import { SceneMode, ScenePageUIState, SceneUIState, StripSceneUIState } from './SceneInfo'
5
+ import { getRemoteSceneList, saveScene, useScene, useSwitchLed, useWorkMode } from './SceneAction'
6
+ import { WorkMode } from '@ledvance/base/src/utils/interface'
7
+ import { useDeviceInfo, useMoods, useUAGroupInfo } from '@ledvance/base/src/models/modules/NativePropsSlice'
8
+ import { useReactive } from 'ahooks'
9
+ import Strings from '@ledvance/base/src/i18n'
10
+ import res from '@ledvance/base/src/res'
11
+ import { FlatList, StyleSheet, View } from 'react-native'
12
+ import Tag from '@ledvance/base/src/components/Tag'
13
+ 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 { useNavigation, useRoute } from '@react-navigation/core'
18
+ import { cloneDeep } from 'lodash'
19
+ import { ui_biz_routerKey } from '../../navigation/Routers'
20
+
21
+ const cx = Utils.RatioUtils.convertX
22
+
23
+ interface MoodPageUIState extends ScenePageUIState {
24
+ staticTagChecked: boolean
25
+ dynamicTagChecked: boolean
26
+ showAddMoodPopover: boolean
27
+ originScene: SceneUIState[] | StripSceneUIState[]
28
+ filteredMoods: SceneUIState[] | StripSceneUIState[]
29
+ loading: boolean
30
+ }
31
+
32
+ export interface MoodPageProps {
33
+ switchLedDpCode: string
34
+ sceneDataDpCode: string
35
+ workModeDpCode: string
36
+ isSupportFan?: boolean
37
+ isSupportUVC?: boolean
38
+ isSupportColor: boolean
39
+ isSupportTemperature: boolean
40
+ isSupportBrightness: boolean
41
+ isStringLight?: boolean
42
+ isStripLight?: boolean
43
+ }
44
+
45
+ const MAX_MOOD_COUNT = 255
46
+
47
+ const MoodPage = () => {
48
+ const routeParams = useRoute().params as MoodPageProps
49
+ const params: MoodPageProps = {
50
+ ...routeParams,
51
+ }
52
+ const deviceInfo = useDeviceInfo()
53
+ const uaGroupInfo = useUAGroupInfo()
54
+ const navigation = useNavigation()
55
+ const [scene, setScene] = useScene({
56
+ isStringLight: params.isStringLight,
57
+ isStripLight: params.isStripLight,
58
+ isSupportFan: params.isSupportFan,
59
+ isSupportUVC: params.isSupportUVC
60
+ })
61
+ const [moods, setMoods] = useMoods()
62
+ const [workMode] = useWorkMode()
63
+ const [switchLed] = useSwitchLed()
64
+ const state = useReactive<MoodPageUIState>({
65
+ currentScene: undefined,
66
+ staticTagChecked: true,
67
+ dynamicTagChecked: true,
68
+ showAddMoodPopover: false,
69
+ scenes: cloneDeep(moods),
70
+ flag: Symbol(),
71
+ originScene: [],
72
+ filteredMoods: [],
73
+ loading: false,
74
+ })
75
+
76
+ useEffect(() => {
77
+ if (!(moods && moods.length)) {
78
+ getRemoteSceneList(uaGroupInfo.tyGroupId.toString(), {
79
+ isSupportColor: params.isSupportColor,
80
+ isSupportTemperature: params.isSupportTemperature,
81
+ isSupportBrightness: params.isSupportBrightness,
82
+ isStringLight: params.isStringLight,
83
+ isStripLight: params.isStripLight,
84
+ isSupportFan: params.isSupportFan,
85
+ isSupportUVC: params.isSupportUVC
86
+ }).then(res => {
87
+ if (res.success && res.data) {
88
+ setMoods(res.data)
89
+ // @ts-ignore
90
+ state.scenes = cloneDeep(res.data)
91
+ }
92
+ })
93
+ }
94
+ }, [])
95
+
96
+ const checkedMood = (currentMood?: SceneUIState): SceneUIState | undefined=>{
97
+ if(currentMood){
98
+ return {
99
+ ...currentMood,
100
+ nodes: currentMood.nodes.map(node =>({
101
+ ...node,
102
+ h: node.h,
103
+ s: node.isColorNode ? node.s : 50,
104
+ v: node.isColorNode ? node.v : 80,
105
+ colorTemp: node.isColorNode ? 100 : node.colorTemp,
106
+ brightness: node.isColorNode ? 100 : node.brightness
107
+ }))
108
+ }
109
+ }
110
+ return currentMood
111
+ }
112
+
113
+ const navigationRoute = (isStatic: boolean, mode: 'add' | 'edit', currentMood?: SceneUIState) => {
114
+ const path = mode === 'add' ? ui_biz_routerKey.group_ui_biz_mood_add : isStatic ? ui_biz_routerKey.group_ui_biz_static_mood_edit : ui_biz_routerKey.group_ui_biz_dynamic_mood_edit
115
+ navigation.navigate(path, {
116
+ mode,
117
+ isStatic,
118
+ moods: state.scenes,
119
+ currentMood: checkedMood(currentMood),
120
+ moduleParams: params,
121
+ modDeleteMood
122
+ })
123
+ }
124
+
125
+ const modDeleteMood = async (mode: 'add' | 'edit' | 'del', currentMood: SceneUIState) => {
126
+ const checkedMood = {
127
+ ...currentMood,
128
+ nodes: currentMood.nodes.map(node => {
129
+ if(mode !== 'del'){
130
+ if(node.isColorNode){
131
+ node.brightness = 0
132
+ node.colorTemp = 0
133
+ }else{
134
+ node.h = 0
135
+ node.s = 0
136
+ node.v = 0
137
+ if(!params.isSupportTemperature){
138
+ node.colorTemp = 100 // 适配dim灯
139
+ }
140
+ }
141
+ return node
142
+ }
143
+ return node
144
+ })
145
+ }
146
+
147
+ let newScene: SceneUIState[] = []
148
+ if (mode === 'add') {
149
+ newScene = [
150
+ checkedMood,
151
+ ...state.scenes,
152
+ ]
153
+ } else if (mode === 'del') {
154
+ newScene = state.scenes.filter(item => item.id !== checkedMood.id)
155
+ } else {
156
+ newScene = state.scenes.map(item => {
157
+ if (item.id === checkedMood.id) {
158
+ return checkedMood
159
+ }
160
+ return item
161
+ })
162
+ }
163
+ const mood = mode === 'del' ? (newScene.length === 0 ? undefined : newScene[0]) : checkedMood
164
+ const res = await saveScene(uaGroupInfo.tyGroupId.toString(), cloneDeep(newScene), {
165
+ isStringLight: params.isStringLight,
166
+ isStripLight: params.isStripLight,
167
+ isSupportFan: params.isSupportFan,
168
+ isSupportUVC: params.isSupportUVC
169
+ })
170
+ if (res.success) {
171
+ state.scenes = cloneDeep(newScene)
172
+ setMoods(cloneDeep(newScene))
173
+ return setScene({
174
+ scene: cloneDeep(mood),
175
+ sceneDataDpCode: params.sceneDataDpCode,
176
+ workModeDpCode: params.workModeDpCode,
177
+ workMode: mood ? WorkMode.Scene : (params.isSupportColor ? WorkMode.Colour : WorkMode.White),
178
+ switchLedDpCode: params.switchLedDpCode
179
+ })
180
+ }
181
+ return {
182
+ success: false
183
+ }
184
+ }
185
+
186
+ const onAddMoodDialogItemClick = useCallback((isStatic: boolean, _: number) => {
187
+ if (!!state.scenes) {
188
+ navigationRoute(isStatic, 'add')
189
+ }
190
+ state.showAddMoodPopover = false
191
+ }, [state.scenes])
192
+
193
+ const getCustomList = (isFantasyScene: boolean) =>{
194
+ const customList = [
195
+ {
196
+ text: Strings.getLang('mood_overview_add_mood_text'),
197
+ value: true,
198
+ },
199
+ {
200
+ text: Strings.getLang('mood_overview_add_mood_text2'),
201
+ value: false,
202
+ },
203
+ ]
204
+ if(isFantasyScene){
205
+ return customList.filter(c => !c.value)
206
+ }
207
+ return customList
208
+ }
209
+
210
+ useEffect(() => {
211
+ state.filteredMoods = state.scenes.filter(item => {
212
+ return (state.staticTagChecked && state.dynamicTagChecked) ||
213
+ (!state.staticTagChecked && !state.dynamicTagChecked) ||
214
+ (state.staticTagChecked && item.nodes.length < 2) ||
215
+ (state.dynamicTagChecked && item.nodes.length > 1)
216
+ })
217
+ }, [state.staticTagChecked, state.dynamicTagChecked, state.scenes])
218
+
219
+ const gradientMode = useMemo(() => (
220
+ params.isStringLight ? SceneMode.StringGradient : params.isStripLight ? SceneMode.StripGradient : SceneMode.SourceGradient
221
+ ), [params.isStringLight, params.isStripLight, SceneMode])
222
+ return (
223
+ <>
224
+ <Page
225
+ backText={deviceInfo.name}
226
+ headlineText={Strings.getLang('mood_overview_headline_text')}
227
+ headlineIcon={state.scenes.length < MAX_MOOD_COUNT ? res.add : undefined}
228
+ onHeadlineIconClick={() => {
229
+ state.showAddMoodPopover = !state.showAddMoodPopover
230
+ }}
231
+ loading={state.loading}>
232
+ <View style={styles.tagLine}>
233
+ <Tag
234
+ checked={state.staticTagChecked}
235
+ text={Strings.getLang('mood_overview_filter_name_text1')}
236
+ onCheckedChange={checked => {
237
+ state.staticTagChecked = checked
238
+ }} />
239
+ <Spacer width={cx(8)} height={0} />
240
+ <Tag
241
+ checked={state.dynamicTagChecked}
242
+ text={Strings.getLang('mood_overview_filter_name_text2')}
243
+ onCheckedChange={checked => {
244
+ state.dynamicTagChecked = checked
245
+ }} />
246
+ </View>
247
+ <Spacer height={cx(10)} />
248
+ {
249
+ state.scenes.length >= MAX_MOOD_COUNT &&
250
+ <View style={styles.infoLine}>
251
+ <Spacer height={cx(10)} />
252
+ <InfoText
253
+ icon={res.ic_warning_amber}
254
+ text={Strings.getLang('mood_overview_warning_max_number_text')}
255
+ contentColor={'#ff9500'} />
256
+ <Spacer height={cx(6)} />
257
+ </View>
258
+ }
259
+ <FlatList
260
+ // @ts-ignore
261
+ data={state.filteredMoods}
262
+ renderItem={({ item }) => {
263
+ return (
264
+ <MoodItem
265
+ enable={switchLed && workMode === WorkMode.Scene && scene?.scene?.id === item.id}
266
+ mood={item}
267
+ onPress={() => {
268
+ navigationRoute(item.nodes.length === 1, 'edit', item)
269
+ }}
270
+ type={item.mode === gradientMode ? 'gradient' : 'separate'}
271
+ onSwitch={async _ => {
272
+ state.loading = true
273
+ await setScene({
274
+ scene: cloneDeep(item),
275
+ sceneDataDpCode: params.sceneDataDpCode,
276
+ workModeDpCode: params.workModeDpCode,
277
+ workMode: WorkMode.Scene,
278
+ switchLedDpCode: params.switchLedDpCode
279
+ })
280
+ state.loading = false
281
+ }} />
282
+ )
283
+ }}
284
+ ListHeaderComponent={() => (<Spacer height={cx(10)} />)}
285
+ ItemSeparatorComponent={() => (<Spacer />)}
286
+ ListFooterComponent={() => (
287
+ <View style={styles.infoLine}>
288
+ <Spacer />
289
+ <InfoText
290
+ icon={res.ic_info}
291
+ text={Strings.getLang('mood_overview_information_text')} />
292
+ <Spacer height={cx(40)} />
293
+ </View>
294
+ )}
295
+ keyExtractor={item => `${item.id}`} />
296
+ </Page>
297
+ <CustomListDialog
298
+ show={state.showAddMoodPopover}
299
+ style={styles.addMoodPopover}
300
+ itemStyle={styles.popoverItem}
301
+ onDismiss={() => {
302
+ state.showAddMoodPopover = false
303
+ }}
304
+ data={getCustomList(!!(params.isStringLight || params.isStripLight))}
305
+ onItemPress={onAddMoodDialogItemClick} />
306
+ </>
307
+ )
308
+ }
309
+
310
+ const styles = StyleSheet.create({
311
+ tagLine: {
312
+ flexDirection: 'row',
313
+ marginHorizontal: cx(24),
314
+ },
315
+ infoLine: {
316
+ marginHorizontal: cx(24),
317
+ },
318
+ addMoodPopover: {
319
+ width: cx(171),
320
+ height: cx(90.5),
321
+ marginStart: cx(156),
322
+ marginTop: cx(105),
323
+ backgroundColor: '#fff',
324
+ },
325
+ popoverItem: {
326
+ width: cx(171),
327
+ height: cx(45),
328
+ alignItems: 'flex-start',
329
+ },
330
+ })
331
+
332
+ export default MoodPage
@@ -0,0 +1,75 @@
1
+ import { StyleSheet, View } from 'react-native'
2
+ import React from 'react'
3
+ import Card from '@ledvance/base/src/components/Card'
4
+ import { Utils } from 'tuya-panel-kit'
5
+ import MoodColorsLine, { MoodColorsLineType } from '@ledvance/base/src/components/MoodColorsLine'
6
+ import Spacer from '@ledvance/base/src/components/Spacer'
7
+ import { hsv2Hex } from '@ledvance/base/src/utils'
8
+ import { CellContent } from '@ledvance/base/src/components/Cell'
9
+ import { cctToColor } from '@ledvance/base/src/utils/cctUtils'
10
+ import {SceneNodeInfo} from './SceneInfo'
11
+
12
+ const cx = Utils.RatioUtils.convertX
13
+
14
+ export interface ColorsLineProps {
15
+ type: MoodColorsLineType
16
+ nodes?: SceneNodeInfo[]
17
+ }
18
+
19
+ interface RecommendMoodItemProps {
20
+ title: string
21
+ moodColorsLineProps?: ColorsLineProps
22
+ onPress: () => void
23
+ }
24
+
25
+ export default function RecommendMoodItem(props: RecommendMoodItemProps) {
26
+ return (
27
+ <Card style={styles.root} onPress={props.onPress}>
28
+ <CellContent
29
+ title={props.title}
30
+ value={''}
31
+ style={styles.content}
32
+ titleStyle={styles.title}
33
+ iconStyle={{
34
+ color: '#000',
35
+ size: cx(16),
36
+ }} />
37
+ {(!!props.moodColorsLineProps) &&
38
+ (<>
39
+ <View style={styles.lineStyle}>
40
+ <MoodColorsLine type={props.moodColorsLineProps!!.type}
41
+ colors={props.moodColorsLineProps!!.nodes!!.map(node => {
42
+ return node.isColorNode ?
43
+ hsv2Hex(node.h, node.s, node.v) :
44
+ cctToColor(node.colorTemp.toFixed())
45
+ })} />
46
+ </View>
47
+ <Spacer height={cx(24)} />
48
+ </>
49
+ )
50
+ }
51
+ </Card>
52
+ )
53
+ }
54
+
55
+ const styles = StyleSheet.create({
56
+ root: {
57
+ flexDirection: 'row',
58
+ alignItems: 'center',
59
+ marginHorizontal: cx(24),
60
+ },
61
+ content: {
62
+ height: cx(56),
63
+ marginHorizontal: cx(16),
64
+ width: cx(295)
65
+ },
66
+ title: {
67
+ color: '#000',
68
+ fontSize: cx(16),
69
+ fontFamily: 'helvetica_neue_lt_std_bd',
70
+ },
71
+ lineStyle: {
72
+ alignItems: 'center',
73
+ marginHorizontal: cx(16),
74
+ },
75
+ })