@ledvance/group-ui-biz-bundle 1.0.95 → 1.0.97

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 (25) hide show
  1. package/package.json +1 -1
  2. package/src/modules/biorhythm/BiorhythmDetailPage.tsx +1 -0
  3. package/src/modules/biorhythm/BiorhythmPage.tsx +8 -2
  4. package/src/modules/energyConsumption/EnergyConsumptionActions.ts +144 -137
  5. package/src/modules/energyConsumption/EnergyConsumptionChart.tsx +74 -71
  6. package/src/modules/energyConsumption/EnergyConsumptionDetail.tsx +13 -11
  7. package/src/modules/energyConsumption/EnergyConsumptionPage.tsx +7 -6
  8. package/src/modules/energyConsumption/component/EnergyModal.tsx +1 -1
  9. package/src/modules/fixedTimeForPlug/FixedTimeForPlugDetailPage.tsx +6 -4
  10. package/src/modules/fixedTimeForPlug/FixedTimeForPlugPage.tsx +33 -5
  11. package/src/modules/fixedTimingForLight/FixedTimingForLightDetailPage.tsx +6 -4
  12. package/src/modules/fixedTimingForLight/FixedTimingForLightPage.tsx +34 -6
  13. package/src/modules/music/MusicActions.ts +3 -0
  14. package/src/modules/music/MusicPage.tsx +2 -0
  15. package/src/modules/randomTimeForPlug/RandomTimeForPlugDetailPage.tsx +6 -4
  16. package/src/modules/randomTimeForPlug/RandomTimeForPlugPage.tsx +34 -6
  17. package/src/modules/randomTimingForLight/ItemCard.tsx +3 -2
  18. package/src/modules/randomTimingForLight/RandomTimingForLightDetailPage.tsx +6 -4
  19. package/src/modules/randomTimingForLight/RandomTimingForLightPage.tsx +34 -6
  20. package/src/modules/sleepWakeUp/SleepWakeUpActions.ts +1 -1
  21. package/src/modules/sleepWakeUp/SleepWakeUpDetailPage.tsx +9 -8
  22. package/src/modules/sleepWakeUp/SleepWakeUpPage.tsx +120 -38
  23. package/src/modules/timeSchedule/TimeScheduleDetailPage.tsx +3 -2
  24. package/src/modules/timeSchedule/TimeSchedulePage.tsx +15 -1
  25. package/src/modules/timeSchedule/components/ManuaSettings.tsx +18 -8
@@ -16,7 +16,6 @@ import { useTimeZoneCity } from '@ledvance/base/src/models/modules/NativePropsSl
16
16
  import { flattenDeep, isNumber, sumBy } from 'lodash';
17
17
  import {
18
18
  exchangeNumber,
19
- exportFile,
20
19
  localeNumber,
21
20
  monthFormat,
22
21
  monthFormatShort,
@@ -28,6 +27,7 @@ import { EnergyConsumptionDetailProps } from './EnergyConsumptionDetail';
28
27
  import { EnergyConsumptionChartProps } from './EnergyConsumptionChart';
29
28
  import SegmentControl from '@ledvance/base/src/components/segmentControl';
30
29
  import ThemeType from '@ledvance/base/src/config/themeType'
30
+ import { exportEnergyCsv } from "./EnergyConsumptionActions";
31
31
 
32
32
  const { convertX: cx } = Utils.RatioUtils;
33
33
  const { withTheme } = Utils.ThemeUtils;
@@ -285,7 +285,8 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
285
285
  )}
286
286
  headlineIcon={(state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList).length ? res.download_icon : undefined}
287
287
  onHeadlineIconClick={() => {
288
- exportFile(state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList, state.price, state.unit);
288
+ const values = (state.isSolarMode ? state.solarOverviewList : state.wifiOverviewList).map(item => [item.key, item.value, (Number(state.price) * Number(item.value)).toFixed(2)])
289
+ exportEnergyCsv(values, state.unit)
289
290
  }}
290
291
  showGreenery={state.isSolarMode}
291
292
  greeneryIcon={res.energy_consumption_greenery}
@@ -309,7 +310,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
309
310
  {/* tip */}
310
311
  <Spacer height={cx(15)} />
311
312
  <View style={styles.showTip}>
312
- <Text style={{ fontSize: cx(14) }}>
313
+ <Text style={{ fontSize: cx(14), color: props.theme?.global.fontColor, }}>
313
314
  {I18n.getLang(
314
315
  state.isSolarMode
315
316
  ? 'generation_data_description_text'
@@ -378,7 +379,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
378
379
  style={{
379
380
  height: cx(20),
380
381
  width: cx(20),
381
- tintColor: props.theme?.button.active,
382
+ tintColor: props.theme?.button.primary,
382
383
  }}
383
384
  />
384
385
  </View>
@@ -401,7 +402,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
401
402
  style={{
402
403
  height: cx(20),
403
404
  width: cx(20),
404
- tintColor: props.theme?.button.active,
405
+ tintColor: props.theme?.button.primary,
405
406
  }}
406
407
  />
407
408
  </TouchableOpacity>
@@ -420,7 +421,7 @@ const EnergyConsumptionPage = (props: { theme?: ThemeType }) => {
420
421
  <Image
421
422
  source={res.energy_consumption_cash}
422
423
  resizeMode="contain"
423
- style={{ height: cx(20), width: cx(20), tintColor: props.theme?.button.active }}
424
+ style={{ height: cx(20), width: cx(20), tintColor: props.theme?.button.primary }}
424
425
  />
425
426
  </View>
426
427
  <View>
@@ -59,7 +59,7 @@ const EnergyModal = (props: EnergyModalProps) => {
59
59
  <Text style={{ color: props.theme?.global.fontColor }}>{text[length - 4] + text[length - 3] + ':'}</Text>
60
60
  <Spacer />
61
61
  <Text
62
- style={{ textDecorationLine: 'underline', color: props.theme?.button.active }}
62
+ style={{ textDecorationLine: 'underline', color: props.theme?.button.primary }}
63
63
  onPress={() => openLink(`${text[length - 2]}:${text[length - 1]}${text[length]}`)}
64
64
  >
65
65
  {`${text[length - 2]}:${text[length - 1]}${text[length]}`}
@@ -33,6 +33,7 @@ interface FixedTimeDetailParam extends FixedTimeParam {
33
33
  const newFixedTimeItem = (): FixedTimeItem => {
34
34
  const startTime = dayjs().hour() * 60 + dayjs().minute()
35
35
  return {
36
+ name: I18n.getLang('fixedTimeCycle_socket_headline'),
36
37
  enable: true,
37
38
  channel: 0,
38
39
  weeks: [0, 0, 0, 0, 0, 0, 0, 0],
@@ -89,14 +90,14 @@ const FixedTimeForPlugDetailPage = (props: { theme?: ThemeType }) => {
89
90
  return timeInterval >= workTime
90
91
  }, [state.item.startTime, state.item.endTime, state.onHour, state.onMinute, state.offHour, state.offMinute])
91
92
 
92
- const canSave = useMemo(() => {
93
- return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && isTimeEffective
94
- }, [state.item.name, state.item.channel, isTimeEffective])
95
-
96
93
  const showConfirm = useMemo(() => {
97
94
  return !isEqual(state.item, params.mode === 'edit' ? params.item : initItem)
98
95
  }, [JSON.stringify(state.item), JSON.stringify(params.item)])
99
96
 
97
+ const canSave = useMemo(() => {
98
+ return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && isTimeEffective && (showConfirm || params.mode === 'add')
99
+ }, [state.item.name, state.item.channel, isTimeEffective, showConfirm])
100
+
100
101
  const onSave = async () => {
101
102
  if (!canSave) {
102
103
  return
@@ -203,6 +204,7 @@ const FixedTimeForPlugDetailPage = (props: { theme?: ThemeType }) => {
203
204
  />
204
205
  {/* pick */}
205
206
  <TimerPicker
207
+ key={props.theme?.type}
206
208
  itemTextColor='#aeadb5'
207
209
  style={{ paddingVertical: cx(0), marginVertical: cx(0), backgroundColor: props.theme?.global.background }}
208
210
  pickerFontColor={props.theme?.global.fontColor}
@@ -10,7 +10,7 @@ import {useReactive} from "ahooks";
10
10
  import {ui_biz_routerKey} from "../../navigation/Routers";
11
11
  import {cloneDeep} from "lodash";
12
12
  import Spacer from "@ledvance/base/src/components/Spacer";
13
- import {Utils} from "tuya-panel-kit";
13
+ import {Utils, Dialog} from "tuya-panel-kit";
14
14
  import ItemCard from "./ItemCard";
15
15
  import InfoText from "@ledvance/base/src/components/InfoText";
16
16
  import ThemeType from '@ledvance/base/src/config/themeType'
@@ -43,18 +43,46 @@ const FixedTimeForPlugPage = (props: { theme?: ThemeType}) => {
43
43
  })
44
44
  }
45
45
 
46
- const onPost = useCallback(async (mode: 'add' | 'edit' | 'del', fixedTime: FixedTimeItem, goBack?: boolean) => {
46
+ const onPost = useCallback(async (mode: 'add' | 'edit' | 'del' | 'set', fixedTime: FixedTimeItem, goBack?: boolean) => {
47
47
  state.loading = true
48
48
  const cloneFixedTimeList = cloneDeep(fixedTimeList)
49
49
  const idx = fixedTimeList.findIndex(it => it.index === fixedTime.index)
50
- if (mode === 'edit') {
50
+ if (mode === 'edit' || mode === 'set') {
51
51
  cloneFixedTimeList.splice(idx, 1, fixedTime)
52
52
  }
53
53
  if (mode === 'del') cloneFixedTimeList.splice(idx, 1)
54
- const newFixedTimeList = mode === 'add' ? [...fixedTimeList, {
54
+ let newFixedTimeList = mode === 'add' ? [...fixedTimeList, {
55
55
  ...fixedTime,
56
56
  index: fixedTimeList.length
57
57
  }] : cloneFixedTimeList
58
+ if (((mode === 'edit' || mode === 'set') && fixedTime.enable) || mode === 'add') {
59
+ const cloneList = cloneDeep(newFixedTimeList)
60
+ let itselfConflict = false
61
+ cloneList.forEach((item, idx) => {
62
+ const itself = mode === 'add' ? (idx === cloneList.length - 1) : fixedTime.index === item.index
63
+ if (!itself && item.enable && isConflictTask(item, fixedTime)) {
64
+ itselfConflict = true
65
+ item.enable = false
66
+ }
67
+ })
68
+ if (itselfConflict && mode === 'set') {
69
+ return showDialog({
70
+ method: 'confirm',
71
+ title: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_titel'),
72
+ subTitle: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_description'),
73
+ onConfirm: async (_, { close }) => {
74
+ close()
75
+ setFixedTimeList(cloneList)
76
+ state.loading = false
77
+ },
78
+ onCancel: () => {
79
+ state.loading = false
80
+ Dialog.close()
81
+ }
82
+ })
83
+ }
84
+ newFixedTimeList = cloneList
85
+ }
58
86
  const res = await setFixedTimeList(newFixedTimeList)
59
87
  state.loading = false
60
88
  if (res.success && goBack) {
@@ -106,7 +134,7 @@ const FixedTimeForPlugPage = (props: { theme?: ThemeType}) => {
106
134
  item={item}
107
135
  is24Hour={params.is24Hour}
108
136
  onSwitch={async (v) => {
109
- await onPost('edit', {
137
+ await onPost('set', {
110
138
  ...item,
111
139
  enable: v,
112
140
  settingTime: new Date().getTime()
@@ -36,6 +36,7 @@ interface FixedTimeDetailParam extends FixedTimingParam {
36
36
  const newFixedTimingItem = (): FixedTimingItem => {
37
37
  const startTime = dayjs().hour() * 60 + dayjs().minute()
38
38
  return {
39
+ name: I18n.getLang('fixedTimeCycle_socket_headline'),
39
40
  power: true,
40
41
  channel: 0,
41
42
  weeks: [0, 0, 0, 0, 0, 0, 0],
@@ -105,14 +106,14 @@ const FixedTimingForLightDetailPage = (props: { theme?: ThemeType }) => {
105
106
  return timeInterval >= workTime
106
107
  }, [state.item.startTime, state.item.endTime, state.onHour, state.onMinute, state.offHour, state.offMinute])
107
108
 
108
- const canSave = useMemo(() => {
109
- return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && isTimeEffective
110
- }, [state.item.name, state.item.channel, isTimeEffective])
111
-
112
109
  const showConfirm = useMemo(() => {
113
110
  return !isEqual(state.item, params.mode === 'edit' ? params.item : initItem)
114
111
  }, [JSON.stringify(state.item), JSON.stringify(params.item)])
115
112
 
113
+ const canSave = useMemo(() => {
114
+ return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && isTimeEffective && (showConfirm || params.mode === 'add')
115
+ }, [state.item.name, state.item.channel, isTimeEffective, showConfirm])
116
+
116
117
  const onSave = async () => {
117
118
  if (!canSave) {
118
119
  return
@@ -230,6 +231,7 @@ const FixedTimingForLightDetailPage = (props: { theme?: ThemeType }) => {
230
231
  />
231
232
  {/* pick */}
232
233
  <TimerPicker
234
+ key={props.theme?.type}
233
235
  itemTextColor='#aeadb5'
234
236
  style={{ paddingVertical: cx(0), marginVertical: cx(0), backgroundColor: props.theme?.global.background }}
235
237
  pickerFontColor={props.theme?.global.fontColor}
@@ -6,7 +6,7 @@ import res from "@ledvance/base/src/res/index";
6
6
  import {useReactive} from "ahooks";
7
7
  import React, {useCallback, useMemo} from "react";
8
8
  import {FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
9
- import {Utils} from "tuya-panel-kit";
9
+ import {Utils, Dialog} from "tuya-panel-kit";
10
10
  import {ui_biz_routerKey} from "../../navigation/Routers";
11
11
  import {FixedTimingItem, FixedTimingParam, useFixedTiming} from "./FixedTimingForLightAction";
12
12
  import Spacer from "@ledvance/base/src/components/Spacer";
@@ -14,7 +14,7 @@ import ItemCard from "./ItemCard";
14
14
  import {cloneDeep} from "lodash";
15
15
  import InfoText from "@ledvance/base/src/components/InfoText";
16
16
  import ThemeType from '@ledvance/base/src/config/themeType'
17
- import { showDialog } from "@ledvance/base/src/utils/common";
17
+ import { isConflictTask, showDialog } from "@ledvance/base/src/utils/common";
18
18
 
19
19
  const {convertX: cx, topBarHeight} = Utils.RatioUtils;
20
20
  const { withTheme } = Utils.ThemeUtils
@@ -43,18 +43,46 @@ const FixedTimeForLightPage = (props: { theme?: ThemeType}) => {
43
43
  })
44
44
  }
45
45
 
46
- const onPost = useCallback(async (mode: 'add' | 'edit' | 'del', fixedTiming: FixedTimingItem, goBack?: boolean) => {
46
+ const onPost = useCallback(async (mode: 'add' | 'edit' | 'del' | 'set', fixedTiming: FixedTimingItem, goBack?: boolean) => {
47
47
  state.loading = true
48
48
  const cloneFixedTimingList = cloneDeep(fixedTimingList)
49
49
  const idx = fixedTimingList.findIndex(it => it.index === fixedTiming.index)
50
- if (mode === 'edit') {
50
+ if (mode === 'edit' || mode === 'set') {
51
51
  cloneFixedTimingList.splice(idx, 1, fixedTiming)
52
52
  }
53
53
  if (mode === 'del') cloneFixedTimingList.splice(idx, 1)
54
- const newFixedTimingList = mode === 'add' ? [...fixedTimingList, {
54
+ let newFixedTimingList = mode === 'add' ? [...fixedTimingList, {
55
55
  ...fixedTiming,
56
56
  index: fixedTimingList.length
57
57
  }] : cloneFixedTimingList
58
+ if (((mode === 'edit' || mode === 'set') && fixedTiming.power) || mode === 'add') {
59
+ const cloneList = cloneDeep(newFixedTimingList)
60
+ let itselfConflict = false
61
+ cloneList.forEach((item, idx) => {
62
+ const itself = mode === 'add' ? (idx === cloneList.length - 1) : fixedTiming.index === item.index
63
+ if (!itself && item.power && isConflictTask(item, fixedTiming)) {
64
+ itselfConflict = true
65
+ item.power = false
66
+ }
67
+ })
68
+ if (itselfConflict && mode === 'set') {
69
+ return showDialog({
70
+ method: 'confirm',
71
+ title: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_titel'),
72
+ subTitle: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_description'),
73
+ onConfirm: async (_, { close }) => {
74
+ close()
75
+ await setFixedTimingList(cloneList)
76
+ state.loading = false
77
+ },
78
+ onCancel: () => {
79
+ state.loading = false
80
+ Dialog.close()
81
+ }
82
+ })
83
+ }
84
+ newFixedTimingList = cloneList
85
+ }
58
86
  const res = await setFixedTimingList(newFixedTimingList)
59
87
  state.loading = false
60
88
  if (res.success && goBack) {
@@ -111,7 +139,7 @@ const FixedTimeForLightPage = (props: { theme?: ThemeType}) => {
111
139
  item={item}
112
140
  is24Hour={params.is24Hour}
113
141
  onSwitch={async (v) => {
114
- await onPost('edit', {
142
+ await onPost('set', {
115
143
  ...item,
116
144
  power: v,
117
145
  settingTime: new Date().getTime()
@@ -47,6 +47,9 @@ export const useDreamMusicData = (musicOption: MusicPageParams) => {
47
47
  }
48
48
  dps[musicOption.workModeDp] = WorkMode.Music
49
49
  dps[musicOption.switchLedDp] = true
50
+ if (musicOption.colourLedDp && musicOption.isCeilingLight){
51
+ dps[musicOption.colourLedDp] = true
52
+ }
50
53
  }else{
51
54
  dps[musicOption.workModeDp] = v.lastWorkMode
52
55
  }
@@ -30,6 +30,8 @@ export interface MusicPageParams {
30
30
  musicDataDp: string
31
31
  dreamMusicDp?: string
32
32
  isMixLight?: boolean
33
+ isCeilingLight?: boolean
34
+ colourLedDp?: string
33
35
  }
34
36
 
35
37
  const MusicPage = (props: { theme?: ThemeType }) => {
@@ -33,6 +33,7 @@ interface RandomTimeDetailParam extends RandomTimeParam {
33
33
  const newRandomTimeItem = (): RandomTimeItem => {
34
34
  const startTime = dayjs().hour() * 60 + dayjs().minute()
35
35
  return {
36
+ name: I18n.getLang('randomtimecycle_sockets_headline_text'),
36
37
  enable: true,
37
38
  channel: 0,
38
39
  weeks: [0, 0, 0, 0, 0, 0, 0, 0],
@@ -51,14 +52,14 @@ const RandomTimeForPlugDetailPage = (props: { theme?: ThemeType }) => {
51
52
  loading: false
52
53
  })
53
54
 
54
- const canSave = useMemo(() => {
55
- return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined
56
- }, [state.item.name, state.item.channel])
57
-
58
55
  const showConfirm = useMemo(() => {
59
56
  return !isEqual(state.item, params.mode === 'edit' ? params.item : initItem)
60
57
  }, [JSON.stringify(state.item), JSON.stringify(params.item)])
61
58
 
59
+ const canSave = useMemo(() => {
60
+ return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && (showConfirm || params.mode === 'add')
61
+ }, [state.item.name, state.item.channel, showConfirm])
62
+
62
63
  const onSave = async () => {
63
64
  if (!canSave) {
64
65
  return
@@ -162,6 +163,7 @@ const RandomTimeForPlugDetailPage = (props: { theme?: ThemeType }) => {
162
163
  />
163
164
  {/* pick */}
164
165
  <TimerPicker
166
+ key={props.theme?.type}
165
167
  itemTextColor="#aeadb5"
166
168
  style={{ paddingVertical: cx(0), marginVertical: cx(0), backgroundColor: props.theme?.global.background }}
167
169
  pickerFontColor={props.theme?.global.fontColor}
@@ -6,7 +6,7 @@ import res from "@ledvance/base/src/res/index";
6
6
  import {useReactive} from "ahooks";
7
7
  import React, {useCallback, useMemo} from "react";
8
8
  import {FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
9
- import {Utils} from "tuya-panel-kit";
9
+ import {Dialog, Utils} from "tuya-panel-kit";
10
10
  import {ui_biz_routerKey} from "../../navigation/Routers";
11
11
  import {RandomTimeItem, RandomTimeParam, useRandomTime} from "./RandomTimeForPlugAction";
12
12
  import Spacer from "@ledvance/base/src/components/Spacer";
@@ -14,7 +14,7 @@ import ItemCard from "./ItemCard";
14
14
  import {cloneDeep} from "lodash";
15
15
  import InfoText from "@ledvance/base/src/components/InfoText";
16
16
  import ThemeType from '@ledvance/base/src/config/themeType'
17
- import { showDialog } from "@ledvance/base/src/utils/common";
17
+ import { isConflictTask, showDialog } from "@ledvance/base/src/utils/common";
18
18
 
19
19
  const {convertX: cx, topBarHeight} = Utils.RatioUtils;
20
20
  const { withTheme } = Utils.ThemeUtils
@@ -43,18 +43,46 @@ const RandomTimeForPlugPage = (props: { theme?: ThemeType}) => {
43
43
  })
44
44
  }
45
45
 
46
- const onPost = useCallback(async (mode: 'add' | 'edit' | 'del', randomTime: RandomTimeItem, goBack?: boolean) => {
46
+ const onPost = useCallback(async (mode: 'add' | 'edit' | 'del' | 'set', randomTime: RandomTimeItem, goBack?: boolean) => {
47
47
  state.loading = true
48
48
  const cloneRandomTimeList = cloneDeep(randomTimeList)
49
49
  const idx = randomTimeList.findIndex(it => it.index === randomTime.index)
50
- if (mode === 'edit') {
50
+ if (mode === 'edit' || mode === 'set') {
51
51
  cloneRandomTimeList.splice(idx, 1, randomTime)
52
52
  }
53
53
  if (mode === 'del') cloneRandomTimeList.splice(idx, 1)
54
- const newRandomTimeList = mode === 'add' ? [...randomTimeList, {
54
+ let newRandomTimeList = mode === 'add' ? [...randomTimeList, {
55
55
  ...randomTime,
56
56
  index: randomTimeList.length
57
57
  }] : cloneRandomTimeList
58
+ if (((mode === 'edit' || mode === 'set') && randomTime.enable) || mode === 'add') {
59
+ const cloneList = cloneDeep(newRandomTimeList)
60
+ let itselfConflict = false
61
+ cloneList.forEach((item, idx) => {
62
+ const itself = mode === 'add' ? (idx === cloneList.length - 1) : randomTime.index === item.index
63
+ if (!itself && item.enable && isConflictTask(item, randomTime)) {
64
+ itselfConflict = true
65
+ item.enable = false
66
+ }
67
+ })
68
+ if (itselfConflict && mode === 'set') {
69
+ return showDialog({
70
+ method: 'confirm',
71
+ title: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_titel'),
72
+ subTitle: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_description'),
73
+ onConfirm: async (_, { close }) => {
74
+ close()
75
+ await setRandomTimeList(cloneList)
76
+ state.loading = false
77
+ },
78
+ onCancel: () => {
79
+ state.loading = false
80
+ Dialog.close()
81
+ }
82
+ })
83
+ }
84
+ newRandomTimeList = cloneList
85
+ }
58
86
  const res = await setRandomTimeList(newRandomTimeList)
59
87
  state.loading = false
60
88
  if (res.success && goBack) {
@@ -120,7 +148,7 @@ const RandomTimeForPlugPage = (props: { theme?: ThemeType}) => {
120
148
  item={item}
121
149
  is24Hour={params.is24Hour}
122
150
  onSwitch={async (v) => {
123
- await onPost('edit', {
151
+ await onPost('set', {
124
152
  ...item,
125
153
  enable: v,
126
154
  settingTime: new Date().getTime()
@@ -24,10 +24,11 @@ export interface ItemCardProps<T> {
24
24
  is24Hour?: boolean,
25
25
  onSwitch: (enable: boolean) => void
26
26
  onPress: () => void
27
+ onLongPress: () => void
27
28
  }
28
29
 
29
30
  const ItemCard = <T, >(props: ItemCardProps<T>) => {
30
- const {item, is24Hour, onSwitch, onPress} = props
31
+ const {item, is24Hour, onSwitch, onPress, onLongPress} = props
31
32
  // 判断是否关闭
32
33
  const closed = getIsClosed(item)
33
34
 
@@ -56,7 +57,7 @@ const ItemCard = <T, >(props: ItemCardProps<T>) => {
56
57
  })
57
58
 
58
59
  return (
59
- <Card style={styles.itemCard} onPress={onPress}>
60
+ <Card style={styles.itemCard} onPress={onPress} onLongPress={onLongPress}>
60
61
  <Spacer height={cx(16)}/>
61
62
  <View style={styles.switchLine}>
62
63
  <Text style={styles.time}>
@@ -35,6 +35,7 @@ interface RandomTimeDetailParam extends RandomTimingParam {
35
35
  const newRandomTimingItem = (): RandomTimingItem => {
36
36
  const startTime = dayjs().hour() * 60 + dayjs().minute()
37
37
  return {
38
+ name: I18n.getLang('randomtimecycle_sockets_headline_text'),
38
39
  power: true,
39
40
  channel: 0,
40
41
  weeks: [0, 0, 0, 0, 0, 0, 0],
@@ -66,14 +67,14 @@ const RandomTimingForLightDetailPage = (props: { theme?: ThemeType }) => {
66
67
  state.isColorMode = brightness === 0 && temperature === 0 && (hue !== 0 || saturation !== 0 || value !== 0)
67
68
  }, [])
68
69
 
69
- const canSave = useMemo(() => {
70
- return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined
71
- }, [state.item.name, state.item.channel])
72
-
73
70
  const showConfirm = useMemo(() => {
74
71
  return !isEqual(state.item, params.mode === 'edit' ? params.item : initItem)
75
72
  }, [JSON.stringify(state.item), JSON.stringify(params.item)])
76
73
 
74
+ const canSave = useMemo(() => {
75
+ return state.item.name && state.item.name.length < 33 && state.item.channel !== undefined && (showConfirm || params.mode === 'add')
76
+ }, [state.item.name, state.item.channel, showConfirm])
77
+
77
78
  const onSave = async () => {
78
79
  if (!canSave) {
79
80
  return
@@ -185,6 +186,7 @@ const RandomTimingForLightDetailPage = (props: { theme?: ThemeType }) => {
185
186
  />
186
187
  {/* pick */}
187
188
  <TimerPicker
189
+ key={props.theme?.type}
188
190
  itemTextColor='#aeadb5'
189
191
  style={{ paddingVertical: cx(0), marginVertical: cx(0), backgroundColor: props.theme?.global.background }}
190
192
  pickerFontColor={props.theme?.global.fontColor}
@@ -6,7 +6,7 @@ import res from "@ledvance/base/src/res/index";
6
6
  import {useReactive} from "ahooks";
7
7
  import React, {useCallback, useMemo} from "react";
8
8
  import {FlatList, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View} from "react-native";
9
- import {Utils} from "tuya-panel-kit";
9
+ import {Utils, Dialog} from "tuya-panel-kit";
10
10
  import {ui_biz_routerKey} from "../../navigation/Routers";
11
11
  import {RandomTimingItem, RandomTimingParam, useRandomTiming} from "./RandomTimingForLightAction";
12
12
  import Spacer from "@ledvance/base/src/components/Spacer";
@@ -14,7 +14,7 @@ import ItemCard from "./ItemCard";
14
14
  import {cloneDeep} from "lodash";
15
15
  import InfoText from "@ledvance/base/src/components/InfoText";
16
16
  import ThemeType from '@ledvance/base/src/config/themeType'
17
- import { showDialog } from "@ledvance/base/src/utils/common";
17
+ import { isConflictTask, showDialog } from "@ledvance/base/src/utils/common";
18
18
 
19
19
  const {convertX: cx, topBarHeight} = Utils.RatioUtils;
20
20
  const { withTheme } = Utils.ThemeUtils
@@ -43,18 +43,46 @@ const RandomTimeForLightPage = (props: { theme?: ThemeType}) => {
43
43
  })
44
44
  }
45
45
 
46
- const onPost = useCallback(async (mode: 'add' | 'edit' | 'del', randomTiming: RandomTimingItem, goBack?: boolean) => {
46
+ const onPost = useCallback(async (mode: 'add' | 'edit' | 'del' | 'set', randomTiming: RandomTimingItem, goBack?: boolean) => {
47
47
  state.loading = true
48
48
  const cloneRandomTimingList = cloneDeep(randomTimingList)
49
49
  const idx = randomTimingList.findIndex(it => it.index === randomTiming.index)
50
- if (mode === 'edit') {
50
+ if (mode === 'edit' || mode === 'set') {
51
51
  cloneRandomTimingList.splice(idx, 1, randomTiming)
52
52
  }
53
53
  if (mode === 'del') cloneRandomTimingList.splice(idx, 1)
54
- const newRandomTimingList = mode === 'add' ? [...randomTimingList, {
54
+ let newRandomTimingList = mode === 'add' ? [...randomTimingList, {
55
55
  ...randomTiming,
56
56
  index: randomTimingList.length
57
57
  }] : cloneRandomTimingList
58
+ if (((mode === 'edit' || mode === 'set') && randomTiming.power) || mode === 'add') {
59
+ const cloneList = cloneDeep(newRandomTimingList)
60
+ let itselfConflict = false
61
+ cloneList.forEach((item, idx) => {
62
+ const itself = mode === 'add' ? (idx === cloneList.length - 1) : randomTiming.index === item.index
63
+ if (!itself && item.power && isConflictTask(item, randomTiming)) {
64
+ itselfConflict = true
65
+ item.power = false
66
+ }
67
+ })
68
+ if (itselfConflict && mode === 'set') {
69
+ return showDialog({
70
+ method: 'confirm',
71
+ title: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_titel'),
72
+ subTitle: I18n.getLang('conflict_dialog_active_item_fixedtimecycle_description'),
73
+ onConfirm: async (_, { close }) => {
74
+ close()
75
+ await setRandomTimingList(cloneList)
76
+ state.loading = false
77
+ },
78
+ onCancel: () => {
79
+ state.loading = false
80
+ Dialog.close()
81
+ }
82
+ })
83
+ }
84
+ newRandomTimingList = cloneList
85
+ }
58
86
  const res = await setRandomTimingList(newRandomTimingList)
59
87
  state.loading = false
60
88
  if (res.success && goBack) {
@@ -123,7 +151,7 @@ const RandomTimeForLightPage = (props: { theme?: ThemeType}) => {
123
151
  item={item}
124
152
  is24Hour={params.is24Hour}
125
153
  onSwitch={async (v) => {
126
- await onPost('edit', {
154
+ await onPost('set', {
127
155
  ...item,
128
156
  power: v,
129
157
  settingTime: new Date().getTime()
@@ -41,7 +41,7 @@ export function getEndTime(item: SleepWakeUpItem) {
41
41
  return time > 1440 ? time - 1440 : time
42
42
  }
43
43
 
44
- const encodeSleepOrWakeUp = (items: SleepWakeUpItem[]) => {
44
+ export const encodeSleepOrWakeUp = (items: SleepWakeUpItem[]) => {
45
45
  const bytes: number[] = []
46
46
  bytes.push(numToByte(0))
47
47
  bytes.push(numToByte(items.length))
@@ -91,7 +91,7 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
91
91
  return cctToColor(state.sleepWakeUp.temperature);
92
92
  }, [state.sleepWakeUp]);
93
93
 
94
- const showBackDialog = () => {
94
+ const showBackDialog = useMemo(() => {
95
95
  const excludeKeys: string[] = []
96
96
  if (state.sleepWakeUp.isColorMode) {
97
97
  excludeKeys.push('brightness', 'temperature')
@@ -99,11 +99,11 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
99
99
  excludeKeys.push('hue', 'sat', 'value')
100
100
  }
101
101
  return !isEqual(omit(params.scheduleItem, excludeKeys), omit(state.sleepWakeUp, excludeKeys))
102
- };
102
+ }, [JSON.stringify(params.scheduleItem), JSON.stringify(state.sleepWakeUp)])
103
103
 
104
104
  const caSubmit = useMemo(() => {
105
- return state.sleepWakeUp.name?.length > 0 && state.sleepWakeUp.name?.length < 33;
106
- }, [state.sleepWakeUp.name]);
105
+ return state.sleepWakeUp.name?.length > 0 && state.sleepWakeUp.name?.length < 33 && (showBackDialog || params.mode === 'add');
106
+ }, [state.sleepWakeUp.name, showBackDialog]);
107
107
 
108
108
  const mixLightCard = useMemo(() => {
109
109
  const applyList = params.applyForList.map(item => {
@@ -191,7 +191,7 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
191
191
  picker: {
192
192
  marginHorizontal: cx(24),
193
193
  marginVertical: cx(15),
194
- color: props.theme?.global.backgournd,
194
+ color: props.theme?.global.background,
195
195
  },
196
196
  week: {},
197
197
  itemTitle: {
@@ -257,7 +257,7 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
257
257
  return (
258
258
  <Page
259
259
  backText={I18n.getLang('add_sleepschedule_one_source_system_back_text')}
260
- showBackDialog={showBackDialog()}
260
+ showBackDialog={showBackDialog}
261
261
  loading={state.loading}
262
262
  backDialogTitle={I18n.getLang('cancel_dialog_leave_unsaved_titel')}
263
263
  backDialogContent={I18n.getLang(
@@ -265,9 +265,9 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
265
265
  ? 'cancel_dialog_leave_unsaved_sleepschedule_note'
266
266
  : 'cancel_dialog_leave_unsaved_wakeupschedule_note'
267
267
  )}
268
- rightButtonIcon={showBackDialog() && caSubmit ? res.ic_check : res.ic_uncheck}
268
+ rightButtonIcon={caSubmit ? res.ic_check : res.ic_uncheck}
269
269
  rightButtonIconClick={async () => {
270
- if (!showBackDialog() || !caSubmit || state.loading) return;
270
+ if (!caSubmit || state.loading) return;
271
271
  showDialog({
272
272
  method: 'confirm',
273
273
  title: I18n.getLang('conflict_dialog_active_item_sleepschedule_titel'),
@@ -326,6 +326,7 @@ const SleepWakeUpDetailPage = (props: {theme?: ThemeType}) => {
326
326
  />
327
327
  {/* pick */}
328
328
  <TimerPicker
329
+ key={props.theme?.type}
329
330
  itemTextColor="#aeadb5"
330
331
  style={{ paddingVertical: cx(0), marginVertical: cx(0), backgroundColor: props.theme?.global.background }}
331
332
  pickerFontColor={props.theme?.global.fontColor}