@ledvance/base 1.1.16 → 1.1.17
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 +1 -1
- package/src/components/Cell.tsx +60 -31
- package/src/components/ColorExtractor.tsx +375 -0
- package/src/components/CustomListDialog.tsx +59 -0
- package/src/components/Page.tsx +54 -20
- package/src/components/TextField.tsx +5 -2
- package/src/components/TextFieldStyleButton.tsx +65 -0
- package/src/components/ldvItemView.tsx +44 -0
- package/src/utils/index.ts +8 -0
package/package.json
CHANGED
package/src/components/Cell.tsx
CHANGED
|
@@ -1,41 +1,70 @@
|
|
|
1
|
-
import {IconFont, Utils} from 'tuya-panel-kit'
|
|
2
|
-
import {StyleProp, Text, TouchableOpacity, View, ViewStyle} from 'react-native'
|
|
1
|
+
import { IconFont, Utils } from 'tuya-panel-kit'
|
|
2
|
+
import { StyleProp, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
|
|
5
5
|
const cx = Utils.RatioUtils.convertX
|
|
6
6
|
|
|
7
7
|
interface CellProps {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
title: string,
|
|
9
|
+
value: string,
|
|
10
|
+
onPress: () => void,
|
|
11
|
+
style?: StyleProp<ViewStyle>
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export default function Cell(props: CellProps) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
15
|
+
return (
|
|
16
|
+
<TouchableOpacity
|
|
17
|
+
style={[{
|
|
18
|
+
height: cx(50),
|
|
19
|
+
paddingHorizontal: cx(24),
|
|
20
|
+
justifyContent: 'center',
|
|
21
|
+
}, props.style]}
|
|
22
|
+
onPress={props.onPress}>
|
|
23
|
+
<CellContent title={props.title} value={props.value} />
|
|
24
|
+
</TouchableOpacity>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface CellContentProps {
|
|
29
|
+
title: string
|
|
30
|
+
value: string
|
|
31
|
+
style?: StyleProp<ViewStyle>
|
|
32
|
+
titleStyle?: StyleProp<TextStyle>
|
|
33
|
+
valueStyle?: StyleProp<TextStyle>
|
|
34
|
+
iconStyle?: { color?: any, size?: number }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function CellContent(props: CellContentProps) {
|
|
38
|
+
return (
|
|
39
|
+
<View
|
|
40
|
+
style={[
|
|
41
|
+
{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
|
|
42
|
+
props.style,
|
|
43
|
+
]}>
|
|
44
|
+
<Text
|
|
45
|
+
style={[
|
|
46
|
+
{
|
|
47
|
+
fontSize: cx(14),
|
|
48
|
+
color: '#444',
|
|
49
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
50
|
+
},
|
|
51
|
+
props.titleStyle,
|
|
52
|
+
]}>{props.title}</Text>
|
|
53
|
+
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
54
|
+
<Text style={[
|
|
55
|
+
{
|
|
56
|
+
fontSize: cx(14),
|
|
57
|
+
color: '#444',
|
|
58
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
59
|
+
},
|
|
60
|
+
props.valueStyle,
|
|
61
|
+
]}>{props.value}</Text>
|
|
62
|
+
<View style={{ width: cx(4) }} />
|
|
63
|
+
<IconFont
|
|
64
|
+
name="arrow"
|
|
65
|
+
color={props.iconStyle?.color || '#444'}
|
|
66
|
+
size={props.iconStyle?.size || cx(11)} />
|
|
67
|
+
</View>
|
|
37
68
|
</View>
|
|
38
|
-
|
|
39
|
-
</TouchableOpacity>
|
|
40
|
-
)
|
|
69
|
+
)
|
|
41
70
|
}
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import React, { Component } from 'react'
|
|
2
|
+
import { Dimensions, Image, PanResponder, View, StyleSheet, PanResponderInstance } from 'react-native'
|
|
3
|
+
import { TYSdk } from 'tuya-panel-kit'
|
|
4
|
+
|
|
5
|
+
import ColorUtils from '../utils/ColorUtils'
|
|
6
|
+
import res from '@res'
|
|
7
|
+
|
|
8
|
+
export default class ColorExtractor extends Component<any> {
|
|
9
|
+
state: any
|
|
10
|
+
_panResponder: PanResponderInstance
|
|
11
|
+
onColorChange: any
|
|
12
|
+
lastX: any
|
|
13
|
+
lastY: any
|
|
14
|
+
self: any
|
|
15
|
+
startTouchXY: any
|
|
16
|
+
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props)
|
|
19
|
+
let {
|
|
20
|
+
thumbSizeW,
|
|
21
|
+
radius,
|
|
22
|
+
color,
|
|
23
|
+
onColorChange,
|
|
24
|
+
colorTemperatureInterval,
|
|
25
|
+
miniColorTemperature,
|
|
26
|
+
} = !!props && props
|
|
27
|
+
this.onColorChange = onColorChange
|
|
28
|
+
radius = radius || 130
|
|
29
|
+
thumbSizeW = thumbSizeW || 30
|
|
30
|
+
const currentColor = color
|
|
31
|
+
this.state = {
|
|
32
|
+
thumbSizeW,
|
|
33
|
+
radius,
|
|
34
|
+
offset: { x: radius - thumbSizeW / 2, y: radius - thumbSizeW / 2 },
|
|
35
|
+
currentColor,
|
|
36
|
+
ratio: 0,
|
|
37
|
+
miniColorTemperature: !!miniColorTemperature ? miniColorTemperature : 2700,
|
|
38
|
+
colorTemperatureInterval: colorTemperatureInterval,
|
|
39
|
+
}
|
|
40
|
+
this.lastX = radius - thumbSizeW / 2
|
|
41
|
+
this.lastY = radius - thumbSizeW / 2
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onLayout(_: any) {
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
componentDidMount() {
|
|
49
|
+
this.updateUIWithColor(this.state.currentColor, true)
|
|
50
|
+
// 图标的手势
|
|
51
|
+
this._panResponder = PanResponder.create({
|
|
52
|
+
onMoveShouldSetPanResponder: () => {
|
|
53
|
+
return true
|
|
54
|
+
},
|
|
55
|
+
onPanResponderMove: (evt, gestureState) => {
|
|
56
|
+
this.handlerData(evt, gestureState, true)
|
|
57
|
+
},
|
|
58
|
+
onPanResponderRelease: (evt, gestureState) => {
|
|
59
|
+
this.handlerData(evt, gestureState, false)
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
if (this.props.showColorTemperature) {
|
|
64
|
+
TYSdk.event.off('onColorTempChange')
|
|
65
|
+
TYSdk.event.on('onColorTempChange', (color) => {
|
|
66
|
+
this.updateUIWithColor(color, false)
|
|
67
|
+
})
|
|
68
|
+
} else {
|
|
69
|
+
TYSdk.event.off('onColorChange')
|
|
70
|
+
TYSdk.event.on('onColorChange', (color) => {
|
|
71
|
+
this.updateUIWithColor(color, false)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
componentWillUnmount() {
|
|
77
|
+
TYSdk.event.off('onColorChange')
|
|
78
|
+
TYSdk.event.off('onColorTempChange')
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
handleTapData(evt) {
|
|
82
|
+
if (!!this.props.disabled) {
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
let tapX = evt.nativeEvent.locationX
|
|
86
|
+
let tapY = evt.nativeEvent.locationY
|
|
87
|
+
let result = this.getPointValues(tapX, tapY)
|
|
88
|
+
let maxX = result.maxX
|
|
89
|
+
let maxY = result.maxY
|
|
90
|
+
this.setState({
|
|
91
|
+
offset: {
|
|
92
|
+
x: maxX,
|
|
93
|
+
y: maxY,
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
this.lastX = maxX
|
|
97
|
+
this.lastY = maxY
|
|
98
|
+
this.updateColor(evt.nativeEvent.locationX, evt.nativeEvent.locationY, false)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
handlerData(_evt, ges, moving) {
|
|
102
|
+
if (!!this.props.disabled) {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//此时视图的坐标
|
|
107
|
+
let locationX = this.lastX + ges.dx + this.state.thumbSizeW / 2
|
|
108
|
+
let locationY = this.lastY + ges.dy + this.state.thumbSizeW / 2
|
|
109
|
+
// 获取在父元素的实际坐标点值
|
|
110
|
+
let result = this.getPointValues(locationX, locationY)
|
|
111
|
+
let maxX = result.maxX
|
|
112
|
+
let maxY = result.maxY
|
|
113
|
+
// 获取此点的颜色值
|
|
114
|
+
this.updateColor(locationX, locationY, moving)
|
|
115
|
+
|
|
116
|
+
this.setState({
|
|
117
|
+
offset: {
|
|
118
|
+
x: maxX,
|
|
119
|
+
y: maxY,
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
if (!(!!moving)) {
|
|
124
|
+
// 记录滑动前 图表的位置
|
|
125
|
+
this.lastX = this.state.offset.x
|
|
126
|
+
this.lastY = this.state.offset.y
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 获取实际坐标的 角度 坐标值 步长
|
|
131
|
+
getPointValues(locationX, locationY) {
|
|
132
|
+
//半径
|
|
133
|
+
let radius = this.state.radius
|
|
134
|
+
// 求斜边的长度
|
|
135
|
+
let offsetX = Math.abs(radius - locationX)
|
|
136
|
+
let offsetY = Math.abs(radius - locationY)
|
|
137
|
+
let length = Math.sqrt(offsetX * offsetX + offsetY * offsetY)// 斜边长度
|
|
138
|
+
//求角度
|
|
139
|
+
// let angle = Math.atan2(offsetY, offsetX) * (180 / Math.PI)
|
|
140
|
+
let angle = this.getPointAngle(radius - locationX, radius - locationY)
|
|
141
|
+
// console.log('是否出界'+[locationX,locationY,angle])
|
|
142
|
+
// 最终的坐标
|
|
143
|
+
let maxX = locationX - this.state.thumbSizeW / 2//this.lastX + ges.dx
|
|
144
|
+
let maxY = locationY - this.state.thumbSizeW / 2//this.lastY + ges.dy
|
|
145
|
+
if (length > this.state.radius) {
|
|
146
|
+
// 超出边界
|
|
147
|
+
let maxOffsetX = this.state.radius * (locationX - radius) / length
|
|
148
|
+
let maxOffsetY = this.state.radius * (radius - locationY) / length
|
|
149
|
+
maxX = radius + maxOffsetX - this.state.thumbSizeW / 2
|
|
150
|
+
maxY = radius - maxOffsetY - this.state.thumbSizeW / 2
|
|
151
|
+
length = this.state.radius
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
angle: angle,
|
|
155
|
+
maxX: maxX,
|
|
156
|
+
maxY: maxY,
|
|
157
|
+
length: length,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getPointAngle(x, y) {
|
|
162
|
+
// 此时的角度是从左边为 0°开始 顺时针 到右边为 180° 逆时针到最右边为 -180°
|
|
163
|
+
let angle = Math.atan2(y, x) * (180 / Math.PI)
|
|
164
|
+
// 此转换为左边 0° 顺时针转一圈为 360°
|
|
165
|
+
angle = 180 - angle
|
|
166
|
+
//console.log('获取角度' + angle)
|
|
167
|
+
return angle
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 根据颜色值更新图标的位置 color : #ffffff
|
|
171
|
+
updateUIWithColor(color, isFirst) {
|
|
172
|
+
const { radius } = this.state
|
|
173
|
+
// 根据初始的颜色值回去图标的坐标
|
|
174
|
+
const hsv = ColorUtils.hex2Hsv(color)
|
|
175
|
+
//console.log('初始值颜色' + [hsv.h, hsv.s, hsv.v])
|
|
176
|
+
|
|
177
|
+
//角度
|
|
178
|
+
let angle = 180 - hsv.h
|
|
179
|
+
// 在色盘中的步长
|
|
180
|
+
let length = (radius / 100) * hsv.s
|
|
181
|
+
//
|
|
182
|
+
const offset = this.hypotenuse(length, angle)
|
|
183
|
+
const offsetX = radius - offset.x - this.state.thumbSizeW / 2
|
|
184
|
+
const offsetY = radius - offset.y - this.state.thumbSizeW / 2
|
|
185
|
+
|
|
186
|
+
this.lastX = offsetX
|
|
187
|
+
this.lastY = offsetY
|
|
188
|
+
this.setState({
|
|
189
|
+
currentColor: color,
|
|
190
|
+
offset: {
|
|
191
|
+
x: offsetX,
|
|
192
|
+
y: offsetY,
|
|
193
|
+
},
|
|
194
|
+
ratio: hsv.s / 100,
|
|
195
|
+
}, () => {
|
|
196
|
+
this.updateColor(offsetX + this.state.thumbSizeW / 2, offsetY + this.state.thumbSizeW / 2, false, isFirst)
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
//已知角度和斜边,求直角边
|
|
201
|
+
hypotenuse(long, angle) {
|
|
202
|
+
//获得弧度
|
|
203
|
+
const radian = 2 * Math.PI / 360 * angle
|
|
204
|
+
return {
|
|
205
|
+
x: Math.cos(radian) * long,
|
|
206
|
+
y: Math.sin(radian) * long,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 根据坐标的位置 获取颜色值
|
|
211
|
+
updateColor(x, y, moving, isFirst?: boolean) {
|
|
212
|
+
const { angle, length } = this.getPointValues(x, y)
|
|
213
|
+
//console.log('根据坐标的位置 获取颜色值', angle, maxX, maxY, length);
|
|
214
|
+
let radius = length / this.state.radius
|
|
215
|
+
const rad = radius > 1 ? 1 : radius
|
|
216
|
+
const hsv = { h: angle, s: 100 * rad, v: 100 }
|
|
217
|
+
const currentColor = ColorUtils.hsv2Hex(hsv)
|
|
218
|
+
this.setState({ currentColor, ratio: rad })
|
|
219
|
+
//console.log('获取当前的颜色' + [currentColor, angle])
|
|
220
|
+
//滑动结束 发送当前颜色值
|
|
221
|
+
if (moving === false) {
|
|
222
|
+
this.onColorChange && this.onColorChange(hsv, isFirst)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
render() {
|
|
227
|
+
const { radius, offset, ratio, miniColorTemperature, colorTemperatureInterval } = this.state
|
|
228
|
+
const { x, y } = offset
|
|
229
|
+
const { showColorTemperature } = this.props
|
|
230
|
+
return (
|
|
231
|
+
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
|
232
|
+
<View
|
|
233
|
+
ref={node => {
|
|
234
|
+
this.self = node
|
|
235
|
+
}}
|
|
236
|
+
onLayout={nativeEvent => this.onLayout(nativeEvent)}
|
|
237
|
+
style={[{
|
|
238
|
+
height: radius * 2,
|
|
239
|
+
width: radius * 2,
|
|
240
|
+
}, this.props.style]}>
|
|
241
|
+
|
|
242
|
+
<View
|
|
243
|
+
style={[styles.img, {
|
|
244
|
+
height: radius * 2,
|
|
245
|
+
width: radius * 2,
|
|
246
|
+
}]}>
|
|
247
|
+
<Image
|
|
248
|
+
style={{
|
|
249
|
+
height: radius * 2,
|
|
250
|
+
width: radius * 2,
|
|
251
|
+
alignItems: 'center',
|
|
252
|
+
position: 'absolute',
|
|
253
|
+
}}
|
|
254
|
+
source={{ uri: !!showColorTemperature ? res.color_temperature_wheel : res.color_wheel }}
|
|
255
|
+
// @ts-ignore
|
|
256
|
+
onStartShouldSetResponder={(evt) => {
|
|
257
|
+
this.startTouchXY = evt.nativeEvent
|
|
258
|
+
return true
|
|
259
|
+
}}
|
|
260
|
+
onResponderMove={() => {
|
|
261
|
+
return false
|
|
262
|
+
}}
|
|
263
|
+
onResponderRelease={(evt) => {
|
|
264
|
+
const { locationX, locationY, timestamp } = !!this.startTouchXY && this.startTouchXY
|
|
265
|
+
const endLocationX = evt.nativeEvent.locationX
|
|
266
|
+
const endLocationY = evt.nativeEvent.locationY
|
|
267
|
+
const endTimestamp = evt.nativeEvent.timestamp
|
|
268
|
+
|
|
269
|
+
if (Math.abs(locationX - endLocationX) <= 10 && Math.abs(locationY - endLocationY) <= 10 && endTimestamp - timestamp < 500) {
|
|
270
|
+
this.handleTapData(evt)
|
|
271
|
+
}
|
|
272
|
+
}} />
|
|
273
|
+
{<View
|
|
274
|
+
{...(this._panResponder || {}).panHandlers}
|
|
275
|
+
style={{
|
|
276
|
+
marginTop: y,
|
|
277
|
+
marginLeft: x,
|
|
278
|
+
width: this.state.thumbSizeW,
|
|
279
|
+
height: this.state.thumbSizeW,
|
|
280
|
+
position: 'absolute',
|
|
281
|
+
backgroundColor: '#ffffff',
|
|
282
|
+
elevation: !!this.props.disabled ? 0 : 3,
|
|
283
|
+
shadowOpacity: 0.15,
|
|
284
|
+
shadowRadius: 5,
|
|
285
|
+
shadowOffset: { width: 0, height: 3.5 },
|
|
286
|
+
borderRadius: this.state.thumbSizeW / 2,
|
|
287
|
+
}}>
|
|
288
|
+
{!(!!showColorTemperature) && <View
|
|
289
|
+
style={{
|
|
290
|
+
marginTop: 3,
|
|
291
|
+
marginLeft: 3,
|
|
292
|
+
width: this.state.thumbSizeW - 6,
|
|
293
|
+
height: this.state.thumbSizeW - 6,
|
|
294
|
+
position: 'absolute',
|
|
295
|
+
backgroundColor: this.state.currentColor,
|
|
296
|
+
borderRadius: (this.state.thumbSizeW - 6) / 2,
|
|
297
|
+
}}>
|
|
298
|
+
</View>}
|
|
299
|
+
|
|
300
|
+
{!!showColorTemperature && <View
|
|
301
|
+
style={{
|
|
302
|
+
marginTop: 3,
|
|
303
|
+
marginLeft: 3,
|
|
304
|
+
width: this.state.thumbSizeW - 6,
|
|
305
|
+
height: this.state.thumbSizeW - 6,
|
|
306
|
+
position: 'absolute',
|
|
307
|
+
backgroundColor: colorTemperatureToColor(miniColorTemperature + ratio * colorTemperatureInterval),
|
|
308
|
+
borderRadius: (this.state.thumbSizeW - 6) / 2,
|
|
309
|
+
}}>
|
|
310
|
+
</View>}
|
|
311
|
+
</View>}
|
|
312
|
+
</View>
|
|
313
|
+
</View>
|
|
314
|
+
</View>
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const styles = StyleSheet.create({
|
|
319
|
+
colorWheelStyle: {
|
|
320
|
+
width: Dimensions.get('window').width,
|
|
321
|
+
},
|
|
322
|
+
coverResponder: {
|
|
323
|
+
width: 260,
|
|
324
|
+
height: 260,
|
|
325
|
+
},
|
|
326
|
+
img: {},
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
export const colorTemperature = {
|
|
330
|
+
2700: '#FFDC94',
|
|
331
|
+
2800: '#FFDD96',
|
|
332
|
+
2900: '#FFDF9A',
|
|
333
|
+
3000: '#FFE19D',
|
|
334
|
+
3100: '#FFE29F',
|
|
335
|
+
3200: '#FFE4A3',
|
|
336
|
+
3300: '#FFE5A6',
|
|
337
|
+
3400: '#FFE7A9',
|
|
338
|
+
3500: '#FFE8AC',
|
|
339
|
+
3600: '#FFEAAF',
|
|
340
|
+
3700: '#FFECB3',
|
|
341
|
+
3800: '#FFEDB6',
|
|
342
|
+
3900: '#FFEFB9',
|
|
343
|
+
4000: '#FFF0BB',
|
|
344
|
+
4100: '#FFF2BF',
|
|
345
|
+
4200: '#FFF3C2',
|
|
346
|
+
4300: '#FFF5C5',
|
|
347
|
+
4400: '#FFF6C8',
|
|
348
|
+
4500: '#FFF8CB',
|
|
349
|
+
4600: '#FFFACF',
|
|
350
|
+
4700: '#FFFBD2',
|
|
351
|
+
4800: '#FFFCD4',
|
|
352
|
+
4900: '#FFFDD7',
|
|
353
|
+
5000: '#FEFEDA',
|
|
354
|
+
5100: '#FEFEDD',
|
|
355
|
+
5200: '#FEFFE0',
|
|
356
|
+
5300: '#FAFEE1',
|
|
357
|
+
5400: '#F7FEE3',
|
|
358
|
+
5500: '#F3FCE3',
|
|
359
|
+
5600: '#F0FCE4',
|
|
360
|
+
5700: '#EDFBE6',
|
|
361
|
+
5800: '#E9FAE6',
|
|
362
|
+
5900: '#E5F9E8',
|
|
363
|
+
6000: '#E2F9E9',
|
|
364
|
+
6100: '#DFF8EA',
|
|
365
|
+
6200: '#DCF7EC',
|
|
366
|
+
6300: '#D7F6EC',
|
|
367
|
+
6400: '#D4F5ED',
|
|
368
|
+
6500: '#D1F5EF',
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export const colorTemperatureToColor = (temperature) => {
|
|
372
|
+
const colorTemperatureValue = parseInt(`${temperature / 100}`, 10) * 100
|
|
373
|
+
//console.log("colorTemperatureValue :::::: ",colorTemperatureValue,colorTemperature[`${colorTemperatureValue}`])
|
|
374
|
+
return colorTemperature[colorTemperatureValue]
|
|
375
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Card from './Card'
|
|
2
|
+
import { FlatList, StyleProp, StyleSheet, View, ViewProps, ViewStyle } from 'react-native'
|
|
3
|
+
import TextButton from './TextButton'
|
|
4
|
+
import Dialog from './Dialog'
|
|
5
|
+
import React from 'react'
|
|
6
|
+
import { Utils } from 'tuya-panel-kit'
|
|
7
|
+
|
|
8
|
+
const cx = Utils.RatioUtils.convertX
|
|
9
|
+
|
|
10
|
+
interface ListData {
|
|
11
|
+
text: string
|
|
12
|
+
value?: any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CustomListDialogProps extends ViewProps {
|
|
16
|
+
itemStyle?: StyleProp<ViewStyle>
|
|
17
|
+
show: boolean
|
|
18
|
+
onDismiss: () => void
|
|
19
|
+
data: ListData[]
|
|
20
|
+
onItemPress: (item: any | undefined, index: number) => void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const CustomListDialog = (props: CustomListDialogProps) => {
|
|
24
|
+
return <Dialog
|
|
25
|
+
show={props.show}
|
|
26
|
+
hideMask={true}
|
|
27
|
+
onRequestClose={props.onDismiss}>
|
|
28
|
+
<Card style={props.style} shadowHeight={cx(7)}>
|
|
29
|
+
<FlatList
|
|
30
|
+
data={props.data}
|
|
31
|
+
renderItem={({ item, index }) => {
|
|
32
|
+
return (
|
|
33
|
+
<TextButton
|
|
34
|
+
text={item.text}
|
|
35
|
+
style={props.itemStyle}
|
|
36
|
+
textStyle={styles.popoverItemText}
|
|
37
|
+
onPress={() => {
|
|
38
|
+
props.onItemPress(item.value, index)
|
|
39
|
+
}} />
|
|
40
|
+
)
|
|
41
|
+
}}
|
|
42
|
+
keyExtractor={(_, index) => `${index}`}
|
|
43
|
+
ItemSeparatorComponent={() => (<View style={styles.line} />)} />
|
|
44
|
+
</Card>
|
|
45
|
+
</Dialog>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const styles = StyleSheet.create({
|
|
49
|
+
popoverItemText: {
|
|
50
|
+
color: '#000',
|
|
51
|
+
fontSize: cx(16),
|
|
52
|
+
},
|
|
53
|
+
line: {
|
|
54
|
+
height: .5,
|
|
55
|
+
backgroundColor: 'rgba(60,60,67,.36)',
|
|
56
|
+
},
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
export default CustomListDialog
|
package/src/components/Page.tsx
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import React, {PropsWithChildren} from 'react'
|
|
2
|
-
import {View, ViewProps} from 'react-native'
|
|
1
|
+
import React, { PropsWithChildren, useCallback } from 'react'
|
|
2
|
+
import { View, ViewProps } from 'react-native'
|
|
3
3
|
import LDVTopBar from './ldvTopBar'
|
|
4
|
-
import {useNavigation} from '@react-navigation/native'
|
|
4
|
+
import { useNavigation } from '@react-navigation/native'
|
|
5
5
|
import LdvTopName from './ldvTopName'
|
|
6
|
+
import { Dialog, Toast } from 'tuya-panel-kit'
|
|
7
|
+
import I18n from '../i18n'
|
|
6
8
|
|
|
7
9
|
interface PageProps extends PropsWithChildren<ViewProps> {
|
|
10
|
+
rightButtonDisabled?: boolean
|
|
8
11
|
backText: string
|
|
9
12
|
onBackClick?: () => void
|
|
13
|
+
showBackDialog?: boolean
|
|
14
|
+
backDialogTitle?: string
|
|
15
|
+
backDialogContent?: string
|
|
10
16
|
rightButtonIcon?: string
|
|
11
17
|
rightButtonIconClick?: () => void
|
|
12
18
|
headlineText?: string
|
|
@@ -14,31 +20,59 @@ interface PageProps extends PropsWithChildren<ViewProps> {
|
|
|
14
20
|
onHeadlineIconClick?: () => void
|
|
15
21
|
showGreenery?: boolean
|
|
16
22
|
greeneryIcon?: string | undefined | number
|
|
23
|
+
loading?: boolean
|
|
17
24
|
}
|
|
18
25
|
|
|
19
26
|
const Page = (props: PageProps) => {
|
|
20
27
|
const navigation = useNavigation()
|
|
28
|
+
const disabled = props.rightButtonDisabled
|
|
21
29
|
|
|
30
|
+
const onBack = useCallback(() => {
|
|
31
|
+
if (disabled) {
|
|
32
|
+
navigation.goBack()
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
Dialog.confirm({
|
|
36
|
+
title: props.backDialogTitle || '',
|
|
37
|
+
subTitle: props.backDialogContent || '',
|
|
38
|
+
cancelText: I18n.getLang('cancel_dialog_delete_item_sleepschedule_answer_no_text'),
|
|
39
|
+
confirmText: I18n.getLang('cancel_dialog_delete_item_sleepschedule_answer_yes_text'),
|
|
40
|
+
onConfirm: (_, { close }) => {
|
|
41
|
+
close()
|
|
42
|
+
navigation.goBack()
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
return true
|
|
46
|
+
},
|
|
47
|
+
[props.backDialogTitle, props.backDialogContent, disabled],
|
|
48
|
+
)
|
|
22
49
|
return (
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
<>
|
|
51
|
+
<View style={[{ flex: 1 }, props.style]}>
|
|
52
|
+
<LDVTopBar
|
|
53
|
+
title={props.backText}
|
|
54
|
+
onBackPress={props.onBackClick || (() => {
|
|
55
|
+
navigation.goBack()
|
|
56
|
+
})}
|
|
57
|
+
rightButtonIcon={props.rightButtonIcon}
|
|
58
|
+
onRightButtonPress={props.rightButtonIconClick}
|
|
59
|
+
/>
|
|
60
|
+
{props.headlineText &&
|
|
33
61
|
<LdvTopName
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
62
|
+
title={props.headlineText}
|
|
63
|
+
rightIcon={props.headlineIcon}
|
|
64
|
+
rightIconClick={props.onHeadlineIconClick}
|
|
65
|
+
showGreenery={props.showGreenery}
|
|
66
|
+
greeneryIcon={props.greeneryIcon}
|
|
39
67
|
/>}
|
|
40
|
-
|
|
41
|
-
|
|
68
|
+
{props.children}
|
|
69
|
+
</View>
|
|
70
|
+
<Toast.Loading
|
|
71
|
+
show={!!props.loading}
|
|
72
|
+
onFinish={() => {
|
|
73
|
+
|
|
74
|
+
}} />
|
|
75
|
+
</>
|
|
42
76
|
)
|
|
43
77
|
}
|
|
44
78
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Image, StyleSheet, Text, TextInput, TextInputProps, TouchableOpacity, View} from 'react-native'
|
|
1
|
+
import {Image, StyleSheet, Text, TextInput, TextInputProps, ImageSourcePropType,TouchableOpacity, View} from 'react-native'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import {Utils} from 'tuya-panel-kit'
|
|
4
4
|
import res from '../res'
|
|
@@ -6,7 +6,10 @@ import res from '../res'
|
|
|
6
6
|
const cx = Utils.RatioUtils.convertX
|
|
7
7
|
|
|
8
8
|
interface TextFieldProps extends TextInputProps {
|
|
9
|
-
|
|
9
|
+
showError?: boolean
|
|
10
|
+
errorText?: string
|
|
11
|
+
tipIcon?: ImageSourcePropType
|
|
12
|
+
tipColor?: string
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
const TextField = (props: TextFieldProps) => {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { StyleSheet, Text, TouchableOpacity, View, ViewProps } from 'react-native'
|
|
2
|
+
import { Utils } from 'tuya-panel-kit'
|
|
3
|
+
import React from 'react'
|
|
4
|
+
|
|
5
|
+
const cx = Utils.RatioUtils.convertX
|
|
6
|
+
|
|
7
|
+
interface TextFieldStyleButtonProps extends ViewProps {
|
|
8
|
+
placeholder: string
|
|
9
|
+
text: string
|
|
10
|
+
onPress: () => void
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const TextFieldStyleButton = (props: TextFieldStyleButtonProps) => {
|
|
14
|
+
return (
|
|
15
|
+
<View style={props.style}>
|
|
16
|
+
<Text style={styles.topTip}>{props.placeholder}</Text>
|
|
17
|
+
<TouchableOpacity onPress={props.onPress}>
|
|
18
|
+
<View style={styles.textGroup}>
|
|
19
|
+
<View style={styles.textParent}>
|
|
20
|
+
<Text style={styles.text}>{props.text}</Text>
|
|
21
|
+
</View>
|
|
22
|
+
<View style={styles.line} />
|
|
23
|
+
</View>
|
|
24
|
+
</TouchableOpacity>
|
|
25
|
+
</View>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const styles = StyleSheet.create({
|
|
30
|
+
topTip: {
|
|
31
|
+
marginTop: cx(5),
|
|
32
|
+
fontSize: cx(12),
|
|
33
|
+
marginStart: cx(13),
|
|
34
|
+
color: '#666',
|
|
35
|
+
fontFamily: 'helvetica_neue_lt_std_bd',
|
|
36
|
+
},
|
|
37
|
+
textGroup: {
|
|
38
|
+
flexDirection: 'row',
|
|
39
|
+
borderRadius: cx(4),
|
|
40
|
+
backgroundColor: '#f6f6f6',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
},
|
|
43
|
+
textParent: {
|
|
44
|
+
flex: 1,
|
|
45
|
+
height: cx(44),
|
|
46
|
+
justifyContent: 'center',
|
|
47
|
+
},
|
|
48
|
+
text: {
|
|
49
|
+
marginStart: cx(16),
|
|
50
|
+
marginEnd: cx(6),
|
|
51
|
+
fontSize: cx(16),
|
|
52
|
+
color: '#000',
|
|
53
|
+
fontFamily: 'helvetica_neue_lt_std_roman',
|
|
54
|
+
},
|
|
55
|
+
line: {
|
|
56
|
+
height: 1,
|
|
57
|
+
position: 'absolute',
|
|
58
|
+
start: cx(4),
|
|
59
|
+
end: cx(4),
|
|
60
|
+
bottom: 0,
|
|
61
|
+
backgroundColor: '#cbcbcb',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
export default TextFieldStyleButton
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { StyleProp, StyleSheet, Text, TextStyle, TouchableOpacity, View, ViewStyle } from 'react-native'
|
|
3
|
+
import { Utils } from 'tuya-panel-kit'
|
|
4
|
+
|
|
5
|
+
const { convertX } = Utils.RatioUtils
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
style?: StyleProp<ViewStyle>
|
|
9
|
+
textStyle?: StyleProp<TextStyle>
|
|
10
|
+
title: string
|
|
11
|
+
rightComponent?: any
|
|
12
|
+
onPress?: any
|
|
13
|
+
disabled?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const LdvItemView: React.FC<Props> = (props) => {
|
|
17
|
+
const { rightComponent, title, style, onPress, disabled, textStyle } = props
|
|
18
|
+
return (
|
|
19
|
+
<TouchableOpacity onPress={onPress} disabled={disabled}>
|
|
20
|
+
<View style={[styles.bg, style]}>
|
|
21
|
+
<Text style={[styles.text, textStyle]}>
|
|
22
|
+
{title}
|
|
23
|
+
</Text>
|
|
24
|
+
{rightComponent && rightComponent()}
|
|
25
|
+
</View>
|
|
26
|
+
</TouchableOpacity>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const styles = StyleSheet.create({
|
|
31
|
+
bg: {
|
|
32
|
+
height: convertX(50),
|
|
33
|
+
flexDirection: 'row',
|
|
34
|
+
justifyContent: 'space-between',
|
|
35
|
+
alignItems: 'center',
|
|
36
|
+
marginHorizontal: convertX(24),
|
|
37
|
+
},
|
|
38
|
+
text: {
|
|
39
|
+
fontSize: convertX(16),
|
|
40
|
+
fontWeight: 'bold',
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
export default LdvItemView
|
package/src/utils/index.ts
CHANGED
|
@@ -162,3 +162,11 @@ export const getHSVByHex = (string) => {
|
|
|
162
162
|
v: parseInt(v, 16),
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
+
|
|
166
|
+
export function mapFloatToRange(value: number, min: number, max: number): number {
|
|
167
|
+
// 确保 value 在 [0, 1] 范围内
|
|
168
|
+
value = Math.max(0, Math.min(1, value))
|
|
169
|
+
|
|
170
|
+
// 计算插值后的值
|
|
171
|
+
return min + value * (max - min)
|
|
172
|
+
}
|