xref: /MusicFree/src/pages/setCustomTheme/body.tsx (revision 5589cdf32b2bb0f641e5ac7bf1f6152cd6b9b70e)
1import React from 'react';
2import {StyleSheet, View} from 'react-native';
3import rpx from '@/utils/rpx';
4import globalStyle from '@/constants/globalStyle';
5import Image from '@/components/base/image';
6import {ImgAsset} from '@/constants/assetsConst';
7import {ScrollView, TouchableOpacity} from 'react-native-gesture-handler';
8import {launchImageLibrary} from 'react-native-image-picker';
9import pathConst from '@/constants/pathConst';
10import {copyFile} from 'react-native-fs';
11import ImageColors from 'react-native-image-colors';
12import ThemeText from '@/components/base/themeText';
13import Slider from '@react-native-community/slider';
14import Theme from '@/core/theme';
15import Color from 'color';
16import {showPanel} from '@/components/panels/usePanel';
17import {grayRate} from '@/utils/colorUtil';
18import {CustomizedColors} from '@/hooks/useColors';
19
20export default function Body() {
21    const theme = Theme.useTheme();
22    const backgroundInfo = Theme.useBackground();
23
24    async function onImageClick() {
25        try {
26            const result = await launchImageLibrary({
27                mediaType: 'photo',
28            });
29            const uri = result.assets?.[0].uri;
30            if (!uri) {
31                return;
32            }
33
34            const bgPath = `${pathConst.dataPath}background${uri.substring(
35                uri.lastIndexOf('.'),
36            )}`;
37            await copyFile(uri, bgPath);
38
39            const colorsResult = await ImageColors.getColors(uri, {
40                fallback: '#ffffff',
41            });
42            const colors = {
43                primary:
44                    colorsResult.platform === 'android'
45                        ? colorsResult.dominant
46                        : colorsResult.platform === 'ios'
47                        ? colorsResult.primary
48                        : colorsResult.vibrant,
49                average:
50                    colorsResult.platform === 'android'
51                        ? colorsResult.average
52                        : colorsResult.platform === 'ios'
53                        ? colorsResult.detail
54                        : colorsResult.dominant,
55                vibrant:
56                    colorsResult.platform === 'android'
57                        ? colorsResult.vibrant
58                        : colorsResult.platform === 'ios'
59                        ? colorsResult.secondary
60                        : colorsResult.vibrant,
61            };
62
63            const primaryGrayRate = grayRate(colors.primary!);
64
65            let themeColors: Partial<CustomizedColors>;
66            if (primaryGrayRate < -0.4) {
67                const primaryColor = Color(colors.primary!);
68
69                console.log(
70                    colors.primary,
71                    primaryGrayRate,
72                    primaryColor
73                        .whiten(3 * primaryGrayRate)
74                        .hex()
75                        .toString(),
76                );
77                themeColors = {
78                    appBar: colors.primary,
79                    primary: primaryColor
80                        .darken(primaryGrayRate * 5)
81                        .toString(),
82                    musicBar: colors.primary,
83                    card: 'rgba(0,0,0,0.2)',
84                    tabBar: primaryColor.alpha(0.2).toString(),
85                };
86            } else if (primaryGrayRate > 0.4) {
87                themeColors = {
88                    appBar: colors.primary,
89                    primary: Color(colors.primary)
90                        .darken(primaryGrayRate * 5)
91                        .toString(),
92                    musicBar: colors.primary,
93                    card: 'rgba(0,0,0,0.2)',
94                };
95            } else {
96                // const primaryColor = Color(colors.primary!);
97
98                themeColors = {
99                    appBar: colors.primary,
100                    primary: Color(colors.primary)
101                        .saturate(Math.abs(primaryGrayRate) * 2 + 2)
102                        .toString(),
103                    musicBar: colors.primary,
104                    card: 'rgba(0,0,0,0.2)',
105                };
106            }
107
108            Theme.setTheme('custom', {
109                colors: themeColors,
110                background: {
111                    url: `file://${bgPath}#${Date.now()}`,
112                },
113            });
114            // Config.set('setting.theme.colors', {
115            //     primary: primaryColor,
116            //     textHighlight: textHighlight,
117            //     accent: textHighlight,
118            // });
119        } catch (e) {
120            console.log(e);
121        }
122    }
123
124    return (
125        <ScrollView style={globalStyle.fwflex1}>
126            <TouchableOpacity onPress={onImageClick}>
127                <Image
128                    style={styles.image}
129                    uri={backgroundInfo?.url}
130                    emptySrc={ImgAsset.addBackground}
131                />
132            </TouchableOpacity>
133
134            <View style={styles.sliderWrapper}>
135                <ThemeText>模糊度</ThemeText>
136                <Slider
137                    style={styles.slider}
138                    minimumTrackTintColor={theme.colors.primary}
139                    maximumTrackTintColor={theme.colors.text ?? '#999999'}
140                    thumbTintColor={theme.colors.primary}
141                    minimumValue={0}
142                    step={1}
143                    maximumValue={30}
144                    onSlidingComplete={val => {
145                        Theme.setBackground({
146                            blur: val,
147                        });
148                    }}
149                    value={backgroundInfo?.blur ?? 20}
150                />
151            </View>
152            <View style={styles.sliderWrapper}>
153                <ThemeText>透明度</ThemeText>
154                <Slider
155                    style={styles.slider}
156                    minimumTrackTintColor={theme.colors.primary}
157                    maximumTrackTintColor={theme.colors.text ?? '#999999'}
158                    thumbTintColor={theme.colors.primary}
159                    minimumValue={0.3}
160                    step={0.01}
161                    maximumValue={1}
162                    onSlidingComplete={val => {
163                        Theme.setBackground({
164                            opacity: val,
165                        });
166                    }}
167                    value={backgroundInfo?.opacity ?? 0.7}
168                />
169            </View>
170            <View style={styles.colorsContainer}>
171                {Theme.configableColorKey.map(key => (
172                    <View key={key} style={styles.colorItem}>
173                        <ThemeText>{Theme.colorDesc[key]}</ThemeText>
174                        <TouchableOpacity
175                            onPress={() => {
176                                showPanel('ColorPicker', {
177                                    // @ts-ignore
178                                    defaultColor: theme.colors[key],
179                                    onSelected(color) {
180                                        Theme.setColors({
181                                            [key]: color.hexa().toString(),
182                                        });
183                                    },
184                                });
185                            }}
186                            style={styles.colorItemBlockContainer}>
187                            <View style={[styles.colorBlockContainer]}>
188                                <Image
189                                    resizeMode="repeat"
190                                    emptySrc={ImgAsset.transparentBg}
191                                    style={styles.transparentBg}
192                                />
193                                <View
194                                    style={[
195                                        {
196                                            /** @ts-ignore */
197                                            backgroundColor: theme.colors[key],
198                                        },
199                                        styles.colorBlock,
200                                    ]}
201                                />
202                            </View>
203                            <ThemeText
204                                fontSize="subTitle"
205                                style={styles.colorText}>
206                                {
207                                    /** @ts-ignore */
208                                    Color(theme.colors[key]).hexa().toString()
209                                }
210                            </ThemeText>
211                        </TouchableOpacity>
212                    </View>
213                ))}
214            </View>
215        </ScrollView>
216    );
217}
218
219const styles = StyleSheet.create({
220    container: {
221        width: '100%',
222        flex: 1,
223    },
224    image: {
225        marginTop: rpx(36),
226        borderRadius: rpx(12),
227        width: rpx(460),
228        height: rpx(690),
229        alignSelf: 'center',
230    },
231    sliderWrapper: {
232        marginTop: rpx(48),
233        width: '100%',
234        paddingHorizontal: rpx(24),
235        flexDirection: 'row',
236        justifyContent: 'space-between',
237        alignItems: 'center',
238    },
239    slider: {
240        flex: 1,
241        height: rpx(40),
242    },
243    colorsContainer: {
244        width: '100%',
245        flex: 1,
246        flexDirection: 'row',
247        flexWrap: 'wrap',
248        marginTop: rpx(48),
249        paddingHorizontal: rpx(24),
250        justifyContent: 'space-between',
251    },
252    colorItem: {
253        flex: 1,
254        flexBasis: '40%',
255        marginBottom: rpx(36),
256    },
257    colorBlockContainer: {
258        width: rpx(76),
259        height: rpx(50),
260        borderWidth: 1,
261        borderStyle: 'solid',
262        borderColor: '#ccc',
263    },
264    colorBlock: {
265        width: '100%',
266        height: '100%',
267        position: 'absolute',
268        top: 0,
269        left: 0,
270        zIndex: 2,
271    },
272    colorItemBlockContainer: {
273        marginTop: rpx(18),
274        flexDirection: 'row',
275        alignItems: 'center',
276    },
277    colorText: {
278        marginLeft: rpx(8),
279    },
280    transparentBg: {
281        position: 'absolute',
282        zIndex: -1,
283        width: '100%',
284        height: '100%',
285        left: 0,
286        top: 0,
287    },
288});
289