@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,246 @@
1
+ import React, { useCallback, useEffect, useMemo } from "react";
2
+ import { ScrollView, Text, StyleSheet, FlatList, View, Image } from "react-native";
3
+ import { useNavigation, useRoute } from '@react-navigation/core'
4
+ import { Utils } from 'tuya-panel-kit'
5
+ import Page from "@ledvance/base/src/components/Page";
6
+ import I18n from "@ledvance/base/src/i18n";
7
+ import { useDeviceInfo, useTimeSchedule, useUAGroupInfo } from "@ledvance/base/src/models/modules/NativePropsSlice";
8
+ import res from "@ledvance/base/src/res";
9
+ import Spacer from "@ledvance/base/src/components/Spacer";
10
+ import InfoText from "@ledvance/base/src/components/InfoText"
11
+ import DeleteButton from "@ledvance/base/src/components/DeleteButton"
12
+ import ScheduleCard from "./ScheduleCard";
13
+ import { ui_biz_routerKey } from "../../navigation/Routers";
14
+ import { addTimeSchedule, modDelTimeSchedule, getTimeSchedule, modifyTimeSchedule } from "./TimeScheduleActions";
15
+ import { Timer } from './Interface'
16
+ import { useReactive, useUpdateEffect } from "ahooks";
17
+ import { cloneDeep } from "lodash";
18
+ import { SceneInfo } from "../mood/SceneInfo";
19
+ import { StripState } from "./TimeScheduleDetailPage";
20
+
21
+
22
+ const { convertX: cx } = Utils.RatioUtils
23
+ const MAX_NUM = 30
24
+ interface HSV {
25
+ h: number
26
+ s: number
27
+ v: number
28
+ }
29
+
30
+ interface DrawToolDataType {
31
+ hsv: HSV
32
+ brightness: number
33
+ temperature: number
34
+ stripState?: StripState
35
+ isColor?: boolean
36
+ }
37
+
38
+ export interface TimeSchedulePageParams {
39
+ isSupportColor: boolean
40
+ isSupportTemperature: boolean
41
+ isSupportBrightness: boolean
42
+ isSupportMood?: boolean
43
+ isStringLight?: boolean
44
+ isStripLight?: boolean
45
+ isSupportFan?: boolean
46
+ isSupportUVC?: boolean
47
+ switchLedCode?: string
48
+ switchSocket?: string
49
+ switchFan?: string
50
+ workModeCode: string
51
+ brightValueCode?: string
52
+ tempValueCode?: string
53
+ sceneDataCode?: string
54
+ sceneDataDp2Obj?: (sceneDp: string) => SceneInfo
55
+ sceneDataObj2Dp?: (scene: any) => string
56
+ colorDataCode?: string
57
+ colorDataDp2Obj?: (hex: string) => HSV
58
+ colorDataObj2Dp?: (hsv: HSV) => string
59
+ drawToolDataCode?: string
60
+ drawToolDataObj2Dp?: (dpData: DrawToolDataType) => string
61
+ drawToolDataDp2Obj?: (dp:string) => DrawToolDataType
62
+ }
63
+
64
+ const TimeSchedulePage = () => {
65
+ const deviceInfo = useDeviceInfo()
66
+ const navigation = useNavigation()
67
+ const uaGroupInfo = useUAGroupInfo()
68
+ const [timeScheduleStatus, setTimeScheduleStatus] = useTimeSchedule()
69
+ const props = cloneDeep(useRoute().params) as TimeSchedulePageParams
70
+ const state = useReactive({
71
+ timeScheduleList: [] as Timer[],
72
+ flag: Symbol(),
73
+ loading: false
74
+ })
75
+
76
+ const isMaxSchedule = useMemo(() => state.timeScheduleList.length >= MAX_NUM, [state.timeScheduleList])
77
+
78
+ useUpdateEffect(() => {
79
+ const status = state.timeScheduleList.some(item => item.status === 1)
80
+ if (status !== timeScheduleStatus) {
81
+ setTimeScheduleStatus(status)
82
+ }
83
+ }, [JSON.stringify(state.timeScheduleList)])
84
+
85
+ useEffect(() => {
86
+ getTimeScheduleList().then()
87
+ }, [state.flag])
88
+
89
+ const navigateToEdit = useCallback((mode: 'add' | 'edit', timeSchedule?: Timer) => {
90
+ const path = ui_biz_routerKey.group_ui_biz_time_schedule_edit
91
+ navigation.navigate(path, {
92
+ mode,
93
+ name: path,
94
+ timeSchedule,
95
+ modDeleteTimeSchedule,
96
+ refreshFn: () => {
97
+ state.flag = Symbol()
98
+ },
99
+ ...props
100
+ })
101
+ }, [])
102
+
103
+ const modDeleteTimeSchedule = async (mode: 'add' | 'edit' | 'del', timeSchedule: Timer, ids: string) => {
104
+ if (mode === 'add') {
105
+ return addTimeSchedule({
106
+ ...timeSchedule,
107
+ bizId: uaGroupInfo.tyGroupId.toString(),
108
+ actions: timeSchedule.dps
109
+ })
110
+ } else if (mode === 'edit') {
111
+ return modifyTimeSchedule({
112
+ ...timeSchedule,
113
+ bizId: uaGroupInfo.tyGroupId.toString(),
114
+ actions: timeSchedule.dps
115
+ })
116
+ } else {
117
+ return modDelTimeSchedule({
118
+ bizId: uaGroupInfo.tyGroupId.toString(),
119
+ status: timeSchedule.status,
120
+ ids,
121
+ })
122
+ }
123
+ }
124
+
125
+ const getTimeScheduleList = async () => {
126
+ const res = await getTimeSchedule({
127
+ bizId: uaGroupInfo.tyGroupId.toString()
128
+ })
129
+ if (res.success) {
130
+ state.timeScheduleList = res.data || []
131
+ } else {
132
+ state.timeScheduleList = []
133
+ }
134
+ }
135
+
136
+ return (
137
+ <Page
138
+ backText={deviceInfo.name}
139
+ onBackClick={navigation.goBack}
140
+ headlineText={I18n.getLang('timeschedule_overview_headline_text')}
141
+ headlineIcon={isMaxSchedule ? undefined : res.device_panel_schedule_add}
142
+ onHeadlineIconClick={() => {
143
+ navigateToEdit('add')
144
+ }}
145
+ loading={state.loading}
146
+ >
147
+ <ScrollView nestedScrollEnabled={true}>
148
+ <Text style={styles.overviewDescription}>{I18n.getLang('timeschedule_overview_description_text')}</Text>
149
+ <Spacer height={cx(10)} />
150
+ {isMaxSchedule && <InfoText
151
+ text={I18n.getLang('motion_detection_time_schedule_notifications_warning_text')}
152
+ icon={res.ic_warning_amber}
153
+ style={{ marginHorizontal: cx(24) }}
154
+ textStyle={{ color: '#000' }}
155
+ iconStyle={{ tintColor: '#ff9500' }}
156
+ />}
157
+ <FlatList
158
+ data={state.timeScheduleList}
159
+ renderItem={({ item }) =>
160
+ (<ScheduleCard
161
+ item={item}
162
+ onEnableChange={(enable) => {
163
+ state.loading = true
164
+ modDeleteTimeSchedule('del', {
165
+ ...item,
166
+ status: enable ? 1 : 0
167
+ }, item.id.toString()).then((res) => {
168
+ if (res.success) {
169
+ state.timeScheduleList = state.timeScheduleList.map(schedule => {
170
+ if (schedule.id === item.id) {
171
+ return {
172
+ ...schedule,
173
+ status: enable ? 1 : 0
174
+ }
175
+ }
176
+ return schedule
177
+ })
178
+ }
179
+ state.loading = false
180
+ })
181
+ }}
182
+ onPress={() => {
183
+ navigateToEdit('edit', item)
184
+ }}
185
+ onLongPress={() => { }}
186
+ />)}
187
+ keyExtractor={(item) => item.id.toString()}
188
+ ListEmptyComponent={() => (
189
+ <View style={styles.emptyContainer}>
190
+ <Spacer height={cx(60)} />
191
+ <Image
192
+ style={styles.emptyImage}
193
+ source={{ uri: res.ldv_timer_empty }}
194
+ resizeMode="contain"
195
+ />
196
+ <InfoText
197
+ icon={res.device_panel_schedule_alert}
198
+ text={I18n.getLang('timeschedule_overview_empty_information_text')}
199
+ style={{ width: 'auto', alignItems: 'center' }}
200
+ textStyle={{ color: '#000', flex: undefined }}
201
+ iconStyle={{ tintColor: '#000' }}
202
+ />
203
+ <Spacer height={cx(16)} />
204
+ <DeleteButton
205
+ style={styles.addBtn}
206
+ text={`${I18n.getLang('timeschedule_overview_empty_button_add_text')}`}
207
+ textStyle={{ fontSize: cx(12) }}
208
+ onPress={() => {
209
+ navigateToEdit('add')
210
+ }}
211
+ />
212
+ </View>
213
+ )}
214
+ ListHeaderComponent={() => <Spacer height={cx(10)} />}
215
+ ItemSeparatorComponent={() => <Spacer />}
216
+ ListFooterComponent={() => <Spacer height={cx(30)} />}
217
+ />
218
+ </ScrollView>
219
+ </Page>
220
+ )
221
+ }
222
+
223
+
224
+ const styles = StyleSheet.create({
225
+ overviewDescription: {
226
+ color: '#000',
227
+ marginHorizontal: cx(24)
228
+ },
229
+ emptyImage: {
230
+ width: cx(225),
231
+ height: cx(198),
232
+ },
233
+ emptyContainer: {
234
+ marginHorizontal: cx(24),
235
+ alignItems: 'center'
236
+ },
237
+ addBtn: {
238
+ height: cx(45),
239
+ width: 'auto',
240
+ minWidth: cx(150),
241
+ paddingHorizontal: cx(16),
242
+ backgroundColor: '#f60'
243
+ }
244
+ })
245
+
246
+ export default TimeSchedulePage
@@ -0,0 +1,12 @@
1
+ export interface TimerTask {
2
+ name: string;
3
+ startTime: number;
4
+ duration: number;
5
+ dpKey: number;
6
+ status: TaskStatus;
7
+ }
8
+ export declare enum TaskStatus {
9
+ NoSelected = 0,
10
+ Selected = 1,
11
+ Started = 2
12
+ }
@@ -0,0 +1,150 @@
1
+ import { useFeatureHook } from '@ledvance/base/src/models/modules/NativePropsSlice'
2
+ import { Result } from '@ledvance/base/src/models/modules/Result'
3
+ import dayjs from 'dayjs'
4
+ import { useCountDown, useReactive } from 'ahooks'
5
+ import { useEffect } from 'react'
6
+ import { cloneDeep } from 'lodash'
7
+
8
+ export interface TimerTask {
9
+ name: string
10
+ startTime: number
11
+ duration: number
12
+ timeLeft: number
13
+ dp: {
14
+ key: string
15
+ code: string
16
+ }
17
+ status: TaskStatus
18
+ stringOn: string
19
+ stringOff: string
20
+ }
21
+
22
+ export enum TaskStatus {
23
+ NoSelected,
24
+ Selected,
25
+ Started
26
+ }
27
+
28
+ export interface TimerConfig {
29
+ timerTasks: TimerTask[]
30
+ }
31
+
32
+ export function useTimerTasks(timerSettableDps: TimerSettableDp[]): [TimerTask[], (value: TimerTask[]) => Promise<Result<any>>] {
33
+ const countdowns = timerSettableDps.map(dps => {
34
+ const [countdown, setTargetDate] = useCountDown({ interval: 1000 })
35
+ return {
36
+ dpCode: dps.dp.code,
37
+ countdown: {
38
+ value: countdown,
39
+ setTargetDate,
40
+ },
41
+ }
42
+ })
43
+ const [tasks, setTasks] = useFeatureHook<TimerConfig, TimerTask[]>(
44
+ 'timerTasks',
45
+ timerSettableDps.map(timerSettableDp => ({
46
+ name: timerSettableDp.label,
47
+ startTime: 0,
48
+ duration: 0,
49
+ timeLeft: 0,
50
+ dp: timerSettableDp.dp,
51
+ status: TaskStatus.NoSelected,
52
+ stringOn: timerSettableDp.stringOn,
53
+ stringOff: timerSettableDp.stringOff,
54
+ })),
55
+ () => undefined,
56
+ timerTasks => {
57
+ const dps = {}
58
+ timerTasks.forEach(task => {
59
+ dps[task.dp.code] = task.duration
60
+ })
61
+ return dps
62
+ },
63
+ )
64
+
65
+ const state = useReactive({ tasks: cloneDeep(tasks) })
66
+
67
+ useEffect(() => {
68
+ state.tasks = cloneDeep(tasks)
69
+ .map(task => {
70
+ const taskEndTime = dayjs.unix(task.startTime)
71
+ .add(task.duration, 'second')
72
+ const taskIsEnd = task.status !== TaskStatus.Started ||
73
+ getTaskLeftover(task) === 0
74
+
75
+ countdowns.forEach(countdown => {
76
+ if (countdown.dpCode === task.dp.code) {
77
+ countdown.countdown.setTargetDate(taskIsEnd ? undefined : taskEndTime.toDate())
78
+ }
79
+ })
80
+
81
+ return {
82
+ ...task,
83
+ startTime: taskIsEnd ? 0 : task.startTime,
84
+ duration: taskIsEnd ? 0 : task.duration,
85
+ timeLeft: taskIsEnd ? 0 : task.timeLeft,
86
+ status: taskIsEnd ? TaskStatus.NoSelected : TaskStatus.Started,
87
+ }
88
+ })
89
+
90
+ return () => {
91
+ countdowns.forEach(countdown => {
92
+ countdown.countdown.setTargetDate(undefined)
93
+ })
94
+ }
95
+ }, [JSON.stringify(tasks)])
96
+
97
+ useEffect(() => {
98
+ countdowns.forEach(cd => {
99
+ state.tasks.forEach(task => {
100
+ if (task.dp.code === cd.dpCode) {
101
+ task.timeLeft = Math.trunc(cd.countdown.value / 1000)
102
+ if (task.timeLeft <= 0) {
103
+ task.status = TaskStatus.NoSelected
104
+ } else {
105
+ task.status = TaskStatus.Started
106
+ }
107
+ }
108
+ })
109
+ })
110
+ }, [JSON.stringify(countdowns.map(c => c.countdown.value))])
111
+
112
+ return [state.tasks, setTasks]
113
+ }
114
+
115
+ export function getTaskLeftover(timerTask: TimerTask): number {
116
+ // 当前时间和任务结束时间
117
+ const currentTime = dayjs()
118
+ const taskEndTime = dayjs.unix(timerTask.startTime).add(timerTask.duration, 'second')
119
+
120
+ // 剩余时间
121
+ const timeLeft = taskEndTime.diff(currentTime, 'second')
122
+
123
+ // 如果剩余时间小于0,返回0
124
+ return timeLeft > 0 ? timeLeft : 0
125
+ }
126
+
127
+ export interface TimerSettableDp {
128
+ label: string
129
+ dp: {
130
+ key: string
131
+ code: string
132
+ }
133
+ stringOn: string
134
+ stringOff: string
135
+ }
136
+
137
+ export interface TimerPageParams {
138
+ timerSettableDps: TimerSettableDp[]
139
+ }
140
+
141
+ export function timeFormat(time: number): string {
142
+ let hour = Math.trunc(time / 3600)
143
+ const beforeMin = (time % 3600) / 60
144
+ let min = Math.ceil(beforeMin)
145
+ if (min === 60) {
146
+ hour += 1
147
+ min = 0
148
+ }
149
+ return `${hour > 0 ? `${hour} h ` : ''}${min > 0 ? `${min} min` : ''}`
150
+ }
@@ -0,0 +1,2 @@
1
+ declare const TimerPage: () => JSX.Element;
2
+ export default TimerPage;