@ledvance/base 1.3.62 → 1.3.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,400 @@
1
+ import React, { Component } from 'react';
2
+ import _ from 'lodash';
3
+ import { View, ViewStyle } from 'react-native';
4
+ import StorageUtils from './utils/storage';
5
+ import RectPicker, {
6
+ ValidBound,
7
+ ILinear,
8
+ ILinearColors,
9
+ Point,
10
+ defaultProps as baseDefault,
11
+ } from './RectPicker';
12
+ import Slider, { IBrightOption } from './Slider';
13
+ import ColorUtils from './utils/color';
14
+
15
+ export interface IWhite {
16
+ brightness: number;
17
+ temperature: number;
18
+ }
19
+ const defaultProps = {
20
+ ...baseDefault,
21
+ brightOption: {} as IBrightOption,
22
+ value: { brightness: 500, temperature: 500 } as IWhite,
23
+ lossSliderColor: 'rgba(255,255,255,0.4)',
24
+ hideTemp: false,
25
+ hideBright: false,
26
+ /**
27
+ * 排布方向
28
+ * leftBottom 对角线, 0在左下角
29
+ * leftTop 对角线, 0在左上角
30
+ * rightBottom 反向对角线, 0在右下角
31
+ * rightTop 反向对角线, 0在右上角
32
+ * left 从左往右,0在左边
33
+ * right 从右往左,0在右边
34
+ * top 从上往下,0在上边
35
+ * bottom 从下往上,0在下边
36
+ * @version ^0.3.0
37
+ */
38
+ direction: 'left' as
39
+ | 'leftBottom'
40
+ | 'leftTop'
41
+ | 'rightBottom'
42
+ | 'rightTop'
43
+ | 'left'
44
+ | 'right'
45
+ | 'top'
46
+ | 'bottom',
47
+ bgs: [
48
+ { offset: '0%', stopColor: '#FFCA5C', stopOpacity: 1 },
49
+ { offset: '60%', stopColor: '#FFFFFF', stopOpacity: 1 },
50
+ { offset: '100%', stopColor: '#CDECFE', stopOpacity: 1 },
51
+ ] as ILinearColors[],
52
+ onGrant(v: any, option?: { isChangeBright: boolean }) {},
53
+ onMove(v: any, option?: { isChangeBright: boolean }) {},
54
+ onRelease(v: any, option?: { isChangeBright: boolean }) {},
55
+ onPress(v: any, option?: { isChangeBright: boolean }) {},
56
+ };
57
+ interface TempStorageData {
58
+ temperature: number;
59
+ position: Point;
60
+ }
61
+ type DefaultProps = {
62
+ style?: ViewStyle;
63
+ rectStyle?: ViewStyle;
64
+ storageKey?: string;
65
+ } & Readonly<typeof defaultProps>;
66
+
67
+ type WhiteProps = DefaultProps;
68
+
69
+ let storageKeyIndex = 0;
70
+
71
+ export default class WhitePicker extends Component<WhiteProps, IWhite> {
72
+ static defaultProps = defaultProps;
73
+
74
+ constructor(props: WhiteProps) {
75
+ super(props);
76
+ // 是否定义了storageKey
77
+ const {
78
+ storageKey,
79
+ value: { brightness, temperature },
80
+ } = this.props;
81
+ this.state = { brightness, temperature };
82
+ if (!storageKey) {
83
+ this.storageKey = `temperature_key_${storageKeyIndex++}`;
84
+ } else {
85
+ this.storageKey = storageKey;
86
+ }
87
+ }
88
+
89
+ // eslint-disable-next-line react/no-deprecated
90
+ componentWillReceiveProps(nextProps: WhiteProps) {
91
+ const {
92
+ value: { temperature, brightness },
93
+ } = nextProps;
94
+ if (temperature !== this.props.value.temperature) {
95
+ this.setState({ temperature });
96
+ this.thumbPosition = this.autoTemperaturePosition(temperature);
97
+ this.currentTemperature = temperature;
98
+ }
99
+ if (brightness !== this.props.value.brightness && brightness !== this.state.brightness) {
100
+ this.setState({ brightness });
101
+ }
102
+ }
103
+
104
+ shouldComponentUpdate(nextProps: WhiteProps, nextState: IWhite) {
105
+ return !_.isEqual(nextProps, this.props) || !_.isEqual(nextState, this.state);
106
+ }
107
+
108
+ onBrightGrant = () => {
109
+ const { brightness, temperature } = this.state;
110
+ this.firPropsEvent(this.props.onGrant, { brightness, temperature }, { isChangeBright: true });
111
+ };
112
+
113
+ onBrightMove = (brightness: number) => {
114
+ const { temperature } = this.state;
115
+ this.firPropsEvent(this.props.onMove, { temperature, brightness }, { isChangeBright: true });
116
+ };
117
+
118
+ onBrightRelease = (brightness: number) => {
119
+ const { temperature } = this.state;
120
+ this.setState({ temperature, brightness });
121
+ this.firPropsEvent(this.props.onRelease, { temperature, brightness }, { isChangeBright: true });
122
+ };
123
+
124
+ onBrightPress = (brightness: number) => {
125
+ const { temperature } = this.state;
126
+ this.setState({ temperature, brightness });
127
+ this.firPropsEvent(this.props.onPress, { temperature, brightness }, { isChangeBright: true });
128
+ };
129
+
130
+ getBgs() {
131
+ const { direction, bgs } = this.props;
132
+ // left bottom
133
+ let x1 = '0%';
134
+ let y1 = '100%';
135
+ let x2 = '100%';
136
+ let y2 = '0%';
137
+ switch (direction) {
138
+ case 'leftTop':
139
+ x1 = '0%';
140
+ y1 = '0%';
141
+ x2 = '100%';
142
+ y2 = '100%';
143
+ break;
144
+ case 'rightBottom':
145
+ x1 = '100%';
146
+ y1 = '100%';
147
+ x2 = '0%';
148
+ y2 = '0%';
149
+ break;
150
+ case 'rightTop':
151
+ x1 = '100%';
152
+ y1 = '0%';
153
+ x2 = '0%';
154
+ y2 = '100%';
155
+ break;
156
+ case 'left':
157
+ x1 = '0%';
158
+ y1 = '0%';
159
+ x2 = '100%';
160
+ y2 = '0%';
161
+ break;
162
+ case 'right':
163
+ x1 = '100%';
164
+ y1 = '0%';
165
+ x2 = '0%';
166
+ y2 = '0%';
167
+ break;
168
+ case 'top':
169
+ x1 = '0%';
170
+ y1 = '0%';
171
+ x2 = '0%';
172
+ y2 = '100%';
173
+ break;
174
+ case 'bottom':
175
+ x1 = '0%';
176
+ y1 = '100%';
177
+ x2 = '0%';
178
+ y2 = '0%';
179
+ break;
180
+
181
+ default:
182
+ break;
183
+ }
184
+
185
+ return [{ x1, y1, x2, y2, colors: bgs }] as ILinear[];
186
+ }
187
+
188
+ getNormalVector({ width, height, x, y }: ValidBound) {
189
+ switch (this.props.direction) {
190
+ case 'leftTop':
191
+ return { x: width, y: height, originX: x, originY: y };
192
+ case 'rightBottom':
193
+ return { x: -width, y: -height, originX: width + x, originY: height + y };
194
+ case 'rightTop':
195
+ return { x: -width, y: height, originX: width + x, originY: y };
196
+ case 'left':
197
+ return { x: width, y: 0, originX: x, originY: height / 2 + y };
198
+ case 'right':
199
+ return { x: -width, y: 0, originX: width + x, originY: height / 2 + y };
200
+ case 'top':
201
+ return { x: 0, y: height, originX: width / 2 + x, originY: y };
202
+ case 'bottom':
203
+ return { x: 0, y: -height, originX: width / 2 + x, originY: height + y };
204
+ default:
205
+ return { x: width, y: -height, originX: x, originY: height + y };
206
+ }
207
+ }
208
+
209
+ setValue({ temperature, brightness }: IWhite) {
210
+ this.thumbPosition = this.autoTemperaturePosition(temperature);
211
+ this.currentTemperature = temperature;
212
+ this.setState({ temperature, brightness });
213
+ }
214
+
215
+ initData = async (validBound: ValidBound) => {
216
+ let cacheEnabled = true;
217
+ // 尺寸有变化时,不使用缓存
218
+ if (!_.isEqual(validBound, this.pickerBound)) {
219
+ cacheEnabled = false;
220
+ }
221
+ const { temperature } = this.state;
222
+ // 获取当前positon的值
223
+ // const data = (await StorageUtils.getDevItem(this.storageKey)) as TempStorageData;
224
+ // // 是否相同色温,相同使用缓存坐标展示
225
+ // if (data && data.temperature === temperature && cacheEnabled) {
226
+ // this.thumbPosition = data.position;
227
+ // this.currentTemperature = temperature;
228
+ // } else {
229
+ // // 根据色温计算位置
230
+ // this.thumbPosition = this.autoTemperaturePosition(temperature, validBound);
231
+ // this.currentTemperature = temperature;
232
+ // }
233
+ // 根据色温计算位置
234
+ this.thumbPosition = this.autoTemperaturePosition(temperature, validBound);
235
+ this.currentTemperature = temperature;
236
+ this.pickerBound = validBound;
237
+ };
238
+
239
+ autoTemperaturePosition(temperature: number, validBound?: any) {
240
+ let position;
241
+ if (this.pickerRef) {
242
+ position = this.pickerRef.valueToCoor({ temperature });
243
+ } else {
244
+ position = this.valueToCoor(
245
+ { temperature, brightness: this.state.brightness },
246
+ null,
247
+ validBound
248
+ );
249
+ }
250
+ // StorageUtils.setDevItem(this.storageKey, { temperature, position });
251
+ return position;
252
+ }
253
+
254
+ coorToValue = ({ x, y }: Point, bound: ValidBound) => {
255
+ const { brightness } = this.state;
256
+ // 获取基准向量
257
+ const normalVector = this.getNormalVector(bound);
258
+ const vector1 = { x: x - normalVector.originX, y: y - normalVector.originY };
259
+ // 对角线的长度
260
+ const total = Math.sqrt(normalVector.x ** 2 + normalVector.y ** 2);
261
+ const diff = (vector1.x * normalVector.x + vector1.y * normalVector.y) / total;
262
+ const temperature = Math.round((diff / total) * 1000);
263
+ return { temperature, brightness };
264
+ };
265
+
266
+ handleTemperaturePosition(temperature: number, bound: ValidBound) {
267
+ // 获取基准向量
268
+ const normalVector = this.getNormalVector(bound);
269
+ const total = Math.sqrt(normalVector.x ** 2 + normalVector.y ** 2);
270
+ const normal = { x: normalVector.x / total, y: normalVector.y / total };
271
+ const length = total * (temperature / 1000);
272
+ const position = {
273
+ x: normal.x * length + normalVector.originX,
274
+ y: normal.y * length + normalVector.originY,
275
+ };
276
+ // StorageUtils.setDevItem(this.storageKey, { temperature, position });
277
+ return position;
278
+ }
279
+
280
+ valueToCoor = ({ temperature }: IWhite, origin: Point, validBound: ValidBound): Point => {
281
+ // origin 不存在时,不在滑动时候
282
+ if (!origin) {
283
+ let cacheEnabled = true;
284
+ if (!_.isEqual(validBound, this.pickerBound)) {
285
+ cacheEnabled = false;
286
+ }
287
+ if (this.currentTemperature === temperature && cacheEnabled) {
288
+ if (
289
+ this.thumbPosition &&
290
+ typeof this.thumbPosition.x === 'number' &&
291
+ this.thumbPosition.x >= 0
292
+ ) {
293
+ return this.thumbPosition;
294
+ }
295
+ }
296
+ return this.handleTemperaturePosition(temperature, validBound);
297
+ }
298
+ // StorageUtils.setDevItem(this.storageKey, {
299
+ // temperature,
300
+ // position: origin,
301
+ // });
302
+ this.currentTemperature = temperature;
303
+ this.thumbPosition = origin;
304
+ return origin;
305
+ };
306
+
307
+ valueToColor = (data: IWhite): string => {
308
+ const { temperature, brightness } = data;
309
+ return ColorUtils.brightKelvin2rgba(brightness, temperature);
310
+ };
311
+
312
+ firPropsEvent(cb: (params?: any) => void, ...args: any[]) {
313
+ typeof cb === 'function' && cb(...args);
314
+ }
315
+
316
+ private thumbPosition: Point;
317
+ private currentTemperature: number;
318
+ private pickerRef: RectPicker;
319
+ private storageKey: string;
320
+ private pickerBound: ValidBound;
321
+
322
+ handlePickerGrant = () => {
323
+ const { temperature, brightness } = this.state;
324
+ this.firPropsEvent(this.props.onGrant, { temperature, brightness });
325
+ };
326
+
327
+ handlePickerMove = (white: IWhite) => {
328
+ this.firPropsEvent(this.props.onMove, white);
329
+ };
330
+
331
+ handlePickerRelease = (white: IWhite) => {
332
+ this.setState({ ...white });
333
+ this.firPropsEvent(this.props.onRelease, white);
334
+ };
335
+
336
+ handlePickerPress = (white: IWhite) => {
337
+ this.setState({ ...white });
338
+ this.firPropsEvent(this.props.onPress, white);
339
+ };
340
+
341
+ render() {
342
+ const {
343
+ style,
344
+ rectStyle,
345
+ brightOption,
346
+ lossShow,
347
+ lossSliderColor,
348
+ clickEnabled,
349
+ hideTemp,
350
+ hideBright,
351
+ opacityAnimationValue,
352
+ opacityAnimationDuration,
353
+ ...pickerProps
354
+ } = this.props;
355
+ const { temperature, brightness } = this.state;
356
+ const sliderProps: any = {};
357
+ if (lossShow) {
358
+ sliderProps.activeColor = lossSliderColor;
359
+ }
360
+ return (
361
+ <View style={[{ flex: 1 }, style]}>
362
+ {!hideTemp && (<RectPicker
363
+ ref={(ref: RectPicker) => {
364
+ this.pickerRef = ref;
365
+ }}
366
+ coorToValue={this.coorToValue}
367
+ valueToColor={this.valueToColor}
368
+ valueToCoor={this.valueToCoor}
369
+ value={{ temperature, brightness }}
370
+ lossShow={lossShow}
371
+ clickEnabled={clickEnabled}
372
+ opacityAnimationValue={opacityAnimationValue}
373
+ opacityAnimationDuration={opacityAnimationDuration}
374
+ {...pickerProps}
375
+ bgs={this.getBgs()}
376
+ style={rectStyle}
377
+ onGrant={this.handlePickerGrant}
378
+ onMove={this.handlePickerMove}
379
+ onRelease={this.handlePickerRelease}
380
+ onPress={this.handlePickerPress}
381
+ initData={this.initData}
382
+ />)}
383
+ {!hideBright && (
384
+ <Slider
385
+ opacityAnimationValue={opacityAnimationValue}
386
+ opacityAnimationDuration={opacityAnimationDuration}
387
+ {...brightOption}
388
+ {...sliderProps}
389
+ clickEnabled={clickEnabled}
390
+ value={brightness}
391
+ onGrant={this.onBrightGrant}
392
+ onMove={this.onBrightMove}
393
+ onRelease={this.onBrightRelease}
394
+ onPress={this.onBrightPress}
395
+ />
396
+ )}
397
+ </View>
398
+ );
399
+ }
400
+ }
@@ -0,0 +1,5 @@
1
+ import ColourPicker from './ColourPicker';
2
+ import WhitePicker from './WhitePicker';
3
+ import Slider from './Slider';
4
+
5
+ export default { ColourPicker, WhitePicker, BrightnessSlider: Slider };
@@ -0,0 +1,3 @@
1
+ export default {
2
+ thumbMask: require('./thumb-mask.png'),
3
+ };
@@ -0,0 +1,73 @@
1
+ /* eslint-disable func-names */
2
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
3
+ import { Utils } from 'tuya-panel-kit';
4
+ import ColorObj from 'color';
5
+
6
+ const { color: ColorUtils } = Utils.ColorUtils;
7
+
8
+ ColorUtils.temp2rgb = function (
9
+ kelvin: number,
10
+ { temperatureMin = 4000, temperatureMax = 8000 } = {}
11
+ ) {
12
+ let newKelvin = kelvin;
13
+ newKelvin /= 10; // 0 - 1000 范围
14
+ const temp = temperatureMin + ((temperatureMax - temperatureMin) * newKelvin) / 100;
15
+ const hsv = this.rgb2hsv(...this.kelvin2rgb(temp));
16
+ return this.hsv2RgbString(...hsv);
17
+ };
18
+
19
+ ColorUtils.brightKelvin2rgb = function (
20
+ bright = 1000,
21
+ kelvin = 1000,
22
+ { temperatureMin = 4000, temperatureMax = 8000 } = {}
23
+ ) {
24
+ let newKelvin = kelvin;
25
+ let newBright = bright;
26
+ newBright /= 10;
27
+ newKelvin /= 10;
28
+ const temp = temperatureMin + ((temperatureMax - temperatureMin) * newKelvin) / 100;
29
+ const hsv = this.rgb2hsv(...this.kelvin2rgb(temp));
30
+ const brightV = newBright;
31
+ hsv[2] = brightV;
32
+ return this.hsv2RgbString(...hsv);
33
+ };
34
+
35
+ ColorUtils.bright2Opacity = (
36
+ brightness: number,
37
+ option: { min: number; max: number } = { min: 0.2, max: 1 }
38
+ ) => {
39
+ const { min = 0.2, max = 1 } = option;
40
+ return Math.round((min + ((brightness - 10) / (1000 - 10)) * (max - min)) * 100) / 100;
41
+ };
42
+
43
+ /**
44
+ * 格式化hsv
45
+ * 亮度将转化为透明度变化
46
+ */
47
+ ColorUtils.hsv2rgba = function (hue: number, saturation: number, bright: number) {
48
+ try {
49
+ let color: string = ColorUtils.hsb2hex(hue, saturation / 10, 100);
50
+ // @ts-ignore
51
+ color = new ColorObj(color as string).alpha(this.bright2Opacity(bright)).rgbString();
52
+ return color;
53
+ } catch (error) {
54
+ // eslint-disable-next-line no-console
55
+ console.warn(error);
56
+ return 'transparent';
57
+ }
58
+ };
59
+
60
+ ColorUtils.brightKelvin2rgba = function (bright: number, kelvin: number) {
61
+ try {
62
+ let color = ColorUtils.brightKelvin2rgb(1000, kelvin || 0);
63
+ // @ts-ignore
64
+ color = new ColorObj(color).alpha(this.bright2Opacity(bright)).rgbString();
65
+ return color;
66
+ } catch (error) {
67
+ // eslint-disable-next-line no-console
68
+ console.warn(error);
69
+ return 'transparent';
70
+ }
71
+ };
72
+
73
+ export default ColorUtils;
@@ -0,0 +1,97 @@
1
+ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2
+ import { AsyncStorage } from 'react-native';
3
+ import { TYSdk } from 'tuya-panel-kit';
4
+
5
+ const getDevKey = (name: string) => {
6
+ const { devId } = TYSdk.devInfo;
7
+ return `${devId}_${name}`;
8
+ };
9
+
10
+ const getPidKey = (name: string) => {
11
+ const { productId } = TYSdk.devInfo;
12
+ return `${productId}_${name}`;
13
+ };
14
+
15
+ const getUiKey = (name: string) => {
16
+ const { uiId } = TYSdk.devInfo;
17
+ return `${uiId}_${name}`;
18
+ };
19
+
20
+ export default {
21
+ async setItem(key: string, value: any) {
22
+ const data = { value, type: typeof value };
23
+ const jsonValue = JSON.stringify(data);
24
+ return new Promise((resolve, reject) => {
25
+ AsyncStorage.setItem(key, jsonValue, err => {
26
+ if (err) {
27
+ reject(err);
28
+ return;
29
+ }
30
+ resolve('');
31
+ });
32
+ });
33
+ },
34
+ async setDevItem(name: string, value: any) {
35
+ const key = getDevKey(name);
36
+ return this.setItem(key, value);
37
+ },
38
+ async setPidItem(name: string, value: any) {
39
+ const key = getPidKey(name);
40
+ return this.setItem(key, value);
41
+ },
42
+ async setUiItem(name: string, value: any) {
43
+ const key = getUiKey(name);
44
+ return this.setItem(key, value);
45
+ },
46
+ async getItem(key: string) {
47
+ return new Promise((resolve, reject) => {
48
+ AsyncStorage.getItem(key, (err, data) => {
49
+ if (err) {
50
+ reject(err);
51
+ return;
52
+ }
53
+ if (data) {
54
+ resolve(JSON.parse(data).value);
55
+ }
56
+ resolve(null);
57
+ });
58
+ });
59
+ },
60
+ async getDevItem(name: string) {
61
+ const key = getDevKey(name);
62
+ return this.getItem(key);
63
+ },
64
+ async getPidItem(name: string) {
65
+ const key = getPidKey(name);
66
+ return this.getItem(key);
67
+ },
68
+ async getUiItem(name: string) {
69
+ const key = getUiKey(name);
70
+ return this.getItem(key);
71
+ },
72
+ async removeItem(key: string) {
73
+ return new Promise((resolve, reject) => {
74
+ AsyncStorage.removeItem(key, err => {
75
+ if (err) {
76
+ reject(err);
77
+ return;
78
+ }
79
+ resolve('');
80
+ });
81
+ });
82
+ },
83
+
84
+ async removeDevItem(name: string) {
85
+ const key = getDevKey(name);
86
+ return this.removeItem(key);
87
+ },
88
+
89
+ async removePidItem(name: string) {
90
+ const key = getDevKey(name);
91
+ return this.removeItem(key);
92
+ },
93
+ async removeUiItem(name: string) {
94
+ const key = getUiKey(name);
95
+ return this.removeItem(key);
96
+ },
97
+ };
@@ -8,10 +8,6 @@ const { withTheme } = Utils.ThemeUtils
8
8
 
9
9
  const repeatPeriod = [
10
10
  {
11
- index: 1,
12
- title: I18n.getLang('timeschedule_add_schedule_weekday7_text'),
13
- enabled: false,
14
- }, {
15
11
  index: 2,
16
12
  title: I18n.getLang('timeschedule_add_schedule_weekday1_text'),
17
13
  enabled: false,
@@ -35,14 +31,18 @@ const repeatPeriod = [
35
31
  index: 7,
36
32
  title: I18n.getLang('timeschedule_add_schedule_weekday6_text'),
37
33
  enabled: false,
34
+ }, {
35
+ index: 1,
36
+ title: I18n.getLang('timeschedule_add_schedule_weekday7_text'),
37
+ enabled: false,
38
38
  },
39
39
  ]
40
40
 
41
- export const setDataSource = (loop) => {
42
- return repeatPeriod.map((item, index) => {
41
+ export const setDataSource = (loop: number[] | string[] | string) => {
42
+ return repeatPeriod.map(item => {
43
43
  return {
44
44
  ...item,
45
- enabled: loop[index] === 1,
45
+ enabled: [1, '1'].includes(loop[item.index - 1]),
46
46
  }
47
47
  })
48
48
  }
@@ -10,7 +10,7 @@ import {
10
10
  NativeProps,
11
11
  setGroupDevices,
12
12
  setGroupNativeProps,
13
- setNativeProps,
13
+ setNativeProps, setNewPalette,
14
14
  setSystemTimeFormat,
15
15
  setTimeZone,
16
16
  UAGroupInfo,
@@ -26,6 +26,7 @@ interface Props {
26
26
  ldvDevInfo: LdvDevInfo
27
27
  uaGroupInfo: UAGroupInfoProps
28
28
  colorScheme?: string
29
+ newPalette?: boolean
29
30
  }
30
31
 
31
32
  interface LdvDevInfo extends DeviceInfo {
@@ -130,6 +131,8 @@ const composeLayout = (component: React.ComponentType) => {
130
131
  getTimeZone().then(timeZone => {
131
132
  dispatch(setTimeZone(timeZone))
132
133
  })
134
+
135
+ dispatch(setNewPalette(!!props.newPalette))
133
136
  }
134
137
 
135
138
  initReduxDeviceNativeProps(ldvDevInfo: LdvDevInfo) {