@ledvance/group-ui-biz-bundle 1.0.0 → 1.0.2

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/group-ui-biz-bundle",
5
5
  "pid": [],
6
6
  "uiid": "",
7
- "version": "1.0.0",
7
+ "version": "1.0.2",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -47,7 +47,6 @@ const DynamicMoodEditorPage = () => {
47
47
  sceneMode: moduleParams.isStringLight ? stringLightSceneMode : moduleParams.isStripLight ? stripLightSceneMode : lightSceneMode
48
48
  })
49
49
 
50
- const canDelete = useMemo(() => (role === 0 || role === 2), [role])
51
50
  useEffect(() => {
52
51
  state.headline = Strings.getLang(params.mode ? 'add_new_dynamic_mood_headline_text' : 'edit_static_mood_headline_text')
53
52
  }, [params.mode])
@@ -423,7 +422,7 @@ const DynamicMoodEditorPage = () => {
423
422
  state.mood.fanSpeed = fanSpeed
424
423
  }}
425
424
  style={styles.fanAdjustCard} />}
426
- {params.mode === 'edit' && canDelete &&
425
+ {params.mode === 'edit' &&
427
426
  <View style={{ marginTop: cx(20), marginHorizontal: cx(24) }}>
428
427
  <TextButton
429
428
  style={styles.deleteBtn}
@@ -85,6 +85,7 @@ const MoodPage = () => {
85
85
  isSupportUVC: params.isSupportUVC
86
86
  }).then(res => {
87
87
  if (res.success && res.data) {
88
+ console.log(res.data, '< --- res.datatata')
88
89
  setMoods(res.data)
89
90
  // @ts-ignore
90
91
  state.scenes = cloneDeep(res.data)
@@ -93,11 +94,11 @@ const MoodPage = () => {
93
94
  }
94
95
  }, [])
95
96
 
96
- const checkedMood = (currentMood?: SceneUIState): SceneUIState | undefined=>{
97
- if(currentMood){
97
+ const checkedMood = (currentMood?: SceneUIState): SceneUIState | undefined => {
98
+ if (currentMood) {
98
99
  return {
99
100
  ...currentMood,
100
- nodes: currentMood.nodes.map(node =>({
101
+ nodes: currentMood.nodes.map(node => ({
101
102
  ...node,
102
103
  h: node.h,
103
104
  s: node.isColorNode ? node.s : 50,
@@ -126,15 +127,15 @@ const MoodPage = () => {
126
127
  const checkedMood = {
127
128
  ...currentMood,
128
129
  nodes: currentMood.nodes.map(node => {
129
- if(mode !== 'del'){
130
- if(node.isColorNode){
130
+ if (mode !== 'del') {
131
+ if (node.isColorNode) {
131
132
  node.brightness = 0
132
133
  node.colorTemp = 0
133
- }else{
134
+ } else {
134
135
  node.h = 0
135
136
  node.s = 0
136
137
  node.v = 0
137
- if(!params.isSupportTemperature){
138
+ if (!params.isSupportTemperature) {
138
139
  node.colorTemp = 100 // 适配dim灯
139
140
  }
140
141
  }
@@ -190,23 +191,6 @@ const MoodPage = () => {
190
191
  state.showAddMoodPopover = false
191
192
  }, [state.scenes])
192
193
 
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
194
  useEffect(() => {
211
195
  state.filteredMoods = state.scenes.filter(item => {
212
196
  return (state.staticTagChecked && state.dynamicTagChecked) ||
@@ -218,7 +202,8 @@ const MoodPage = () => {
218
202
 
219
203
  const gradientMode = useMemo(() => (
220
204
  params.isStringLight ? SceneMode.StringGradient : params.isStripLight ? SceneMode.StripGradient : SceneMode.SourceGradient
221
- ), [params.isStringLight, params.isStripLight, SceneMode])
205
+ ), [params.isStringLight, params.isStripLight, SceneMode])
206
+
222
207
  return (
223
208
  <>
224
209
  <Page
@@ -226,7 +211,11 @@ const MoodPage = () => {
226
211
  headlineText={Strings.getLang('mood_overview_headline_text')}
227
212
  headlineIcon={state.scenes.length < MAX_MOOD_COUNT ? res.add : undefined}
228
213
  onHeadlineIconClick={() => {
229
- state.showAddMoodPopover = !state.showAddMoodPopover
214
+ if (params.isStringLight || params.isStripLight) {
215
+ onAddMoodDialogItemClick(false, 1)
216
+ } else {
217
+ state.showAddMoodPopover = !state.showAddMoodPopover
218
+ }
230
219
  }}
231
220
  loading={state.loading}>
232
221
  <View style={styles.tagLine}>
@@ -283,15 +272,7 @@ const MoodPage = () => {
283
272
  }}
284
273
  ListHeaderComponent={() => (<Spacer height={cx(10)} />)}
285
274
  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
- )}
275
+ ListFooterComponent={() => (<Spacer />)}
295
276
  keyExtractor={item => `${item.id}`} />
296
277
  </Page>
297
278
  <CustomListDialog
@@ -301,7 +282,16 @@ const MoodPage = () => {
301
282
  onDismiss={() => {
302
283
  state.showAddMoodPopover = false
303
284
  }}
304
- data={getCustomList(!!(params.isStringLight || params.isStripLight))}
285
+ data={[
286
+ {
287
+ text: Strings.getLang('mood_overview_add_mood_text'),
288
+ value: true,
289
+ },
290
+ {
291
+ text: Strings.getLang('mood_overview_add_mood_text2'),
292
+ value: false,
293
+ },
294
+ ]}
305
295
  onItemPress={onAddMoodDialogItemClick} />
306
296
  </>
307
297
  )
@@ -51,7 +51,7 @@ const StaticMoodEditorPage = () => {
51
51
  currentNode: params.currentMood.nodes[0],
52
52
  loading: false
53
53
  })
54
- const canDelete = useMemo(() => (role === 0 || role === 2), [role])
54
+
55
55
  useEffect(() => {
56
56
  state.headline = I18n.getLang(params.mode === 'add' ? 'add_new_static_mood_headline_text' : 'edit_static_mood_headline_text')
57
57
  }, [params.mode])
@@ -180,7 +180,7 @@ const StaticMoodEditorPage = () => {
180
180
  state.mood.fanSpeed = fanSpeed
181
181
  }}
182
182
  style={styles.fanAdjustCard} />}
183
- {params.mode === 'edit' && canDelete &&
183
+ {params.mode === 'edit' &&
184
184
  <View style={{ marginTop: cx(20), marginHorizontal: cx(24) }}>
185
185
  <TextButton
186
186
  style={styles.deleteBtn}
@@ -82,4 +82,9 @@ export interface IModDeleteTaskByIds {
82
82
  bizType?: string;
83
83
  ids: string;
84
84
  status?: number;
85
+ }
86
+
87
+ export enum UVCFanMode {
88
+ Nature = 'nature',
89
+ Normal = 'normal'
85
90
  }
@@ -2,8 +2,9 @@ import React from "react";
2
2
  import { ViewStyle, View, Text, StyleSheet } from "react-native";
3
3
  import Card from "@ledvance/base/src/components/Card";
4
4
  import { SwitchButton, Utils } from 'tuya-panel-kit';
5
- import { loopText } from '@ledvance/base/src/utils/common';
5
+ import { convertTo12HourFormat, loopText } from '@ledvance/base/src/utils/common';
6
6
  import { Timer } from "./Interface";
7
+ import { useSystemTimeFormate } from "@ledvance/base/src/models/modules/NativePropsSlice";
7
8
  const { convertX: cx } = Utils.RatioUtils;
8
9
 
9
10
  interface ScheduleCardProps {
@@ -16,6 +17,7 @@ interface ScheduleCardProps {
16
17
 
17
18
  const ScheduleCard = (props: ScheduleCardProps) => {
18
19
  const { item, style, onEnableChange, onPress } = props;
20
+ const is24HourClock = useSystemTimeFormate()
19
21
  return (
20
22
  <Card
21
23
  style={styles.card}
@@ -28,7 +30,7 @@ const ScheduleCard = (props: ScheduleCardProps) => {
28
30
  // onLongPress(item);
29
31
  }}>
30
32
  <View style={styles.infoContainer}>
31
- <Text style={styles.time}>{item.time}</Text>
33
+ <Text style={styles.time}>{is24HourClock ? item.time : convertTo12HourFormat(item.time)}</Text>
32
34
  <Text style={styles.loop}>
33
35
  {loopText(item.loops.split('').map(loop => parseInt(loop)), item.time)}
34
36
  </Text>
@@ -1,10 +1,10 @@
1
1
  import { commonApi } from "@tuya/tuya-panel-api"
2
- import { IAddSingleTime, IQueryTimerTasks, IModifySingleTimer, IModDeleteTaskByIds } from "./Interface"
2
+ import { IAddSingleTime, IQueryTimerTasks, IModifySingleTimer, IModDeleteTaskByIds, UVCFanMode } from "./Interface"
3
3
  import { flatMapDeep } from "lodash";
4
-
4
+ import I18n from "@ledvance/base/src/i18n";
5
5
 
6
6
  export const addTimeSchedule = async (props: IAddSingleTime) => {
7
- try{
7
+ try {
8
8
  const res = await commonApi.timerApi.addSingleTimer({
9
9
  ...props,
10
10
  bizType: '1'
@@ -17,7 +17,7 @@ export const addTimeSchedule = async (props: IAddSingleTime) => {
17
17
  return {
18
18
  success: false
19
19
  }
20
- }catch(err){
20
+ } catch (err) {
21
21
  return {
22
22
  success: false
23
23
  }
@@ -25,7 +25,7 @@ export const addTimeSchedule = async (props: IAddSingleTime) => {
25
25
  }
26
26
 
27
27
  export const getTimeSchedule = async (props: IQueryTimerTasks) => {
28
- try{
28
+ try {
29
29
  const res = await commonApi.timerApi.queryTimerTasks({
30
30
  ...props,
31
31
  bizType: '1',
@@ -40,7 +40,7 @@ export const getTimeSchedule = async (props: IQueryTimerTasks) => {
40
40
  return {
41
41
  success: false
42
42
  }
43
- }catch(err){
43
+ } catch (err) {
44
44
  return {
45
45
  success: false
46
46
  }
@@ -48,7 +48,7 @@ export const getTimeSchedule = async (props: IQueryTimerTasks) => {
48
48
  }
49
49
 
50
50
  export const modifyTimeSchedule = async (props: IModifySingleTimer) => {
51
- try{
51
+ try {
52
52
  const status = await commonApi.timerApi.modifySingleTimer({
53
53
  ...props,
54
54
  bizType: '1',
@@ -56,15 +56,15 @@ export const modifyTimeSchedule = async (props: IModifySingleTimer) => {
56
56
  return {
57
57
  success: status
58
58
  }
59
- }catch(err){
59
+ } catch (err) {
60
60
  return {
61
61
  success: false
62
62
  }
63
63
  }
64
64
  }
65
65
 
66
- export const modDelTimeSchedule = async (props: IModDeleteTaskByIds) =>{
67
- try{
66
+ export const modDelTimeSchedule = async (props: IModDeleteTaskByIds) => {
67
+ try {
68
68
  const status = await commonApi.timerApi.modDeleteTaskByIds({
69
69
  ...props,
70
70
  bizType: '1',
@@ -73,9 +73,30 @@ export const modDelTimeSchedule = async (props: IModDeleteTaskByIds) =>{
73
73
  return {
74
74
  success: status
75
75
  }
76
- }catch(err){
76
+ } catch (err) {
77
77
  return {
78
78
  success: false
79
79
  }
80
80
  }
81
+ }
82
+
83
+ export const fanModeOption = [
84
+ {
85
+ label: I18n.getLang('ceiling_fan_mode_info_option_1_headline'),
86
+ value: UVCFanMode.Normal,
87
+ },
88
+ {
89
+ label: I18n.getLang('ceiling_fan_mode_info_option_2_headline'),
90
+ value: UVCFanMode.Nature,
91
+ },
92
+ ]
93
+
94
+ export const actionOption = {
95
+ switchLed: I18n.getLang('light_sources_tile_tw_lighting_headline'),
96
+ switchSocket: I18n.getLang('feature_summary_action_component_5'),
97
+ switchSocket1: I18n.getLang('feature_summary_action_component_6'),
98
+ switchSocket2: I18n.getLang('feature_summary_action_component_7'),
99
+ switchSocket3: I18n.getLang('feature_summary_action_component_8'),
100
+ switchSocket4: I18n.getLang('feature_summary_action_component_9'),
101
+ switchFan: I18n.getLang('add_new_dynamic_mood_ceiling_fan_field_headline'),
81
102
  }
@@ -9,14 +9,14 @@ import { useCreation, useReactive } from "ahooks";
9
9
  import { SwitchButton, TimerPicker, Utils } from "tuya-panel-kit";
10
10
  import Spacer from "@ledvance/base/src/components/Spacer";
11
11
  import LdvWeekView from '@ledvance/base/src/components/weekSelect'
12
- import { loopText, showDialog } from "@ledvance/base/src/utils/common";
12
+ import { convertTo12HourFormat, loopText, showDialog } from "@ledvance/base/src/utils/common";
13
13
  import Card from "@ledvance/base/src/components/Card";
14
14
  import LdvSwitch from "@ledvance/base/src/components/ldvSwitch";
15
15
  import ApplyForDeviceList from '@ledvance/base/src/components/ApplyForDeviceList'
16
16
  import LampAdjustView from "@ledvance/base/src/components/LampAdjustView";
17
- import { Timer } from './Interface'
17
+ import { Timer, UVCFanMode } from './Interface'
18
18
  import res from "@ledvance/base/src/res";
19
- import { useGroupDevices, useMoods, useUAGroupInfo } from "@ledvance/base/src/models/modules/NativePropsSlice";
19
+ import { useGroupDevices, useMoods, useSystemTimeFormate, useUAGroupInfo } from "@ledvance/base/src/models/modules/NativePropsSlice";
20
20
  import { TimeSchedulePageParams } from "./TimeSchedulePage";
21
21
  import { Result } from "@ledvance/base/src/models/modules/Result";
22
22
  import DeleteButton from "@ledvance/base/src/components/DeleteButton";
@@ -28,8 +28,10 @@ import { dp2Obj, getRemoteSceneList, obj2Dp, stripDp2Obj, stripObj2Dp } from "..
28
28
  import FanAdjustView from "@ledvance/base/src/components/FanAdjustView";
29
29
  import { SceneMode } from "../mood/SceneInfo";
30
30
  import StripAdjustView, { ColorList } from "@ledvance/base/src/components/StripAdjustView"
31
+ import SocketItem from '@ledvance/base/src/components/SocketItem'
31
32
  import { WorkMode } from "@ledvance/base/src/utils/interface";
32
33
  import { Buffer } from 'buffer'
34
+ import { fanModeOption, actionOption } from "./TimeScheduleActions";
33
35
 
34
36
  const { convertX: cx } = Utils.RatioUtils;
35
37
  const { toFixedString } = Utils.NumberUtils;
@@ -42,16 +44,22 @@ interface TimeScheduleDetailPageParams extends TimeSchedulePageParams {
42
44
  const TimeScheduleDetailPage = () => {
43
45
  const navigation = useNavigation()
44
46
  const uaGroupInfo = useUAGroupInfo()
47
+ const is24HourClock = useSystemTimeFormate()
45
48
  const [groupDevices] = useGroupDevices()
46
49
  const [moods, setMoods] = useMoods()
47
50
  const props = cloneDeep(useRoute().params) as TimeScheduleDetailPageParams
48
51
  const state = useReactive({
49
52
  timeSchedule: props.mode === 'add' ? newTimeSchedule() : cloneDeep(props.timeSchedule),
50
53
  isManual: true, // manual ,mood
51
- isColorMode: true,
54
+ isColorMode: !!props.colorDataCode,
52
55
  switchLed: true, // light
53
- switchSocket: true,
56
+ switchSocket1: true,
57
+ switchSocket2: true,
58
+ switchSocket3: true,
59
+ switchSocketUSB: true,
54
60
  switchFan: true,
61
+ fanMode: UVCFanMode.Normal,
62
+ fanSpeed: 1,
55
63
  brightness: 100,
56
64
  temperature: 0,
57
65
  hsv: defaultHsv(),
@@ -76,6 +84,10 @@ const TimeScheduleDetailPage = () => {
76
84
  return tabs
77
85
  }, [])
78
86
 
87
+ const isPowerStrip = useMemo(() => {
88
+ return !!(props.switchSocket3 || props.switchSocketUSB)
89
+ }, [])
90
+
79
91
  const getSceneByDp = (sceneDp: string) => {
80
92
  if (props.sceneDataDp2Obj) {
81
93
  return props.sceneDataDp2Obj(sceneDp)
@@ -122,30 +134,59 @@ const TimeScheduleDetailPage = () => {
122
134
  if (props.switchLedCode && dps.hasOwnProperty(props.switchLedCode)) {
123
135
  state.switchLed = dps[props.switchLedCode]
124
136
  }
137
+ if (props.switchSocket1 && dps.hasOwnProperty(props.switchSocket1)) {
138
+ state.switchSocket1 = dps[props.switchSocket1]
139
+ }
140
+ if (props.switchSocket2 && dps.hasOwnProperty(props.switchSocket2)) {
141
+ state.switchSocket2 = dps[props.switchSocket2]
142
+ }
143
+ if (props.switchSocket3 && dps.hasOwnProperty(props.switchSocket3)) {
144
+ state.switchSocket3 = dps[props.switchSocket3]
145
+ }
146
+ if (props.switchSocketUSB && dps.hasOwnProperty(props.switchSocketUSB)) {
147
+ state.switchSocketUSB = dps[props.switchSocketUSB]
148
+ }
149
+ if (props.switchFan && dps.hasOwnProperty(props.switchFan)) {
150
+ state.switchFan = dps[props.switchFan]
151
+ }
152
+ if (props.fanModeCode && dps.hasOwnProperty(props.fanModeCode)) {
153
+ state.fanMode = dps[props.fanModeCode]
154
+ }
155
+ if (props.fanSpeedCode && dps.hasOwnProperty(props.fanSpeedCode)) {
156
+ state.fanSpeed = dps[props.fanSpeedCode]
157
+ }
125
158
  if (props.tempValueCode && dps.hasOwnProperty(props.tempValueCode)) {
126
- state.temperature = Math.round(dps[props.tempValueCode] / 10)
159
+ if (props.tempValueParser) {
160
+ state.temperature = props.tempValueParser(dps[props.tempValueCode])
161
+ } else {
162
+ state.temperature = Math.round(dps[props.tempValueCode] / 10)
163
+ }
127
164
  state.isColorMode = false
128
165
  }
129
166
  if (props.brightValueCode && dps.hasOwnProperty(props.brightValueCode)) {
130
- state.brightness = Math.round(dps[props.brightValueCode] / 10)
167
+ if (props.brightValueParser) {
168
+ state.brightness = props.brightValueParser(dps[props.brightValueCode])
169
+ } else {
170
+ state.brightness = Math.round(dps[props.brightValueCode] / 10)
171
+ }
131
172
  state.isColorMode = false
132
173
  }
133
174
  if (props.colorDataCode && dps.hasOwnProperty(props.colorDataCode)) {
134
175
  if (props.colorDataDp2Obj) {
135
176
  const color = props.colorDataDp2Obj(dps[props.colorDataCode])
177
+ state.hsv = cloneDeep(color)
178
+ if (props.isMatterLight && props.brightValueCode && dps.hasOwnProperty(props.brightValueCode) && props.brightValueParser) {
179
+ state.hsv.v = props.brightValueParser(dps[props.brightValueCode])
180
+ }
181
+ } else {
182
+ const hsv = getHSVByHex(dps[props.colorDataCode])
136
183
  state.hsv = {
137
- h: color.h,
138
- s: Math.round(color.s / 10),
139
- v: Math.round(color.v / 10),
184
+ h: hsv.h,
185
+ s: Math.round(hsv.s / 10),
186
+ v: Math.round(hsv.v / 10),
140
187
  }
141
- return
142
- }
143
- const hsv = getHSVByHex(dps[props.colorDataCode])
144
- state.hsv = {
145
- h: hsv.h,
146
- s: Math.round(hsv.s / 10),
147
- v: Math.round(hsv.v / 10),
148
188
  }
189
+ state.isColorMode = true
149
190
  }
150
191
  if (props.sceneDataCode && dps.hasOwnProperty(props.sceneDataCode)) {
151
192
  if (dps[props.sceneDataCode]) {
@@ -187,33 +228,60 @@ const TimeScheduleDetailPage = () => {
187
228
  }, [])
188
229
 
189
230
  const getActionOnOff = useMemo(() => {
190
- const off = [] as string[]
191
- const on = [] as string[]
231
+ const off: string[] = []
232
+ const on: string[] = []
192
233
  if (props.switchLedCode) {
234
+ const s = actionOption['switchLed']
193
235
  if (state.switchLed) {
194
- on.push(I18n.getLang('light_sources_tile_tw_lighting_headline'))
236
+ on.push(s)
237
+ } else {
238
+ off.push(s)
239
+ }
240
+ }
241
+ if (props.switchSocket1) {
242
+ const s = isPowerStrip ? actionOption['switchSocket1'] : actionOption['switchSocket']
243
+ if (state.switchSocket1) {
244
+ on.push(s)
245
+ } else {
246
+ off.push(s)
247
+ }
248
+ }
249
+ if (props.switchSocket2) {
250
+ const s = actionOption['switchSocket2']
251
+ if (state.switchSocket2) {
252
+ on.push(s)
253
+ } else {
254
+ off.push(s)
255
+ }
256
+ }
257
+ if (props.switchSocket3) {
258
+ const s = actionOption['switchSocket3']
259
+ if (state.switchSocket3) {
260
+ on.push(s)
195
261
  } else {
196
- off.push(I18n.getLang('light_sources_tile_tw_lighting_headline'))
262
+ off.push(s)
197
263
  }
198
264
  }
199
- if (props.switchSocket) {
200
- if (state.switchSocket) {
201
- on.push(I18n.getLang('feature_summary_action_component_5'))
265
+ if (props.switchSocketUSB) {
266
+ const s = actionOption['switchSocket4']
267
+ if (state.switchSocketUSB) {
268
+ on.push(s)
202
269
  } else {
203
- off.push(I18n.getLang('feature_summary_action_component_5'))
270
+ off.push(s)
204
271
  }
205
272
  }
206
273
  if (props.switchFan) {
274
+ const s = actionOption['switchFan']
207
275
  if (state.switchFan) {
208
- on.push(I18n.getLang('add_new_dynamic_mood_ceiling_fan_field_headline'))
276
+ on.push(s)
209
277
  } else {
210
- off.push(I18n.getLang('add_new_dynamic_mood_ceiling_fan_field_headline'))
278
+ off.push(s)
211
279
  }
212
280
  }
213
281
  return {
214
282
  on, off
215
283
  }
216
- }, [state.switchLed, state.switchSocket, state.switchFan])
284
+ }, [state.switchLed, state.switchSocket1, state.switchSocket2, state.switchSocket3, state.switchSocketUSB, state.switchFan])
217
285
 
218
286
  const getActions = useCallback(() => {
219
287
  const actions = {
@@ -231,7 +299,7 @@ const TimeScheduleDetailPage = () => {
231
299
  isColor: state.isColorMode
232
300
  })
233
301
  const whiteMode = props.isStringLight ? !state.isColorMode : state.stripState.activeKey === 0
234
- actions.dps[props.workModeCode] = whiteMode ? WorkMode.White : WorkMode.Colour
302
+ if (props.workModeCode) actions.dps[props.workModeCode] = whiteMode ? WorkMode.White : WorkMode.Colour
235
303
 
236
304
  } else if (state.isColorMode) {
237
305
  if (props.colorDataCode) {
@@ -242,25 +310,57 @@ const TimeScheduleDetailPage = () => {
242
310
  }
243
311
  if (props.colorDataObj2Dp) {
244
312
  actions.dps[props.colorDataCode] = props.colorDataObj2Dp(hsv)
313
+ if (props.isMatterLight && props.brightValueCode && props.brightValueFormatter) {
314
+ actions.dps[props.brightValueCode] = props.brightValueFormatter(state.hsv.v)
315
+ }
245
316
  } else {
246
317
  const hex = getHexByHSV(hsv)
247
318
  actions.dps[props.colorDataCode] = hex
248
319
  }
249
320
  }
250
- actions.dps[props.workModeCode] = WorkMode.Colour
321
+ if (props.workModeCode) actions.dps[props.workModeCode] = WorkMode.Colour
251
322
  } else {
252
323
  if (props.brightValueCode) {
253
- actions.dps[props.brightValueCode] = state.brightness * 10
324
+ if (props.brightValueFormatter) {
325
+ actions.dps[props.brightValueCode] = props.brightValueFormatter(state.brightness)
326
+ } else {
327
+ actions.dps[props.brightValueCode] = state.brightness * 10
328
+ }
254
329
  }
255
330
  if (props.tempValueCode) {
256
- actions.dps[props.tempValueCode] = state.temperature * 10
331
+ if (props.tempValueFormatter) {
332
+ actions.dps[props.tempValueCode] = props.tempValueFormatter(state.temperature)
333
+ } else {
334
+ actions.dps[props.tempValueCode] = state.temperature * 10
335
+ }
257
336
  }
258
- actions.dps[props.workModeCode] = WorkMode.White
337
+ if (props.workModeCode) actions.dps[props.workModeCode] = WorkMode.White
259
338
  }
260
339
  }
261
340
  if (props.switchLedCode) {
262
341
  actions.dps[props.switchLedCode] = state.switchLed
263
342
  }
343
+ if (props.switchSocket1) {
344
+ actions.dps[props.switchSocket1] = state.switchSocket1
345
+ }
346
+ if (props.switchSocket2) {
347
+ actions.dps[props.switchSocket2] = state.switchSocket2
348
+ }
349
+ if (props.switchSocket3) {
350
+ actions.dps[props.switchSocket3] = state.switchSocket3
351
+ }
352
+ if (props.switchSocketUSB) {
353
+ actions.dps[props.switchSocketUSB] = state.switchSocketUSB
354
+ }
355
+ if (props.switchFan) {
356
+ actions.dps[props.switchFan] = state.switchFan
357
+ if (props.fanModeCode && state.switchFan) {
358
+ actions.dps[props.fanModeCode] = state.fanMode
359
+ }
360
+ if (props.fanSpeedCode && state.switchFan) {
361
+ actions.dps[props.fanSpeedCode] = state.fanSpeed
362
+ }
363
+ }
264
364
  } else {
265
365
  if (props.sceneDataCode) {
266
366
  actions.dps[props.sceneDataCode] = state.scene
@@ -273,7 +373,7 @@ const TimeScheduleDetailPage = () => {
273
373
  console.log(state, '< --- state')
274
374
  console.log(actions, '< --- actions')
275
375
  return JSON.stringify(actions)
276
- }, [state.timeSchedule.time, state.switchLed, state.brightness, state.temperature])
376
+ }, [JSON.stringify(state)])
277
377
 
278
378
  const isModify = useMemo(() => {
279
379
  const schedule = props.mode === 'add' ? newTimeSchedule() : props.timeSchedule
@@ -319,8 +419,6 @@ const TimeScheduleDetailPage = () => {
319
419
  headlineText={I18n.getLang(props.mode === 'add' ? 'motion_detection_add_time_schedule_headline_text' : 'edit_timeschedule_headline_text')}
320
420
  rightButtonIcon={allowSubmit ? res.ic_check : res.ic_uncheck}
321
421
  rightButtonIconClick={async () => {
322
- getActions()
323
- return
324
422
  if (!allowSubmit || state.loading) return
325
423
  state.loading = true
326
424
  const res = await props.modDeleteTimeSchedule(props.mode, {
@@ -357,8 +455,10 @@ const TimeScheduleDetailPage = () => {
357
455
  <TimerPicker
358
456
  itemTextColor='#aeadb5'
359
457
  style={{ paddingVertical: cx(0), marginVertical: cx(0) }}
360
- is12Hours={false}
458
+ is12Hours={!is24HourClock}
361
459
  singlePicker={true}
460
+ amText={I18n.getLang('manage_user_calendar_label_am')}
461
+ pmText={I18n.getLang('manage_user_calendar_label_pm')}
362
462
  startTime={getFormateTime(state.timeSchedule.time) as number}
363
463
  symbol={''}
364
464
  onTimerChange={(startTime) => {
@@ -389,99 +489,185 @@ const TimeScheduleDetailPage = () => {
389
489
  <Spacer height={cx(10)} />
390
490
  {state.isManual ?
391
491
  <>
392
- {!!props.switchLedCode && <Card
393
- style={styles.cardContainer}
394
- >
395
- <LdvSwitch
396
- title={I18n.getLang('light_sources_tile_tw_lighting_headline')}
397
- color={'#fff'}
398
- colorAlpha={1}
399
- enable={state.switchLed}
400
- setEnable={(enable: boolean) => {
401
- state.switchLed = enable
402
- }}
403
- />
404
- {state.switchLed && (props.isStripLight ?
405
- <StripAdjustView
406
- lampTabs={tabList}
407
- onColorDiskChange={(color, idx: K) => {
408
- state.stripState = {
409
- ...state.stripState,
410
- colors: color,
411
- colorDiskActiveKey: idx
412
- }
413
- }}
414
- colorDiskActiveKey={state.stripState.colorDiskActiveKey}
415
- activeKey={state.stripState.activeKey}
416
- onActiveKeyChange={(v) => {
417
- state.stripState = {
418
- ...state.stripState,
419
- activeKey: Number(v) as K
420
- }
492
+ {!!props.switchLedCode && <>
493
+ <Card
494
+ style={styles.cardContainer}
495
+ >
496
+ <LdvSwitch
497
+ title={I18n.getLang('light_sources_tile_tw_lighting_headline')}
498
+ color={'#fff'}
499
+ colorAlpha={1}
500
+ enable={state.switchLed}
501
+ setEnable={(enable: boolean) => {
502
+ state.switchLed = enable
421
503
  }}
422
- isSupportTemperature={props.isSupportTemperature}
423
- isSupportBrightness={props.isSupportBrightness}
424
- h={state.hsv.h} s={state.hsv.s} v={state.hsv.v}
425
- onHSVChange={(h, s, v) => { state.hsv = { h, s, v } }}
426
- onHSVChangeComplete={(h, s, v) => { state.hsv = { h, s, v } }}
427
- colorTemp={state.temperature}
428
- brightness={state.brightness}
429
- onCCTChange={() => { }}
430
- onCCTChangeComplete={(cct) => { state.temperature = cct }}
431
- onBrightnessChange={() => { }}
432
- onBrightnessChangeComplete={(bright) => { state.brightness = bright }}
433
- /> :
434
- <LampAdjustView
435
- reserveSV={true}
436
- isSupportBrightness={props.isSupportBrightness}
437
- isSupportColor={props.isSupportColor}
438
- isSupportTemperature={props.isSupportTemperature}
439
- isColorMode={state.isColorMode}
440
- setIsColorMode={(v) => { state.isColorMode = v }}
441
- h={state.hsv.h} s={state.hsv.s} v={state.hsv.v}
442
- colorTemp={state.temperature}
443
- brightness={state.brightness}
444
- onHSVChangeComplete={(h, s, v) => { state.hsv = { h, s, v } }}
445
- onHSVChange={(h, s, v) => { state.hsv = { h, s, v } }}
446
- onCCTChangeComplete={(cct) => { state.temperature = cct }}
447
- onCCTChange={(cct) => { state.temperature = cct }}
448
- onBrightnessChangeComplete={(bright) => { state.brightness = bright }}
449
- onBrightnessChange={(bright) => { state.brightness = bright }}
450
- />)}
451
- <ApplyForDeviceList
452
- devices={cloneDeep(groupDevices)}
453
- />
454
- <Spacer height={cx(16)} />
455
- </Card>}
504
+ />
505
+ {state.switchLed && (props.isStripLight ?
506
+ <StripAdjustView
507
+ lampTabs={tabList}
508
+ onColorDiskChange={(color, idx: K) => {
509
+ state.stripState = {
510
+ ...state.stripState,
511
+ colors: color,
512
+ colorDiskActiveKey: idx
513
+ }
514
+ }}
515
+ colorDiskActiveKey={state.stripState.colorDiskActiveKey}
516
+ activeKey={state.stripState.activeKey}
517
+ onActiveKeyChange={(v) => {
518
+ state.stripState = {
519
+ ...state.stripState,
520
+ activeKey: Number(v) as K
521
+ }
522
+ }}
523
+ isSupportTemperature={props.isSupportTemperature}
524
+ isSupportBrightness={props.isSupportBrightness}
525
+ h={state.hsv.h} s={state.hsv.s} v={state.hsv.v}
526
+ onHSVChange={(h, s, v) => { state.hsv = { h, s, v } }}
527
+ onHSVChangeComplete={(h, s, v) => { state.hsv = { h, s, v } }}
528
+ colorTemp={state.temperature}
529
+ brightness={state.brightness}
530
+ onCCTChange={() => { }}
531
+ onCCTChangeComplete={(cct) => { state.temperature = cct }}
532
+ onBrightnessChange={() => { }}
533
+ onBrightnessChangeComplete={(bright) => { state.brightness = bright }}
534
+ /> :
535
+ <LampAdjustView
536
+ reserveSV={true}
537
+ isSupportBrightness={props.isSupportBrightness}
538
+ isSupportColor={props.isSupportColor}
539
+ isSupportTemperature={props.isSupportTemperature}
540
+ isColorMode={state.isColorMode}
541
+ setIsColorMode={(v) => { state.isColorMode = v }}
542
+ h={state.hsv.h} s={state.hsv.s} v={state.hsv.v}
543
+ colorTemp={state.temperature}
544
+ brightness={state.brightness}
545
+ onHSVChangeComplete={(h, s, v) => { state.hsv = { h, s, v } }}
546
+ onHSVChange={(h, s, v) => { state.hsv = { h, s, v } }}
547
+ onCCTChangeComplete={(cct) => { state.temperature = cct }}
548
+ onCCTChange={(cct) => { state.temperature = cct }}
549
+ onBrightnessChangeComplete={(bright) => { state.brightness = bright }}
550
+ onBrightnessChange={(bright) => { state.brightness = bright }}
551
+ />)}
552
+ <ApplyForDeviceList
553
+ devices={cloneDeep(groupDevices)}
554
+ />
555
+ <Spacer height={cx(16)} />
556
+ </Card>
557
+ <Spacer />
558
+ </>}
456
559
 
457
560
  {/* socket */}
458
- {!!props.switchSocket && <Card
459
- style={styles.cardContainer}
460
- >
461
- <LdvSwitch
462
- title={I18n.getLang('feature_summary_action_component_5')}
463
- color={'#fff'}
464
- colorAlpha={1}
465
- enable={state.switchSocket}
466
- setEnable={(enable: boolean) => {
467
- state.switchSocket = enable
561
+ {!!props.switchSocket1 && <>
562
+ {isPowerStrip ?
563
+ <SocketItem
564
+ title={I18n.getLang('feature_summary_action_component_6')}
565
+ name=""
566
+ icon={{ uri: res.switch_1 }}
567
+ onNameChange={() => { }}
568
+ enabled={state.switchSocket1}
569
+ disabledEdit={true}
570
+ onSwitchChange={enable => {
571
+ state.switchSocket1 = enable
572
+ }}
573
+ >
574
+ <ApplyForDeviceList
575
+ devices={cloneDeep(groupDevices)}
576
+ />
577
+ <Spacer height={cx(16)} />
578
+ </SocketItem> :
579
+ <Card
580
+ style={styles.cardContainer}
581
+ >
582
+ <LdvSwitch
583
+ title={I18n.getLang('feature_summary_action_component_5')}
584
+ color={'#fff'}
585
+ colorAlpha={1}
586
+ enable={state.switchSocket1}
587
+ setEnable={(enable: boolean) => {
588
+ state.switchSocket1 = enable
589
+ }}
590
+ />
591
+ <ApplyForDeviceList
592
+ devices={cloneDeep(groupDevices)}
593
+ />
594
+ <Spacer height={cx(16)} />
595
+ </Card>
596
+ }
597
+ <Spacer />
598
+ </>}
599
+ {!!props.switchSocket2 && <>
600
+ <SocketItem
601
+ title={I18n.getLang('feature_summary_action_component_7')}
602
+ name=""
603
+ icon={{ uri: res.switch_2 }}
604
+ onNameChange={() => { }}
605
+ enabled={state.switchSocket2}
606
+ disabledEdit={true}
607
+ onSwitchChange={enable => {
608
+ state.switchSocket2 = enable
468
609
  }}
469
- />
470
- <ApplyForDeviceList
471
- devices={cloneDeep(groupDevices)}
472
- />
473
- <Spacer height={cx(16)} />
474
- </Card>}
610
+ >
611
+ <ApplyForDeviceList
612
+ devices={cloneDeep(groupDevices)}
613
+ />
614
+ <Spacer height={cx(16)} />
615
+ </SocketItem>
616
+ <Spacer />
617
+ </>}
618
+ {!!props.switchSocket3 && <>
619
+ <SocketItem
620
+ title={I18n.getLang('feature_summary_action_component_8')}
621
+ name=""
622
+ icon={{ uri: res.switch_3 }}
623
+ onNameChange={() => { }}
624
+ enabled={state.switchSocket3}
625
+ disabledEdit={true}
626
+ onSwitchChange={enable => {
627
+ state.switchSocket3 = enable
628
+ }}
629
+ >
630
+ <ApplyForDeviceList
631
+ devices={cloneDeep(groupDevices)}
632
+ />
633
+ <Spacer height={cx(16)} />
634
+ </SocketItem>
635
+ <Spacer />
636
+ </>}
637
+ {!!props.switchSocketUSB && <>
638
+ <SocketItem
639
+ title={I18n.getLang('feature_summary_action_component_9')}
640
+ name=""
641
+ icon={{ uri: res.switch_4 }}
642
+ onNameChange={() => { }}
643
+ enabled={state.switchSocketUSB}
644
+ disabledEdit={true}
645
+ onSwitchChange={enable => {
646
+ state.switchSocketUSB = enable
647
+ }}
648
+ >
649
+ <ApplyForDeviceList
650
+ devices={cloneDeep(groupDevices)}
651
+ />
652
+ <Spacer height={cx(16)} />
653
+ </SocketItem>
654
+ <Spacer />
655
+ </>}
475
656
 
476
657
  {/* Fan */}
477
658
  {props.isSupportFan && <FanAdjustView
659
+ style={styles.cardContainer}
478
660
  fanEnable={state.switchFan}
479
- fanSpeed={1}
480
- onFanSpeedChangeComplete={() => { }}
661
+ fanSpeed={state.fanSpeed}
662
+ modeValue={state.fanMode}
663
+ modeOptions={fanModeOption}
664
+ modeChange={(v: any) => state.fanMode = v}
665
+ maxFanSpeed={props.isSupportUVC ? 20 : 3}
666
+ onFanSpeedChangeComplete={(v) => state.fanSpeed = v}
481
667
  onFanSwitch={(enable) => {
482
668
  state.switchFan = enable
483
669
  }}
484
- isSupportMode={true}
670
+ isSupportMode={props.isSupportUVC}
485
671
  />}
486
672
  </> :
487
673
  <FlatList
@@ -507,7 +693,7 @@ const TimeScheduleDetailPage = () => {
507
693
  </View>)}
508
694
  keyExtractor={item => `${item.id}`} />
509
695
  }
510
- <Spacer height={cx(30)} />
696
+ <Spacer height={cx(20)} />
511
697
  <Text style={[styles.itemTitle, styles.cardContainer]}>{I18n.getLang('timeschedule_add_schedule_subheadline4_text')}</Text>
512
698
  <View style={[styles.switchButton, styles.cardContainer]}>
513
699
  <Text style={styles.text}>{I18n.getLang('timeschedule_add_schedule_text2')}</Text>
@@ -543,7 +729,7 @@ const TimeScheduleDetailPage = () => {
543
729
  style={styles.summaryLeft}
544
730
  />
545
731
  <View style={styles.summaryRight}>
546
- <Text style={styles.rightItem}>{state.timeSchedule.time}</Text>
732
+ <Text style={styles.rightItem}>{is24HourClock ? state.timeSchedule.time : convertTo12HourFormat(state.timeSchedule.time)}</Text>
547
733
  </View>
548
734
  </View>
549
735
  <View style={[styles.summaryContainer, { alignItems: 'flex-start' }]}>
@@ -554,10 +740,10 @@ const TimeScheduleDetailPage = () => {
554
740
  textStyle={styles.leftTitle}
555
741
  style={styles.summaryLeft}
556
742
  />
557
- <View style={{ marginLeft: cx(16) }}>
743
+ <View style={{ marginLeft: cx(16), flex: 1 }}>
558
744
  {!!getActionOnOff.on.length && <View>
559
745
  <Text style={{ marginLeft: cx(5) }}>{I18n.getLang('feature_summary_action_txt_1')}</Text>
560
- <View style={{ flexDirection: 'row' }}>{
746
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>{
561
747
  getActionOnOff.on.map(item => (
562
748
  <View style={[styles.summaryRight, { marginLeft: cx(5), marginBottom: cx(5) }]}
563
749
  key={item}>
@@ -569,7 +755,7 @@ const TimeScheduleDetailPage = () => {
569
755
  </View>}
570
756
  {!!getActionOnOff.off.length && <View>
571
757
  <Text style={{ marginLeft: cx(5) }}>{I18n.getLang('feature_summary_action_txt_2')}</Text>
572
- <View style={{ flexDirection: 'row' }}>{
758
+ <View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>{
573
759
  getActionOnOff.off.map(item => (
574
760
  <View style={[styles.summaryRight, { marginLeft: cx(5), marginBottom: cx(5) }]}
575
761
  key={item}>
@@ -42,14 +42,24 @@ export interface TimeSchedulePageParams {
42
42
  isSupportMood?: boolean
43
43
  isStringLight?: boolean
44
44
  isStripLight?: boolean
45
+ isMatterLight?: boolean
45
46
  isSupportFan?: boolean
46
47
  isSupportUVC?: boolean
47
48
  switchLedCode?: string
48
- switchSocket?: string
49
+ switchSocket1?: string
50
+ switchSocket2?: string
51
+ switchSocket3?: string
52
+ switchSocketUSB?: string
49
53
  switchFan?: string
54
+ fanModeCode?: string
55
+ fanSpeedCode?: string
50
56
  workModeCode: string
51
57
  brightValueCode?: string
58
+ brightValueFormatter?: (bright: number) => number
59
+ brightValueParser?: (bright: number) => number
52
60
  tempValueCode?: string
61
+ tempValueFormatter?: (temp: number) => number
62
+ tempValueParser?: (temp: number) => number
53
63
  sceneDataCode?: string
54
64
  sceneDataDp2Obj?: (sceneDp: string) => SceneInfo
55
65
  sceneDataObj2Dp?: (scene: any) => string
@@ -2,8 +2,7 @@ import { useFeatureHook } from '@ledvance/base/src/models/modules/NativePropsSli
2
2
  import { Result } from '@ledvance/base/src/models/modules/Result'
3
3
  import dayjs from 'dayjs'
4
4
  import { useCountDown, useReactive } from 'ahooks'
5
- import { useEffect } from 'react'
6
- import { cloneDeep } from 'lodash'
5
+ import { useEffect, useMemo } from 'react'
7
6
 
8
7
  export interface TimerTask {
9
8
  name: string
@@ -29,7 +28,8 @@ export interface TimerConfig {
29
28
  timerTasks: TimerTask[]
30
29
  }
31
30
 
32
- export function useTimerTasks(timerSettableDps: TimerSettableDp[]): [TimerTask[], (value: TimerTask[]) => Promise<Result<any>>] {
31
+ export function useTimerTasks(timerSettableDps: TimerSettableDp[]):
32
+ [TimerTask[], (value: TimerTask[]) => Promise<Result<any>>, (tasks: TimerTask[]) => void] {
33
33
  const countdowns = timerSettableDps.map(dps => {
34
34
  const [countdown, setTargetDate] = useCountDown({ interval: 1000 })
35
35
  return {
@@ -40,18 +40,21 @@ export function useTimerTasks(timerSettableDps: TimerSettableDp[]): [TimerTask[]
40
40
  },
41
41
  }
42
42
  })
43
- const [tasks, setTasks] = useFeatureHook<TimerConfig, TimerTask[]>(
43
+
44
+ const defTasks = useMemo(() => timerSettableDps.map(timerSettableDp => ({
45
+ name: timerSettableDp.label,
46
+ startTime: 0,
47
+ duration: 0,
48
+ timeLeft: 0,
49
+ dp: timerSettableDp.dp,
50
+ status: TaskStatus.NoSelected,
51
+ stringOn: timerSettableDp.stringOn,
52
+ stringOff: timerSettableDp.stringOff,
53
+ })), [JSON.stringify(timerSettableDps)])
54
+
55
+ const [remoteTasks, setTasks] = useFeatureHook<TimerConfig, TimerTask[]>(
44
56
  '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
- })),
57
+ defTasks,
55
58
  () => undefined,
56
59
  timerTasks => {
57
60
  const dps = {}
@@ -62,10 +65,15 @@ export function useTimerTasks(timerSettableDps: TimerSettableDp[]): [TimerTask[]
62
65
  },
63
66
  )
64
67
 
65
- const state = useReactive({ tasks: cloneDeep(tasks) })
68
+ const tasks = defTasks.map(defTask => {
69
+ const findTask = remoteTasks.find(remoteTask => remoteTask.dp.code === defTask.dp.code)
70
+ return findTask ? { ...findTask } : defTask
71
+ })
72
+
73
+ const state = useReactive({ tasks: tasks })
66
74
 
67
75
  useEffect(() => {
68
- state.tasks = cloneDeep(tasks)
76
+ state.tasks = tasks
69
77
  .map(task => {
70
78
  const taskEndTime = dayjs.unix(task.startTime)
71
79
  .add(task.duration, 'second')
@@ -99,17 +107,29 @@ export function useTimerTasks(timerSettableDps: TimerSettableDp[]): [TimerTask[]
99
107
  state.tasks.forEach(task => {
100
108
  if (task.dp.code === cd.dpCode) {
101
109
  task.timeLeft = Math.trunc(cd.countdown.value / 1000)
102
- if (task.timeLeft <= 0) {
103
- task.status = TaskStatus.NoSelected
104
- } else {
110
+ if (task.timeLeft > 0) {
105
111
  task.status = TaskStatus.Started
112
+ } else {
113
+ if (task.status === TaskStatus.Started) {
114
+ task.status = TaskStatus.NoSelected
115
+ }
106
116
  }
107
117
  }
108
118
  })
109
119
  })
110
120
  }, [JSON.stringify(countdowns.map(c => c.countdown.value))])
111
121
 
112
- return [state.tasks, setTasks]
122
+ const changeTasks = (timerTasks: TimerTask[]) => {
123
+ timerTasks.forEach(newTask => {
124
+ state.tasks.forEach(task => {
125
+ if (task.dp.code === newTask.dp.code) {
126
+ task.status = newTask.status
127
+ }
128
+ })
129
+ })
130
+ }
131
+
132
+ return [state.tasks, setTasks, changeTasks]
113
133
  }
114
134
 
115
135
  export function getTaskLeftover(timerTask: TimerTask): number {
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo } from 'react'
1
+ import React, { useEffect } from 'react'
2
2
  import { FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
3
3
  import I18n from '@ledvance/base/src/i18n'
4
4
  import Page from '@ledvance/base/src/components/Page'
@@ -23,7 +23,7 @@ const TimerPage = () => {
23
23
  const devInfo = useDeviceInfo()
24
24
 
25
25
  const params = useParams<TimerPageParams>()
26
- const [timerTasks, setTimerTasks] = useTimerTasks(params.timerSettableDps)
26
+ const [timerTasks, setTimerTasks, changeTimerTasks] = useTimerTasks(params.timerSettableDps)
27
27
 
28
28
  const state = useReactive({
29
29
  hour: '00',
@@ -35,15 +35,13 @@ const TimerPage = () => {
35
35
  useEffect(() => {
36
36
  state.tasks = cloneDeep(timerTasks)
37
37
  .map(task => {
38
- const newStatus = timerTasks.length === 1 && task.status !== TaskStatus.Started
38
+ const newStatus = params.timerSettableDps.length === 1 && task.status !== TaskStatus.Started
39
39
  ? TaskStatus.Selected : task.status
40
40
  return { ...task, status: newStatus }
41
41
  })
42
42
  }, [JSON.stringify(timerTasks)])
43
43
 
44
- const tasksByStatus = useMemo(() => {
45
- return groupBy(state.tasks, 'status')
46
- }, [JSON.stringify(state.tasks)])
44
+ const tasksByStatus = groupBy(state.tasks, 'status')
47
45
 
48
46
  const noSelectedTasks = tasksByStatus[TaskStatus.NoSelected] || []
49
47
  const selectedTasks = tasksByStatus[TaskStatus.Selected] || []
@@ -87,6 +85,7 @@ const TimerPage = () => {
87
85
  <TouchableOpacity
88
86
  onPress={() => {
89
87
  item.status = TaskStatus.NoSelected
88
+ changeTimerTasks([cloneDeep(item)])
90
89
  }}>
91
90
  <Image style={styles.taskItemIcon} source={GroupBizRes.ic_arrows_nav_clear}/>
92
91
  </TouchableOpacity>}
@@ -109,6 +108,7 @@ const TimerPage = () => {
109
108
  style={styles.noSelectTaskItem}
110
109
  onPress={() => {
111
110
  item.status = TaskStatus.Selected
111
+ changeTimerTasks([cloneDeep(item)])
112
112
  }}>
113
113
  <Spacer width={cx(8)}/>
114
114
  <Text style={styles.noSelectTaskText}>{item.name}</Text>
@@ -120,6 +120,7 @@ const TimerPage = () => {
120
120
  <Spacer/>
121
121
  <DeleteButton
122
122
  text={I18n.getLang('timer_sockets_button_text')}
123
+ disabled={selectedTasks.length === 0}
123
124
  onPress={async () => {
124
125
  state.loading = true
125
126
  const tasks = selectedTasks.map(task => {
@@ -130,6 +131,7 @@ const TimerPage = () => {
130
131
  status: TaskStatus.Started,
131
132
  }
132
133
  })
134
+ tasks.push(...cloneDeep(startedTasks))
133
135
  await setTimerTasks(cloneDeep(tasks))
134
136
  state.loading = false
135
137
  }}
@@ -137,7 +139,7 @@ const TimerPage = () => {
137
139
  style={{ backgroundColor: !startEnable ? '#FFE0D4' : '#f60' }}/>
138
140
  </View>
139
141
  }
140
- {startedTasks.length > 0 && state.tasks.length > 1 &&
142
+ {startedTasks.length > 0 && params.timerSettableDps.length > 1 &&
141
143
  <>
142
144
  <Spacer height={cx(30)}/>
143
145
  <View style={styles.content}>
@@ -148,8 +150,18 @@ const TimerPage = () => {
148
150
  <FlatList
149
151
  data={startedTasks}
150
152
  renderItem={({ item }) => {
151
- return ActiveTimerItem(item, () => {
152
- item.status = TaskStatus.NoSelected
153
+ return ActiveTimerItem(item, async () => {
154
+ state.loading = true
155
+ const tasks = cloneDeep(startedTasks)
156
+ tasks.forEach(task => {
157
+ if (task.dp.code === item.dp.code) {
158
+ task.status = TaskStatus.NoSelected
159
+ task.startTime = 0
160
+ task.duration = 0
161
+ }
162
+ })
163
+ await setTimerTasks(tasks)
164
+ state.loading = false
153
165
  })
154
166
  }}
155
167
  keyExtractor={item => item.dp.key}
@@ -159,7 +171,7 @@ const TimerPage = () => {
159
171
  </>
160
172
  }
161
173
  {
162
- startedTasks.length === 1 && state.tasks.length === 1 &&
174
+ startedTasks.length === 1 && params.timerSettableDps.length === 1 &&
163
175
  <View style={{ justifyContent: 'center', marginHorizontal: cx(24) }}>
164
176
  <Spacer height={cx(116)}/>
165
177
  <View
@@ -219,17 +231,17 @@ function ActiveTimerItem(task: TimerTask, onCancel: () => void) {
219
231
  <View style={styles.activeTaskHeadLine}>
220
232
  <Spacer width={cx(20)}/>
221
233
  <CircularProgress
222
- progress={25}
234
+ progress={(task.timeLeft / task.duration) * 100}
223
235
  size={cx(24)}
224
236
  strokeWidth={cx(2)}/>
225
237
  <Spacer width={cx(16)}/>
226
- <Text style={styles.activeTaskTimeText}>{'2h 12 min'}</Text>
238
+ <Text style={styles.activeTaskTimeText}>{I18n.formatValue(task.stringOn, timeFormat(task.timeLeft))}</Text>
227
239
  <Spacer width={cx(20)}/>
228
240
  </View>
229
241
  <Spacer/>
230
242
  <View style={{ marginHorizontal: cx(20) }}>
231
243
  <Text style={styles.activeTaskDesc}>{
232
- I18n.getLang(task.stringOn)
244
+ I18n.formatValue(task.stringOn, timeFormat(task.timeLeft))
233
245
  }</Text>
234
246
  </View>
235
247
  <Spacer height={cx(22)}/>