xref: /MusicFree/src/components/musicBar/index.tsx (revision 428a07232c590a64f321e5de380e0b764e4a2b5e)
1import React, {memo, useEffect, useState} from 'react';
2import {Keyboard, Pressable, StyleSheet, Text, View} from 'react-native';
3import rpx from '@/utils/rpx';
4import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
5import MusicQueue from '@/core/musicQueue';
6import {Avatar, IconButton, useTheme} from 'react-native-paper';
7import {CircularProgressBase} from 'react-native-circular-progress-indicator';
8import {ROUTE_PATH, useNavigate} from '@/entry/router';
9
10import musicIsPaused from '@/utils/musicIsPaused';
11
12import Color from 'color';
13import ThemeText from '../base/themeText';
14import {ImgAsset} from '@/constants/assetsConst';
15import {useSafeAreaInsets} from 'react-native-safe-area-context';
16import {showPanel} from '../panels/usePanel';
17
18function CircularPlayBtn() {
19    const progress = MusicQueue.useProgress();
20    const musicState = MusicQueue.usePlaybackState();
21    const {colors} = useTheme();
22
23    return (
24        <CircularProgressBase
25            activeStrokeWidth={rpx(4)}
26            inActiveStrokeWidth={rpx(2)}
27            inActiveStrokeOpacity={0.2}
28            value={
29                progress?.duration
30                    ? (100 * progress.position) / progress.duration
31                    : 0
32            }
33            duration={100}
34            radius={rpx(36)}
35            activeStrokeColor={colors.text}
36            inActiveStrokeColor={Color(colors.text).alpha(0.5).toString()}>
37            {musicIsPaused(musicState) ? (
38                <IconButton
39                    icon="play"
40                    size={rpx(48)}
41                    onPress={async () => {
42                        await MusicQueue.play();
43                    }}
44                />
45            ) : (
46                <IconButton
47                    icon="pause"
48                    size={rpx(48)}
49                    onPress={async () => {
50                        await MusicQueue.pause();
51                    }}
52                />
53            )}
54        </CircularProgressBase>
55    );
56}
57function MusicBar() {
58    const musicItem = MusicQueue.useCurrentMusicItem();
59
60    const [showKeyboard, setKeyboardStatus] = useState(false);
61
62    const navigate = useNavigate();
63    const {colors} = useTheme();
64    const safeAreaInsets = useSafeAreaInsets();
65
66    useEffect(() => {
67        const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
68            setKeyboardStatus(true);
69        });
70        const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
71            setKeyboardStatus(false);
72        });
73
74        return () => {
75            showSubscription.remove();
76            hideSubscription.remove();
77        };
78    }, []);
79
80    return (
81        <>
82            {musicItem && !showKeyboard && (
83                <Pressable
84                    style={[
85                        style.wrapper,
86                        {
87                            backgroundColor: Color(colors.primary)
88                                .alpha(0.66)
89                                .toString(),
90                            paddingLeft: safeAreaInsets.left + rpx(24),
91                            paddingRight: safeAreaInsets.right + rpx(24),
92                        },
93                    ]}
94                    onPress={() => {
95                        navigate(ROUTE_PATH.MUSIC_DETAIL);
96                    }}>
97                    <View style={style.artworkWrapper}>
98                        <Avatar.Image
99                            size={rpx(96)}
100                            source={
101                                musicItem?.artwork
102                                    ? {
103                                          uri: musicItem.artwork,
104                                      }
105                                    : ImgAsset.albumDefault
106                            }
107                        />
108                    </View>
109                    <Text
110                        ellipsizeMode="tail"
111                        style={style.textWrapper}
112                        numberOfLines={1}>
113                        <ThemeText fontSize="content">
114                            {musicItem?.title}
115                        </ThemeText>
116                        {musicItem?.artist && (
117                            <ThemeText
118                                fontSize="description"
119                                fontColor="secondary">
120                                {' '}
121                                -{musicItem.artist}
122                            </ThemeText>
123                        )}
124                    </Text>
125                    <View style={style.actionGroup}>
126                        <CircularPlayBtn />
127
128                        <Icon
129                            name="playlist-music"
130                            size={rpx(56)}
131                            onPress={() => {
132                                showPanel('PlayList');
133                            }}
134                            style={[style.actionIcon, {color: colors.text}]}
135                        />
136                    </View>
137                </Pressable>
138            )}
139        </>
140    );
141}
142
143export default memo(MusicBar, () => true);
144
145const style = StyleSheet.create({
146    wrapper: {
147        width: '100%',
148        height: rpx(120),
149        flexDirection: 'row',
150        alignItems: 'center',
151        paddingHorizontal: rpx(24),
152    },
153    artworkWrapper: {
154        height: rpx(120),
155        width: rpx(120),
156    },
157    textWrapper: {
158        flexGrow: 1,
159        flexShrink: 1,
160    },
161    actionGroup: {
162        width: rpx(200),
163        justifyContent: 'flex-end',
164        flexDirection: 'row',
165        alignItems: 'center',
166    },
167    actionIcon: {
168        marginLeft: rpx(36),
169    },
170});
171