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