@ledvance/group-ui-biz-bundle 1.0.152 → 1.0.153

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.152",
7
+ "version": "1.0.153",
8
8
  "scripts": {},
9
9
  "dependencies": {
10
10
  "@ledvance/base": "^1.x",
@@ -245,26 +245,37 @@ const BiorhythmPage = (props: { theme?: ThemeType }) => {
245
245
  <Page
246
246
  backText={uaGroupInfo.name}
247
247
  onBackClick={navigation.goBack}
248
- headlineTopContent={<View style={{ flexDirection: 'row', width: '100%', justifyContent: 'space-between' }}>
249
- <DeleteButton style={{flex: 1}} text={I18n.getLang('biorhythm_save_as')} onPress={() => {
250
- Dialog.prompt({
251
- title: I18n.getLang('biorhythm_save_title'),
252
- placeholder: I18n.getLang('biorhythm_save_placeholder'),
253
- defaultValue: `${uaGroupInfo.name}`,
254
- cancelText: I18n.getLang('auto_scan_system_cancel'),
255
- confirmText: I18n.getLang('auto_scan_system_wifi_confirm'),
256
- inputWrapperStyle: {backgroundColor: props.theme?.textInput.background, borderRadius: cx(10)},
257
- autoFocus: true,
258
- onConfirm: (data, { close }) => {
259
- saveStorageBiorhythms(data, state.enable, state.gradient, state.repeatPeriod, state.planList)
260
- close()
261
- }
262
- })
263
- }} />
264
- <DeleteButton style={{flex: 1}} text={I18n.getLang('biorhythm_load')} onPress={() => {
265
- setBiorhythmListVisible(true)
266
- }} />
267
- </View>}
248
+ headlineTopContent={
249
+ <View style={{flexDirection: 'row', justifyContent: 'flex-end'}}>
250
+ <TouchableOpacity
251
+ style={{paddingLeft: cx(16)}}
252
+ onPress={() => {
253
+ Dialog.prompt({
254
+ title: I18n.getLang('biorhythm_save_title'),
255
+ placeholder: I18n.getLang('biorhythm_save_placeholder'),
256
+ defaultValue: `${uaGroupInfo.name}`,
257
+ cancelText: I18n.getLang('auto_scan_system_cancel'),
258
+ confirmText: I18n.getLang('auto_scan_system_wifi_confirm'),
259
+ inputWrapperStyle: {backgroundColor: props.theme?.textInput.background, borderRadius: cx(10)},
260
+ autoFocus: true,
261
+ onConfirm: (data, { close }) => {
262
+ saveStorageBiorhythms(data, state.enable, state.gradient, state.repeatPeriod, state.planList)
263
+ close()
264
+ }
265
+ })
266
+ }}
267
+ >
268
+ <Image source={res.icon_save} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
269
+ </TouchableOpacity>
270
+ <TouchableOpacity
271
+ style={{paddingLeft: cx(16)}}
272
+ onPress={() => {
273
+ setBiorhythmListVisible(true)
274
+ }}
275
+ >
276
+ <Image source={res.icon_import} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
277
+ </TouchableOpacity>
278
+ </View>}
268
279
  headlineText={I18n.getLang('add_new_trigger_time_system_back_text')}
269
280
  headlineIconContent={<Switch
270
281
  value={state.enable}
@@ -177,6 +177,9 @@ const DiyScenePage = (props: { theme?: ThemeType }) => {
177
177
  infoLine: {
178
178
  marginHorizontal: cx(24),
179
179
  },
180
+ rightIconView: {
181
+ flexDirection: 'row'
182
+ },
180
183
  addMoodPopover: {
181
184
  position: 'absolute',
182
185
  right: cx(60),
@@ -189,6 +192,9 @@ const DiyScenePage = (props: { theme?: ThemeType }) => {
189
192
  alignItems: 'flex-start',
190
193
  alignSelf: 'flex-start'
191
194
  },
195
+ refresh: {
196
+ paddingLeft: cx(24)
197
+ },
192
198
  })
193
199
 
194
200
  return (
@@ -196,10 +202,33 @@ const DiyScenePage = (props: { theme?: ThemeType }) => {
196
202
  <Page
197
203
  backText={uaGroupInfo.name}
198
204
  headlineText={I18n.getLang('mood_overview_headline_text')}
199
- headlineIcon={state.originScenes.length < MAX_MOOD_COUNT ? res.add : undefined}
200
- onHeadlineIconClick={() => {
201
- navigationRoute('add', cloneDeep(DEFAULT_SCENE))
202
- }}
205
+ headlineIconContent={<View style={styles.rightIconView}>
206
+ <TouchableOpacity
207
+ style={styles.refresh}
208
+ onPress={() => {
209
+ showDialog({
210
+ method: 'confirm',
211
+ title: I18n.getLang('mood_resetbutton'),
212
+ subTitle: I18n.getLang('reset_mooddescription'),
213
+ onConfirm: async (_, { close }) => {
214
+ close()
215
+ resetMixScenes().then();
216
+ }
217
+ })
218
+ }}
219
+ >
220
+ <Image source={{uri: res.ic_refresh}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
221
+ </TouchableOpacity>
222
+ {state.originScenes.length < MAX_MOOD_COUNT && <TouchableOpacity
223
+ style={styles.refresh}
224
+ onPress={() => {
225
+ navigationRoute('add', cloneDeep(DEFAULT_SCENE))
226
+ }}
227
+ >
228
+ <Image source={{uri: res.add}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.brand }} />
229
+ </TouchableOpacity>
230
+ }
231
+ </View>}
203
232
  loading={state.loading}
204
233
  >
205
234
  <View style={styles.tagLine}>
@@ -227,21 +256,6 @@ const DiyScenePage = (props: { theme?: ThemeType }) => {
227
256
  }}
228
257
  />
229
258
  </View>
230
- <TouchableOpacity style={{ alignItems: 'flex-end',paddingRight: cx(24) }}
231
- onPress={() => {
232
- showDialog({
233
- method: 'confirm',
234
- title: I18n.getLang('mood_resetbutton'),
235
- subTitle: I18n.getLang('reset_mooddescription'),
236
- onConfirm: async (_, { close }) => {
237
- close()
238
- resetMixScenes().then();
239
- }
240
- })
241
- }}
242
- >
243
- <Image source={{uri: res.ic_refresh}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
244
- </TouchableOpacity>
245
259
  <Spacer height={cx(10)} />
246
260
  {state.originScenes.length >= MAX_MOOD_COUNT && (
247
261
  <View style={styles.infoLine}>
@@ -498,6 +498,55 @@ function getStringLightSceneList(): RemoteMoodInfo[] {
498
498
  t: 0,
499
499
  e: false,
500
500
  },
501
+ {
502
+ n: I18n.getLang('strip_lights_mood_text45'),
503
+ i: '0125101e1e0000003700a032000000003700c3640000000037011364000000003700782800000000',
504
+ s: '',
505
+ t: 0,
506
+ e: false,
507
+ },
508
+ {
509
+ n: I18n.getLang('strip_lights_mood_text46'),
510
+ i: '01261014140000002d00174a000000002d002348000000002d001e24000000002d00014000000000',
511
+ s: '',
512
+ t: 0,
513
+ e: false,
514
+ },
515
+ {
516
+ n: I18n.getLang('strip_lights_mood_text47'),
517
+ i: '01270a555500000055012c64000000005500b4640000000055010f51000000005501485c00000000',
518
+ s: '',
519
+ t: 0,
520
+ e: false,
521
+ },
522
+ {
523
+ n: I18n.getLang('strip_lights_mood_text48'),
524
+ i: '01281028280000003700d258000000003700b564000000003700b152000000003700f06400000000',
525
+ s: '',
526
+ t: 0,
527
+ e: false,
528
+ },
529
+ {
530
+ n: I18n.getLang('strip_lights_mood_text49'),
531
+ i: '0129100f0f0000002300784c000000002300504b0000000023005238000000002300545200000000',
532
+ s: '',
533
+ t: 0,
534
+ e: false,
535
+ },
536
+ {
537
+ n: I18n.getLang('strip_lights_mood_text50'),
538
+ i: '012a0a5050000000640000640000000064007864000000006400f0640000000064003c640000000064012c6400000000',
539
+ s: '',
540
+ t: 0,
541
+ e: false,
542
+ },
543
+ {
544
+ n: I18n.getLang('strip_lights_mood_text51'),
545
+ i: '012b1032320000001e00f04e000000001e011364000000001e00b42900000000',
546
+ s: '',
547
+ t: 0,
548
+ e: false,
549
+ },
501
550
  ];
502
551
  }
503
552
 
@@ -811,6 +860,55 @@ function getStripLightSceneList(): RemoteMoodInfo[] {
811
860
  t: 0,
812
861
  e: false,
813
862
  },
863
+ {
864
+ n: I18n.getLang('strip_lights_mood_text45'),
865
+ i: '013b011e1e6000003700a03200c364011364007828',
866
+ s: '',
867
+ t: 0,
868
+ e: false,
869
+ },
870
+ {
871
+ n: I18n.getLang('strip_lights_mood_text46'),
872
+ i: '013c0114146000002d00174a002348001e24000140',
873
+ s: '',
874
+ t: 0,
875
+ e: false,
876
+ },
877
+ {
878
+ n: I18n.getLang('strip_lights_mood_text47'),
879
+ i: '013d02555560000055012c6400b464010f5101485c',
880
+ s: '',
881
+ t: 0,
882
+ e: false,
883
+ },
884
+ {
885
+ n: I18n.getLang('strip_lights_mood_text48'),
886
+ i: '013e0128286000003700d25800b56400b15200f064',
887
+ s: '',
888
+ t: 0,
889
+ e: false,
890
+ },
891
+ {
892
+ n: I18n.getLang('strip_lights_mood_text49'),
893
+ i: '013f010f0f6000002300784c00504b005238005452',
894
+ s: '',
895
+ t: 0,
896
+ e: false,
897
+ },
898
+ {
899
+ n: I18n.getLang('strip_lights_mood_text50'),
900
+ i: '01400250506000006400006400786400f064003c64012c64',
901
+ s: '',
902
+ t: 0,
903
+ e: false,
904
+ },
905
+ {
906
+ n: I18n.getLang('strip_lights_mood_text51'),
907
+ i: '01410132326000001e00f04e01136400b429',
908
+ s: '',
909
+ t: 0,
910
+ e: false,
911
+ },
814
912
  ];
815
913
  }
816
914
 
@@ -1152,6 +1250,55 @@ function getMixCeilingLightList(): RemoteMoodInfo[] {
1152
1250
  t: 0,
1153
1251
  e: false,
1154
1252
  },
1253
+ {
1254
+ n: I18n.getLang('strip_lights_mood_text45'),
1255
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1256
+ s: '013b011e1e6000003700a03200c364011364007828',
1257
+ t: 0,
1258
+ e: false,
1259
+ },
1260
+ {
1261
+ n: I18n.getLang('strip_lights_mood_text46'),
1262
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1263
+ s: '013c0114146000002d00174a002348001e24000140',
1264
+ t: 0,
1265
+ e: false,
1266
+ },
1267
+ {
1268
+ n: I18n.getLang('strip_lights_mood_text47'),
1269
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1270
+ s: '013d02555560000055012c6400b464010f5101485c',
1271
+ t: 0,
1272
+ e: false,
1273
+ },
1274
+ {
1275
+ n: I18n.getLang('strip_lights_mood_text48'),
1276
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1277
+ s: '013e0128286000003700d25800b56400b15200f064',
1278
+ t: 0,
1279
+ e: false,
1280
+ },
1281
+ {
1282
+ n: I18n.getLang('strip_lights_mood_text49'),
1283
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1284
+ s: '013f010f0f6000002300784c00504b005238005452',
1285
+ t: 0,
1286
+ e: false,
1287
+ },
1288
+ {
1289
+ n: I18n.getLang('strip_lights_mood_text50'),
1290
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1291
+ s: '01400250506000006400006400786400f064003c64012c64',
1292
+ t: 0,
1293
+ e: false,
1294
+ },
1295
+ {
1296
+ n: I18n.getLang('strip_lights_mood_text51'),
1297
+ i: '040d0d0100000000000003e800000d0d0100000000000003e80000',
1298
+ s: '01410132326000001e00f04e01136400b429',
1299
+ t: 0,
1300
+ e: false,
1301
+ },
1155
1302
  ];
1156
1303
  }
1157
1304
 
@@ -1400,6 +1547,55 @@ const defColorSceneList: RemoteMoodInfo[] = [
1400
1547
  t: 0,
1401
1548
  e: false,
1402
1549
  },
1550
+ {
1551
+ n: I18n.getLang('strip_lights_mood_text45'),
1552
+ i: '251e1e0200a001f40226000000001e1e0200c303e80226000000001e1e02011303e80226000000001e1e0200780190022600000000',
1553
+ s: '',
1554
+ t: 0,
1555
+ e: false,
1556
+ },
1557
+ {
1558
+ n: I18n.getLang('strip_lights_mood_text46'),
1559
+ i: '26141402001702e401c200000000141402002302d001c200000000141402001e016801c2000000001414020001028001c200000000',
1560
+ s: '',
1561
+ t: 0,
1562
+ e: false,
1563
+ },
1564
+ {
1565
+ n: I18n.getLang('strip_lights_mood_text47'),
1566
+ i: '27555501012c03e803520000000055550100b403e8035200000000555501010f032a03520000000055550101480398035200000000',
1567
+ s: '',
1568
+ t: 0,
1569
+ e: false,
1570
+ },
1571
+ {
1572
+ n: I18n.getLang('strip_lights_mood_text48'),
1573
+ i: '2828280200d2037002260000000028280200b503e802260000000028280200b1033402260000000028280200f003e8022600000000',
1574
+ s: '',
1575
+ t: 0,
1576
+ e: false,
1577
+ },
1578
+ {
1579
+ n: I18n.getLang('strip_lights_mood_text49'),
1580
+ i: '290f0f02007802f8015e000000000f0f02005002ee015e000000000f0f0200520230015e000000000f0f0200540334015e00000000',
1581
+ s: '',
1582
+ t: 0,
1583
+ e: false,
1584
+ },
1585
+ {
1586
+ n: I18n.getLang('strip_lights_mood_text50'),
1587
+ i: '2a505001000003e803e800000000505001007803e803e80000000050500100f003e803e800000000505001003c03e803e800000000505001012c03e803e800000000',
1588
+ s: '',
1589
+ t: 0,
1590
+ e: false,
1591
+ },
1592
+ {
1593
+ n: I18n.getLang('strip_lights_mood_text51'),
1594
+ i: '2b32320200f0030c012c00000000323202011303e8012c0000000032320200b4019a012c00000000',
1595
+ s: '',
1596
+ t: 0,
1597
+ e: false,
1598
+ },
1403
1599
  ];
1404
1600
 
1405
1601
  const defMixColorSceneList: MixRemoteMoodInfo[] = [
@@ -1553,6 +1749,41 @@ const defMixColorSceneList: MixRemoteMoodInfo[] = [
1553
1749
  image: '',
1554
1750
  value: '002400000103034b4b0200d203e803e84b4b0200b403e803e84b4b02009603e803e8',
1555
1751
  },
1752
+ {
1753
+ name: I18n.getLang('strip_lights_mood_text45'),
1754
+ image: '',
1755
+ value: '002500000104031e1e0200a001f402261e1e0200c303e802261e1e02011303e802261e1e02007801900226',
1756
+ },
1757
+ {
1758
+ name: I18n.getLang('strip_lights_mood_text46'),
1759
+ image: '',
1760
+ value: '00260000010403141402001702e401c2141402002302d001c2141402001e016801c21414020001028001c2',
1761
+ },
1762
+ {
1763
+ name: I18n.getLang('strip_lights_mood_text47'),
1764
+ image: '',
1765
+ value: '00270000010403555501012c03e8035255550100b403e80352555501010f032a0352555501014803980352',
1766
+ },
1767
+ {
1768
+ name: I18n.getLang('strip_lights_mood_text48'),
1769
+ image: '',
1770
+ value: '0028000001040328280200d20370022628280200b503e8022628280200b10334022628280200f003e80226',
1771
+ },
1772
+ {
1773
+ name: I18n.getLang('strip_lights_mood_text49'),
1774
+ image: '',
1775
+ value: '002900000104030f0f02007802f8015e0f0f02005002ee015e0f0f0200520230015e0f0f0200540334015e',
1776
+ },
1777
+ {
1778
+ name: I18n.getLang('strip_lights_mood_text50'),
1779
+ image: '',
1780
+ value: '002a0000010503505001000003e803e8505001007803e803e850500100f003e803e8505001003c03e803e8505001012c03e803e8',
1781
+ },
1782
+ {
1783
+ name: I18n.getLang('strip_lights_mood_text51'),
1784
+ image: '',
1785
+ value: '002b000001030332320200f0030c012c323202011303e8012c32320200b4019a012c',
1786
+ },
1556
1787
  ];
1557
1788
 
1558
1789
  export type RecommendMood = {
@@ -9,7 +9,7 @@ import {
9
9
  useSwitchLed,
10
10
  useWorkMode
11
11
  } from './MoodActions';
12
- import {useMoods, useUAGroupInfo,} from '@ledvance/base/src/models/modules/NativePropsSlice';
12
+ import { useIsPad, useMoods, useUAGroupInfo, } from '@ledvance/base/src/models/modules/NativePropsSlice'
13
13
  import {useReactive} from 'ahooks';
14
14
  import Strings from '@ledvance/base/src/i18n';
15
15
  import I18n from '@ledvance/base/src/i18n';
@@ -30,21 +30,17 @@ import {WorkMode} from '@ledvance/base/src/utils/interface';
30
30
  import ThemeType from '@ledvance/base/src/config/themeType'
31
31
  import {showDialog} from '@ledvance/base/src/utils/common';
32
32
 
33
- const { convertX: cx, width: screenWidth } = Utils.RatioUtils;
33
+ const { convertX: cx } = Utils.RatioUtils;
34
34
  const { withTheme } = Utils.ThemeUtils
35
35
 
36
36
  const MAX_MOOD_COUNT = 255;
37
- // --- 动态计算项目宽度 ---
38
- // 1. 定义网格的边距和列间距
39
- const GRID_HORIZONTAL_PADDING = cx(24);
37
+
38
+ // --- 将布局常量移到这里,方便管理 ---
39
+ const OPTIMAL_ITEM_WIDTH = cx(160); // 定义一个在所有设备上看起来都很好的“最佳宽度”
40
40
  const GRID_GAP = cx(16);
41
- const NUM_COLUMNS = 2;
42
- // 2. 计算每个 MoodItem 的宽度
43
- // (屏幕总宽度 - 两边的边距 - (列数 - 1) * 列间距) / 列数
44
- const ITEM_WIDTH =
45
- (screenWidth - GRID_HORIZONTAL_PADDING * 2 - (NUM_COLUMNS - 1) * GRID_GAP) / NUM_COLUMNS;
46
41
 
47
42
  const MoodPage = (props: {theme?: ThemeType}) => {
43
+ // ... (所有 hooks 和 state 定义保持不变) ...
48
44
  const params = useParams<MoodPageParams>();
49
45
  const uaGroupInfo = useUAGroupInfo()
50
46
  const navigation = useNavigation();
@@ -54,6 +50,7 @@ const MoodPage = (props: {theme?: ThemeType}) => {
54
50
  const rgbicWorkMode = useRgbicWorkMode()
55
51
  const [moods, setMoods] = useMoods();
56
52
  const [flagMode, setFlagMode] = useFlagMode();
53
+ const isPad = useIsPad()
57
54
  const state = useReactive<MoodPageState>({
58
55
  currentMood: undefined,
59
56
  staticTagChecked: true,
@@ -66,6 +63,28 @@ const MoodPage = (props: {theme?: ThemeType}) => {
66
63
  flag: Symbol(),
67
64
  });
68
65
 
66
+ // --- 关键逻辑 1: 基于 isPad 决定列数,并计算出 FlatList 自身所需的总宽度 ---
67
+ const { numColumns, flatListWidth } = useMemo(() => {
68
+ const cols = isPad ? 3 : 2;
69
+ // FlatList 的总宽度 = (项目数 * 项目宽度) + (项目数 - 1) * 间距
70
+ const listWidth = cols * OPTIMAL_ITEM_WIDTH + (cols - 1) * GRID_GAP;
71
+ return {
72
+ numColumns: cols,
73
+ flatListWidth: listWidth,
74
+ };
75
+ }, [isPad]);
76
+ // --- 关键逻辑 2: 准备幽灵元素数据 (逻辑不变) ---
77
+ const gridData = useMemo(() => {
78
+ const data = state.filterMoods;
79
+ const numToPad = numColumns - (data.length % numColumns);
80
+ if (numToPad === numColumns) {
81
+ return data;
82
+ }
83
+ const ghostItems = Array.from({ length: numToPad }, (_, i) => ({ name: `ghost-${i}`, isGhost: true }));
84
+ return [...data, ...ghostItems];
85
+ }, [state.filterMoods, numColumns]);
86
+
87
+ // ... (所有 useEffect 和函数逻辑保持不变) ...
69
88
  const moodIds = useMemo(() => {
70
89
  // @ts-ignore
71
90
  const mainIds = map(params.isCeilingLight ? (state.originMoods.map(m => m.mainLamp) || []) : state.originMoods, 'id').filter(v => v !== undefined)
@@ -279,6 +298,9 @@ const MoodPage = (props: {theme?: ThemeType}) => {
279
298
  infoLine: {
280
299
  marginHorizontal: cx(24),
281
300
  },
301
+ rightIconView: {
302
+ flexDirection: 'row'
303
+ },
282
304
  addMoodPopover: {
283
305
  position: 'absolute',
284
306
  right: cx(60),
@@ -291,12 +313,17 @@ const MoodPage = (props: {theme?: ThemeType}) => {
291
313
  alignItems: 'flex-start',
292
314
  },
293
315
  refresh: {
294
- alignItems: 'flex-end',
295
- paddingRight: cx(24)
316
+ paddingLeft: cx(24)
296
317
  },
318
+ // 重新启用 columnWrapperStyle
297
319
  columnWrapperStyle: {
298
320
  justifyContent: 'space-between',
299
321
  },
322
+ // --- 关键逻辑 3: 新增列表容器样式 ---
323
+ listContainer: {
324
+ flex: 1,
325
+ alignItems: 'center', // 让内部的 FlatList 水平居中
326
+ },
300
327
  })
301
328
 
302
329
  return (
@@ -304,14 +331,37 @@ const MoodPage = (props: {theme?: ThemeType}) => {
304
331
  <Page
305
332
  backText={uaGroupInfo.name}
306
333
  headlineText={Strings.getLang('mood_overview_headline_text')}
307
- headlineIcon={state.originMoods.length < MAX_MOOD_COUNT ? res.add : undefined}
308
- onHeadlineIconClick={() => {
309
- if (params.isStringLight || params.isStripLight) {
310
- onAddMoodDialogItemClick(false, 1);
311
- } else {
312
- state.showAddMoodPopover = !state.showAddMoodPopover;
334
+ headlineIconContent={<View style={styles.rightIconView}>
335
+ <TouchableOpacity
336
+ style={styles.refresh}
337
+ onPress={() => {
338
+ showDialog({
339
+ method: 'confirm',
340
+ title: I18n.getLang('mood_resetbutton'),
341
+ subTitle: I18n.getLang('reset_mooddescription'),
342
+ onConfirm: (_, { close }) => {
343
+ close()
344
+ getMoodList(true)
345
+ }
346
+ })
347
+ }}
348
+ >
349
+ <Image source={{uri: res.ic_refresh}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
350
+ </TouchableOpacity>
351
+ {state.originMoods.length < MAX_MOOD_COUNT && <TouchableOpacity
352
+ style={styles.refresh}
353
+ onPress={() => {
354
+ if (params.isStringLight || params.isStripLight) {
355
+ onAddMoodDialogItemClick(false, 1);
356
+ } else {
357
+ state.showAddMoodPopover = !state.showAddMoodPopover;
358
+ }
359
+ }}
360
+ >
361
+ <Image source={{uri: res.add}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.brand }} />
362
+ </TouchableOpacity>
313
363
  }
314
- }}
364
+ </View>}
315
365
  loading={state.loading}
316
366
  >
317
367
  {!params.isStripLight && !params.isStringLight && <View style={styles.tagLine}>
@@ -331,22 +381,6 @@ const MoodPage = (props: {theme?: ThemeType}) => {
331
381
  }}
332
382
  />
333
383
  </View>}
334
- <TouchableOpacity
335
- style={styles.refresh}
336
- onPress={() => {
337
- showDialog({
338
- method: 'confirm',
339
- title: I18n.getLang('mood_resetbutton'),
340
- subTitle: I18n.getLang('reset_mooddescription'),
341
- onConfirm: (_, { close }) => {
342
- close()
343
- getMoodList(true)
344
- }
345
- })
346
- }}
347
- >
348
- <Image source={{uri: res.ic_refresh}} style={{ width: cx(24), height: cx(24), tintColor: props.theme?.global.fontColor }} />
349
- </TouchableOpacity>
350
384
  <Spacer height={cx(10)} />
351
385
  {state.originMoods.length >= MAX_MOOD_COUNT && (
352
386
  <View style={styles.infoLine}>
@@ -359,44 +393,44 @@ const MoodPage = (props: {theme?: ThemeType}) => {
359
393
  <Spacer height={cx(6)} />
360
394
  </View>
361
395
  )}
362
- <FlatList
363
- data={state.filterMoods}
364
- // 关键属性 1: 设置列数
365
- numColumns={NUM_COLUMNS}
366
- // 关键属性 2: 为 FlatList 提供一个唯一的 key,当列数改变时强制刷新
367
- key={NUM_COLUMNS}
368
- // 关键属性 3: 设置整个列表容器的样式,主要是左右边距
369
- contentContainerStyle={{
370
- paddingHorizontal: GRID_HORIZONTAL_PADDING,
371
- }}
372
- // 关键属性 4: 设置行包装器的样式,用于在列之间创建间距
373
- columnWrapperStyle={styles.columnWrapperStyle}
374
- renderItem={({ item }) => {
375
- return (
376
- <MoodItem
377
- // 关键修改:通过 style prop 传入计算好的宽度
378
- style={{ width: ITEM_WIDTH }}
379
- enable={getItemEnable(item)}
380
- isMix={!!(params.isMixLight || params.isCeilingLight)}
381
- deviceTypeOption={params}
382
- mood={item}
383
- onPress={() => {
384
- navigationRoute(item.mainLamp.nodes.length === 1, 'edit', item);
385
- }}
386
- onSwitch={async _ => {
387
- state.loading = true;
388
- await modDeleteMood('set', item);
389
- updateFlagMode();
390
- state.loading = false;
391
- }}
392
- />
393
- );
394
- }}
395
- ListHeaderComponent={() => <Spacer height={cx(10)} />}
396
- ItemSeparatorComponent={() => <Spacer />}
397
- ListFooterComponent={() => <Spacer />}
398
- keyExtractor={item => `${item.name}`}
399
- />
396
+ <View style={styles.listContainer}>
397
+ <FlatList
398
+ data={gridData}
399
+ numColumns={numColumns}
400
+ key={numColumns}
401
+ style={{ width: flatListWidth }} // 给 FlatList 一个固定的总宽度
402
+ // 移除 contentContainerStyle
403
+ columnWrapperStyle={styles.columnWrapperStyle}
404
+ renderItem={({ item }) => {
405
+ if (item.isGhost) {
406
+ return <View style={{ width: OPTIMAL_ITEM_WIDTH, marginBottom: cx(16) }} />;
407
+ }
408
+
409
+ return (
410
+ <MoodItem
411
+ style={{ width: OPTIMAL_ITEM_WIDTH }} // 所有项目都使用最佳宽度
412
+ enable={getItemEnable(item)}
413
+ isMix={!!(params.isMixLight || params.isCeilingLight)}
414
+ deviceTypeOption={params}
415
+ mood={item}
416
+ onPress={() => {
417
+ navigationRoute(item.mainLamp.nodes.length === 1, 'edit', item);
418
+ }}
419
+ onSwitch={async _ => {
420
+ state.loading = true;
421
+ await modDeleteMood('set', item);
422
+ updateFlagMode();
423
+ state.loading = false;
424
+ }}
425
+ />
426
+ );
427
+ }}
428
+ ListHeaderComponent={() => <Spacer height={cx(10)} />}
429
+ ItemSeparatorComponent={() => <Spacer />}
430
+ ListFooterComponent={() => <Spacer />}
431
+ keyExtractor={item => `${item.name}`}
432
+ />
433
+ </View>
400
434
  </Page>
401
435
  <CustomListDialog
402
436
  show={state.showAddMoodPopover}
@@ -422,4 +456,4 @@ const MoodPage = (props: {theme?: ThemeType}) => {
422
456
  };
423
457
 
424
458
 
425
- export default withTheme(MoodPage)
459
+ export default withTheme(MoodPage)
@@ -410,7 +410,7 @@ const TimeScheduleDetailPage = (props: { theme?: ThemeType }) => {
410
410
  />
411
411
  <Spacer />
412
412
  <Text style={{ ...styles.cardContainer, color: props.theme?.global.fontColor, fontSize: cx(14) }}>
413
- {loopText(state.timeSchedule.loops.split(''))}
413
+ {loopText(state.timeSchedule.loops.split(''), state.timeSchedule.time)}
414
414
  </Text>
415
415
  <Spacer height={cx(30)} />
416
416