@ledvance/ui-biz-bundle 1.1.104 → 1.1.106

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.
@@ -0,0 +1,359 @@
1
+ import React, {useEffect, useMemo} from 'react';
2
+ import {Image, ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native';
3
+ import {cloneDeep, isEqual} from 'lodash';
4
+ import {useReactive} from 'ahooks';
5
+ import Page from '@ledvance/base/src/components/Page';
6
+ import I18n from '@ledvance/base/src/i18n';
7
+ import {useNavigation} from '@react-navigation/native';
8
+ import TextField from '@ledvance/base/src/components/TextField';
9
+ import {Utils} from 'tuya-panel-kit';
10
+ import Card from '@ledvance/base/src/components/Card';
11
+ import Spacer from '@ledvance/base/src/components/Spacer';
12
+ import res from '@ledvance/base/src/res';
13
+ import TextButton from '@ledvance/base/src/components/TextButton';
14
+ import {useParams} from '@ledvance/base/src/hooks/Hooks';
15
+ import LdvSwitch from '@ledvance/base/src/components/ldvSwitch';
16
+ import {showDialog} from '@ledvance/base/src/utils/common';
17
+ import ColorAdjustView from '@ledvance/base/src/components/ColorAdjustView';
18
+ import ThemeType from '@ledvance/base/src/config/themeType'
19
+ import DiySceneNodeView from "@ledvance/base/src/components/DiySceneNodeView";
20
+ import { useLoveScenes} from "./DiySceneActions";
21
+ import LdvSlider from "@ledvance/base/src/components/ldvSlider";
22
+ import {Result} from "@ledvance/base/src/models/modules/Result";
23
+ import {ui_biz_routerKey} from "../../navigation/Routers";
24
+ import {DiySceneInfo} from "@ledvance/base/src/utils/interface";
25
+
26
+ const cx = Utils.RatioUtils.convertX;
27
+ const { withTheme } = Utils.ThemeUtils
28
+
29
+ export interface DiySceneEditorPageParams {
30
+ mode: 'add' | 'edit'
31
+ currentScene: DiySceneInfo
32
+ nameRepeat: (mood: DiySceneInfo) => boolean
33
+ sceneInfoOperation: (mode: 'add' | 'edit' | 'del', currentScene?: DiySceneInfo) => Promise<Result<any>>
34
+ }
35
+
36
+ export interface DiySceneEditorPageState {
37
+ headline: string;
38
+ h: number
39
+ s: number
40
+ v: number
41
+ sceneInfo: DiySceneInfo;
42
+ loading: boolean;
43
+ currentNode: number,
44
+ position: 'Top' | 'Bottom'
45
+ }
46
+
47
+ const DiySceneEditorPage = (props: { theme?: ThemeType }) => {
48
+ const navigation = useNavigation();
49
+ const routeParams = useParams<DiySceneEditorPageParams>();
50
+ const params = cloneDeep(routeParams);
51
+ const [loveScenes, setLoveScenes] = useLoveScenes()
52
+ const state = useReactive<DiySceneEditorPageState>({
53
+ headline: '',
54
+ h: 359,
55
+ s: 100,
56
+ v: 100,
57
+ sceneInfo: params.currentScene,
58
+ loading: false,
59
+ currentNode: 0,
60
+ position: 'Top'
61
+ });
62
+
63
+ useEffect(() => {
64
+ state.headline = I18n.getLang(
65
+ params.mode === 'add' ? 'string_light_pp_sm_headline_add' : 'edit_static_mood_headline_text'
66
+ );
67
+ }, [params.mode]);
68
+
69
+ useEffect(() => {
70
+ if (state.sceneInfo.nodes.length > 0) {
71
+ const color = state.sceneInfo.nodes[0].top;
72
+ state.h = color.h
73
+ state.s = Math.round(color.s / 10)
74
+ state.v = Math.round((state.sceneInfo.v || 1000) / 10)
75
+ }
76
+ }, []);
77
+
78
+ const onRightClick = async () => {
79
+ if (state.loading || !canSaveMoodData) return;
80
+ state.loading = true;
81
+ const newScene: DiySceneInfo = {
82
+ ...state.sceneInfo
83
+ };
84
+ const res = await params.sceneInfoOperation(params.mode, newScene);
85
+ state.loading = false;
86
+ if (res.success) {
87
+ navigation.navigate(ui_biz_routerKey.ui_biz_diy_scene_page);
88
+ }
89
+ };
90
+
91
+ const nameRepeat = useMemo(() => {
92
+ return params.nameRepeat(state.sceneInfo)
93
+ }, [state.sceneInfo.name]);
94
+
95
+ const isLove = useMemo(() => {
96
+ return loveScenes.some(it => it === state.sceneInfo.id)
97
+ }, [loveScenes]);
98
+
99
+ const checkSceneChanged = useMemo(() => {
100
+ return isEqual(state.sceneInfo, params.currentScene)
101
+ }, [JSON.stringify(state.sceneInfo), {}])
102
+
103
+ const canSaveMoodData = useMemo(() => {
104
+ return state.sceneInfo.name.length > 0 && state.sceneInfo.name.length < 33 && !nameRepeat && (params.mode === 'add' || !checkSceneChanged)
105
+ }, [nameRepeat, state.sceneInfo.name, checkSceneChanged, params.currentScene])
106
+
107
+ const toggleLoveScene = (id: number) => {
108
+ const newLoveScenes = loveScenes
109
+ const index = newLoveScenes.indexOf(id)
110
+ if (index !== -1) {
111
+ if (newLoveScenes.length <= 2) {
112
+ showLoveNumAlert()
113
+ } else {
114
+ newLoveScenes.splice(index, 1)
115
+ }
116
+ } else {
117
+ if (newLoveScenes.length >= 14) {
118
+ showLoveNumAlert()
119
+ } else {
120
+ newLoveScenes.push(id)
121
+ }
122
+ }
123
+ setLoveScenes(newLoveScenes).then()
124
+ }
125
+
126
+ const showLoveNumAlert = () => {
127
+ showDialog({
128
+ method: 'alert',
129
+ title: I18n.getLang('love_mood_alert_title'),
130
+ subTitle: I18n.getLang('love_mood_alert_content'),
131
+ onConfirm: async (_, { close }) => {
132
+ close()
133
+ }
134
+ })
135
+ }
136
+
137
+
138
+ const styles = StyleSheet.create({
139
+ root: {
140
+ flex: 1,
141
+ flexDirection: 'column',
142
+ },
143
+ name: {
144
+ marginHorizontal: cx(24),
145
+ },
146
+ nodeCard: {
147
+ marginHorizontal: cx(24),
148
+ },
149
+ nodeOperation: {
150
+ flexDirection: 'row',
151
+ justifyContent: 'flex-end',
152
+ marginTop: cx(12),
153
+ paddingHorizontal: cx(12),
154
+ },
155
+ nodeList: {
156
+ display: 'flex',
157
+ flexDirection: 'row',
158
+ justifyContent: 'flex-start',
159
+ flexWrap: 'wrap',
160
+ },
161
+ adjustCard: {
162
+ marginTop: cx(12),
163
+ marginHorizontal: cx(24),
164
+ },
165
+ fanAdjustCard: {
166
+ marginHorizontal: cx(24),
167
+ },
168
+ preview: {
169
+ width: cx(20),
170
+ height: cx(20),
171
+ marginStart: cx(12),
172
+ borderRadius: cx(4),
173
+ },
174
+ deleteBtn: {
175
+ width: '100%',
176
+ height: cx(50),
177
+ backgroundColor: props.theme?.button.delete,
178
+ borderRadius: cx(8),
179
+ },
180
+ deleteBtnText: {
181
+ color: props.theme?.button.fontColor,
182
+ fontSize: cx(16),
183
+ fontFamily: 'helvetica_neue_lt_std_bd',
184
+ },
185
+ })
186
+
187
+ return (
188
+ <Page
189
+ backText={I18n.getLang('mesh_device_detail_mode')}
190
+ showBackDialog={!checkSceneChanged}
191
+ backDialogTitle={I18n.getLang(
192
+ params.mode === 'add'
193
+ ? 'string_light_pp_dialog_sm_add_headline_c'
194
+ : 'manage_user_unsaved_changes_dialog_headline'
195
+ )}
196
+ backDialogContent={I18n.getLang(
197
+ params.mode === 'add'
198
+ ? 'strip_light_static_mood_add_step_2_dialog_text'
199
+ : 'strip_light_static_mood_editor_step_2_dialog_text'
200
+ )}
201
+ headlineText={state.headline}
202
+ headlineIconContent={
203
+ state.sceneInfo.type !== 'DIY' && <TouchableOpacity onPress={() => {
204
+ toggleLoveScene(state.sceneInfo.id)
205
+ }}>
206
+ {isLove ? <Image source={res.like} style={{width: cx(24), height: cx(24)}}/>
207
+ : <Image source={res.un_like}
208
+ style={{width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor}}/>}
209
+ </TouchableOpacity>
210
+ }
211
+ rightButtonIcon={canSaveMoodData ? res.ic_check : res.ic_uncheck}
212
+ rightButtonIconClick={onRightClick}
213
+ loading={state.loading}
214
+ >
215
+ <ScrollView style={{ flex: 1 }} nestedScrollEnabled={true}>
216
+ <View style={styles.root}>
217
+ <TextField
218
+ style={styles.name}
219
+ value={state.sceneInfo.name}
220
+ placeholder={I18n.getLang('edit_static_mood_inputfield_topic_text')}
221
+ onChangeText={text => {
222
+ state.sceneInfo.name = text;
223
+ }}
224
+ maxLength={33}
225
+ showError={state.sceneInfo.name.length > 32 || nameRepeat}
226
+ tipColor={nameRepeat ? props.theme?.global.error : undefined}
227
+ tipIcon={nameRepeat ? res.ic_text_field_input_error : undefined}
228
+ errorText={I18n.getLang(
229
+ nameRepeat ? 'string_light_pp_field_sm_add_error1' : 'add_new_dynamic_mood_alert_text'
230
+ )}
231
+ />
232
+ {
233
+ state.sceneInfo.type === 'DIY' && <Card style={styles.nodeCard}>
234
+ <View style={styles.nodeOperation}>
235
+ {state.sceneInfo.nodes.length < 8 && <TouchableOpacity onPress={() => {
236
+ console.log('onPress add node')
237
+ const color = {h: state.h, s: state.s * 10, v: 1000}
238
+ state.sceneInfo.nodes.push({top: color, bottom: color});
239
+ }}>
240
+ <Image source={res.ic_plus} style={{tintColor: props.theme?.icon.primary}} />
241
+ </TouchableOpacity>}
242
+ { state.sceneInfo.nodes.length > 2 && <TouchableOpacity onPress={() => {
243
+ console.log('onPress delete node')
244
+ state.sceneInfo.nodes.splice(state.currentNode, 1)
245
+ state.currentNode = state.currentNode === state.sceneInfo.nodes.length ? 0 : state.currentNode
246
+ console.log('nextNode', state.currentNode)
247
+ }}>
248
+ <Image source={res.ic_mood_del} style={{marginLeft: cx(5),tintColor: props.theme?.icon.primary}} />
249
+ </TouchableOpacity>}
250
+ </View>
251
+ <View style={styles.nodeList}>
252
+ {state.sceneInfo.nodes.map((node, index) => (
253
+ <DiySceneNodeView
254
+ key={index}
255
+ isCurrent={state.currentNode === index}
256
+ position={state.position}
257
+ topColor={node.top}
258
+ bottomColor={node.bottom}
259
+ onChangePosition={(position: 'Top' | 'Bottom') => {
260
+ state.currentNode = index
261
+ state.position = position
262
+ const color = state.sceneInfo.nodes[index];
263
+ state.h = position === 'Top' && color.top.h || color.bottom.h
264
+ state.s = Math.round((position === 'Top' && color.top.s || color.bottom.s) / 10)
265
+ }}
266
+ />
267
+ ))}
268
+ </View>
269
+ </Card>
270
+ }
271
+ <Card style={styles.adjustCard}>
272
+ <LdvSwitch
273
+ title={I18n.getLang('light_sources_tile_tw_lighting_headline')}
274
+ color={''}
275
+ colorAlpha={1}
276
+ enable={false}
277
+ setEnable={() => {}}
278
+ showSwitch={false}
279
+ />
280
+ {
281
+ state.sceneInfo.type === 'DIY' && <ColorAdjustView
282
+ reserveSV={true}
283
+ h={state.h}
284
+ s={state.s}
285
+ v={state.v}
286
+ onHSVChange={() => {}}
287
+ onHSVChangeComplete={(h, s, v) => {
288
+ state.h = h
289
+ state.s = s
290
+ state.v = v
291
+ state.sceneInfo.v = v * 10
292
+ const node = state.sceneInfo.nodes && state.sceneInfo.nodes[state.currentNode]
293
+ if (node) {
294
+ const color = { h: h, s: s * 10, v: 1000 }
295
+ state.position === 'Top' && (node.top = color) || (node.bottom = color)
296
+ }
297
+ }} />
298
+ }
299
+ {
300
+ state.sceneInfo.type !== 'DIY' && <LdvSlider
301
+ title={I18n.getLang('light_sources_tile_rgb_lighting_brightness')}
302
+ min={1}
303
+ value={Math.round((state.sceneInfo.v || 1000) / 10)}
304
+ onValueChange={(v: number) => {state.sceneInfo.v = v * 10}}
305
+ onSlidingComplete={(v: number) => {state.sceneInfo.v = v * 10}}/>
306
+ }
307
+ <Spacer />
308
+ </Card>
309
+
310
+ {
311
+ state.sceneInfo.type !== 'Static' && <Card style={styles.adjustCard}>
312
+ <LdvSlider
313
+ title={I18n.getLang('add_new_dynamic_mood_ceiling_fan_field_text')}
314
+ value={state.sceneInfo.speed || 1}
315
+ min={1}
316
+ max={100}
317
+ onValueChange={(v: number) => {
318
+ state.sceneInfo.speed = v
319
+ }}
320
+ onSlidingComplete={(v: number) => {
321
+ state.sceneInfo.speed = v
322
+ }}
323
+ subTitleStr={`${(state.sceneInfo.speed || 1)}/100`}/>
324
+ </Card>
325
+ }
326
+
327
+ {(params.mode === 'edit' && state.sceneInfo.type === 'DIY') && (
328
+ <View style={{ marginTop: cx(20), marginHorizontal: cx(24) }}>
329
+ <TextButton
330
+ style={styles.deleteBtn}
331
+ textStyle={styles.deleteBtnText}
332
+ text={I18n.getLang('edit_static_mood_button_delete_text')}
333
+ onPress={() => {
334
+ showDialog({
335
+ method: 'confirm',
336
+ title: I18n.getLang('string_light_pp_dialog_sm_ed_headline_d'),
337
+ subTitle: I18n.getLang(`strip_light_static_mood_edit_dialog_text`),
338
+ onConfirm: async (_, { close }) => {
339
+ close();
340
+ state.loading = true;
341
+ const res = await params.sceneInfoOperation('del', state.sceneInfo);
342
+ state.loading = false;
343
+ if (res.success) {
344
+ navigation.navigate(ui_biz_routerKey.ui_biz_diy_scene_page);
345
+ }
346
+ }
347
+ })
348
+ }}
349
+ />
350
+ </View>
351
+ )}
352
+ <Spacer />
353
+ </View>
354
+ </ScrollView>
355
+ </Page>
356
+ );
357
+ };
358
+
359
+ export default withTheme(DiySceneEditorPage)
@@ -0,0 +1,297 @@
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 {useDeviceId, useDeviceInfo, useMoods,} from '@ledvance/base/src/models/modules/NativePropsSlice';
5
+ import {useReactive} from 'ahooks';
6
+ import I18n from '@ledvance/base/src/i18n';
7
+ import res from '@ledvance/base/src/res';
8
+ import {FlatList, Image, Platform, StyleSheet, TouchableOpacity, View} from 'react-native';
9
+ import Tag from '@ledvance/base/src/components/Tag';
10
+ import Spacer from '@ledvance/base/src/components/Spacer';
11
+ import InfoText from '@ledvance/base/src/components/InfoText';
12
+ import {useNavigation} from '@react-navigation/core';
13
+ import {showDialog} from '@ledvance/base/src/utils/common';
14
+ import ThemeType from '@ledvance/base/src/config/themeType'
15
+ import DiySceneItem from "@ledvance/base/src/components/DiySceneItem";
16
+ import {
17
+ getMixSceneList,
18
+ saveMixSceneList,
19
+ useDiySceneId,
20
+ useSceneData,
21
+ useSceneId,
22
+ useSceneStatus,
23
+ useSwitchLed,
24
+ useWorkMode
25
+ } from "./DiySceneActions";
26
+ import {cloneDeep, difference, head, range} from "lodash";
27
+ import {DiySceneInfo, SceneStatusType, WorkMode} from "@ledvance/base/src/utils/interface";
28
+ import {ui_biz_routerKey} from "../../navigation/Routers";
29
+
30
+
31
+ const cx = Utils.RatioUtils.convertX;
32
+ const { withTheme } = Utils.ThemeUtils
33
+
34
+ const MAX_MOOD_COUNT = 255;
35
+
36
+ const DiyScenePage = (props: { theme?: ThemeType }) => {
37
+ const deviceInfo = useDeviceInfo();
38
+ const devId = useDeviceId();
39
+ const [switchLed] = useSwitchLed()
40
+ const [workMode, setWorkMode] = useWorkMode()
41
+ const [sceneStatusId, setSceneStatus] = useSceneStatus()
42
+ const [sceneId] = useSceneId()
43
+ const [diySceneId] = useDiySceneId()
44
+ const [setSceneData] = useSceneData()
45
+ const [scenes, setScenes] = useMoods()
46
+ const navigation = useNavigation();
47
+ const DEFAULT_SCENE: DiySceneInfo = {
48
+ id: -1,
49
+ type: 'DIY',
50
+ name: '',
51
+ speed: 50,
52
+ v: 1000,
53
+ nodes: [{top: {h: 359, s: 1000, v: 1000}, bottom: {h: 120, s: 1000, v: 1000}},
54
+ {top: {h: 359, s: 1000, v: 1000}, bottom: {h: 120, s: 1000, v: 1000}}]
55
+ }
56
+
57
+ const state = useReactive({
58
+ currentMood: undefined,
59
+ staticTagChecked: true,
60
+ dynamicTagChecked: true,
61
+ diyTagChecked: true,
62
+ showAddMoodPopover: false,
63
+ originScenes: cloneDeep(scenes) as DiySceneInfo[],
64
+ filterMoods: [] as DiySceneInfo[],
65
+ loading: false,
66
+ timerId: undefined as any,
67
+ flag: Symbol(),
68
+ });
69
+
70
+ const filterScenes = useMemo(() => {
71
+ return state.originScenes.filter(item => {
72
+ return [state.staticTagChecked, state.dynamicTagChecked, state.diyTagChecked].every(it => !it)
73
+ || (state.staticTagChecked && item.type === 'Static')
74
+ || (state.dynamicTagChecked && item.type === 'Dynamic')
75
+ || (state.diyTagChecked && item.type === 'DIY')
76
+ })
77
+ }, [JSON.stringify(state.originScenes), state.staticTagChecked, state.dynamicTagChecked, state.diyTagChecked])
78
+
79
+ const newSceneId = useMemo(() => {
80
+ const existsIds = state.originScenes.filter(it => it.type === 'DIY').map(it => it.id)
81
+ const idRange = range(1, 256);
82
+ const newId: number = head(difference(idRange, existsIds)) || 0;
83
+ return newId
84
+ }, [state.originScenes])
85
+
86
+ useEffect(() => {
87
+ if (sceneId) {
88
+ setSceneStatus(SceneStatusType.Scene, sceneId).then()
89
+ }
90
+ }, [sceneId])
91
+
92
+ useEffect(() => {
93
+ if (diySceneId) {
94
+ setSceneStatus(SceneStatusType.DIY, diySceneId).then()
95
+ }
96
+ }, [diySceneId])
97
+
98
+ const getRemoteMixSceneInfo = async (isRefresh?: boolean) => {
99
+ state.loading = true
100
+ const res = await getMixSceneList(devId, isRefresh)
101
+ state.loading = false
102
+ if (res.success && Array.isArray(res.data)) {
103
+ setScenes(res.data)
104
+ state.originScenes = cloneDeep(res.data);
105
+ }
106
+ }
107
+
108
+ const navigationRoute = (mode: 'add' | 'edit' | 'del', currentScene?: DiySceneInfo) => {
109
+ navigation.navigate(ui_biz_routerKey.ui_biz_diy_scene_edit_page, {
110
+ mode,
111
+ currentScene,
112
+ nameRepeat,
113
+ sceneInfoOperation,
114
+ });
115
+ };
116
+
117
+ const getItemEnable = useCallback(
118
+ (sceneInfo: DiySceneInfo) => {
119
+ if (sceneStatusId !== -1) {
120
+ return sceneStatusId === sceneInfo.id && workMode === WorkMode.Scene && switchLed
121
+ }
122
+ return false
123
+ },
124
+ [workMode, switchLed, sceneStatusId]
125
+ );
126
+
127
+ const nameRepeat = useCallback((scene: DiySceneInfo) => {
128
+ return !!state.originScenes.filter(m => m.id !== scene.id).find(m => m.name === scene.name)
129
+ }, [state.originScenes])
130
+
131
+ const sceneInfoOperation = async (mode: 'add' | 'edit' | 'del' | 'set', currentScene: DiySceneInfo) => {
132
+ const checkedScene: DiySceneInfo = {
133
+ ...currentScene
134
+ };
135
+ if (mode === 'set') {
136
+ await setSceneStatus(checkedScene.type === 'DIY' ? SceneStatusType.DIY : SceneStatusType.Scene, checkedScene.id)
137
+ return setSceneData(checkedScene);
138
+ }
139
+ let newSceneList: DiySceneInfo[]
140
+ if (mode === 'add') {
141
+ checkedScene.id = newSceneId
142
+ newSceneList = [checkedScene, ...state.originScenes]
143
+ } else if (mode === 'del') {
144
+ newSceneList = state.originScenes.filter(item => item.id !== checkedScene.id)
145
+ } else {
146
+ newSceneList = state.originScenes.map(item => {
147
+ if (item.id === checkedScene.id) {
148
+ return checkedScene
149
+ }
150
+ return item
151
+ })
152
+ }
153
+ const scene = mode === 'del' ? (newSceneList.length === 0 ? undefined : newSceneList[0]) : checkedScene
154
+ const res = await saveMixSceneList(devId, newSceneList)
155
+ if (res.success) {
156
+ state.originScenes = cloneDeep(newSceneList);
157
+ setScenes(cloneDeep(newSceneList))
158
+ if (scene) {
159
+ if (mode === 'del') {
160
+ if (currentScene.id !== sceneStatusId || !switchLed) {
161
+ return {
162
+ success: true,
163
+ };
164
+ }
165
+ }
166
+ setSceneData(checkedScene).then(() => {
167
+ setSceneStatus(checkedScene.type === 'DIY' ? SceneStatusType.DIY : SceneStatusType.Scene, checkedScene.id).then()
168
+ })
169
+ } else {
170
+ if (workMode === WorkMode.Scene) {
171
+ setWorkMode(WorkMode.Colour).then()
172
+ }
173
+ }
174
+ return {
175
+ success: true,
176
+ };
177
+ } else {
178
+ return {
179
+ success: false,
180
+ };
181
+ }
182
+ }
183
+
184
+ const styles = StyleSheet.create({
185
+ tagLine: {
186
+ flexDirection: 'row',
187
+ marginHorizontal: cx(24),
188
+ },
189
+ infoLine: {
190
+ marginHorizontal: cx(24),
191
+ },
192
+ addMoodPopover: {
193
+ position: 'absolute',
194
+ right: cx(60),
195
+ top: Platform.OS === 'android' ? cx(90) : cx(130),
196
+ maxWidth: cx(200),
197
+ backgroundColor: props.theme?.card.background,
198
+ },
199
+ popoverItem: {
200
+ padding: cx(5),
201
+ alignItems: 'flex-start',
202
+ alignSelf: 'flex-start'
203
+ },
204
+ })
205
+
206
+ return (
207
+ <>
208
+ <Page
209
+ backText={deviceInfo.name}
210
+ headlineText={I18n.getLang('mood_overview_headline_text')}
211
+ headlineIcon={state.originScenes.length < MAX_MOOD_COUNT ? res.add : undefined}
212
+ onHeadlineIconClick={() => {
213
+ navigationRoute('add', cloneDeep(DEFAULT_SCENE))
214
+ }}
215
+ loading={state.loading}
216
+ >
217
+ <View style={styles.tagLine}>
218
+ <Tag
219
+ checked={state.staticTagChecked}
220
+ text={I18n.getLang('mood_overview_filter_name_text1')}
221
+ onCheckedChange={checked => {
222
+ state.staticTagChecked = checked;
223
+ }}
224
+ />
225
+ <Spacer width={cx(8)} height={0} />
226
+ <Tag
227
+ checked={state.dynamicTagChecked}
228
+ text={I18n.getLang('mood_overview_filter_name_text2')}
229
+ onCheckedChange={checked => {
230
+ state.dynamicTagChecked = checked;
231
+ }}
232
+ />
233
+ <Spacer width={cx(8)} height={0} />
234
+ <Tag
235
+ checked={state.diyTagChecked}
236
+ text={I18n.getLang('mood_overview_field_chip_diy')}
237
+ onCheckedChange={checked => {
238
+ state.diyTagChecked = checked;
239
+ }}
240
+ />
241
+ </View>
242
+ <TouchableOpacity style={{ alignItems: 'flex-end',paddingRight: cx(24) }}
243
+ onPress={() => {
244
+ showDialog({
245
+ method: 'confirm',
246
+ title: I18n.getLang('mood_resetbutton'),
247
+ subTitle: I18n.getLang('reset_mooddescription'),
248
+ onConfirm: async (_, { close }) => {
249
+ close()
250
+ await getRemoteMixSceneInfo(true)
251
+ }
252
+ })
253
+ }}
254
+ >
255
+ <Image source={res.ic_refresh} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
256
+ </TouchableOpacity>
257
+ <Spacer height={cx(10)} />
258
+ {state.originScenes.length >= MAX_MOOD_COUNT && (
259
+ <View style={styles.infoLine}>
260
+ <Spacer height={cx(10)} />
261
+ <InfoText
262
+ icon={res.ic_warning_amber}
263
+ text={I18n.getLang('mood_overview_warning_max_number_text')}
264
+ contentColor={props.theme?.global.warning}
265
+ />
266
+ <Spacer height={cx(6)} />
267
+ </View>
268
+ )}
269
+ <FlatList
270
+ data={filterScenes}
271
+ renderItem={({ item }) => {
272
+ return (
273
+ <DiySceneItem
274
+ enable={getItemEnable(item)}
275
+ scene={item}
276
+ onPress={() => {
277
+ navigationRoute('edit', item)
278
+ }}
279
+ onSwitch={async _ => {
280
+ state.loading = true;
281
+ await sceneInfoOperation('set', item);
282
+ state.loading = false;
283
+ }}
284
+ />
285
+ );
286
+ }}
287
+ ListHeaderComponent={() => <Spacer height={cx(10)} />}
288
+ ItemSeparatorComponent={() => <Spacer />}
289
+ ListFooterComponent={() => <Spacer />}
290
+ keyExtractor={item => `${item.name}`}
291
+ />
292
+ </Page>
293
+ </>
294
+ );
295
+ };
296
+
297
+ export default withTheme(DiyScenePage)
@@ -0,0 +1,25 @@
1
+ import {NavigationRoute} from "tuya-panel-kit";
2
+ import {ui_biz_routerKey} from "../../navigation/Routers";
3
+ import DiyScenePage from "./DiyScenePage";
4
+ import DiySceneEditorPage from "./DiySceneEditorPage";
5
+
6
+ const DiyScenePageRouters: NavigationRoute[] = [
7
+ {
8
+ name: ui_biz_routerKey.ui_biz_diy_scene_page,
9
+ component: DiyScenePage,
10
+ options: {
11
+ hideTopbar: true,
12
+ showOfflineView: false,
13
+ },
14
+ },
15
+ {
16
+ name: ui_biz_routerKey.ui_biz_diy_scene_edit_page,
17
+ component: DiySceneEditorPage,
18
+ options: {
19
+ hideTopbar: true,
20
+ showOfflineView: false,
21
+ },
22
+ },
23
+ ]
24
+
25
+ export default DiyScenePageRouters