xref: /MusicFree/src/components/base/appBar.tsx (revision 7a8d024e62c773caa4d0887b9fec4611e8a8ef82)
1e650bfb3S猫头猫import React, {ReactNode, useEffect, useRef, useState} from 'react';
2e650bfb3S猫头猫import {
3e650bfb3S猫头猫    LayoutRectangle,
4e650bfb3S猫头猫    StyleSheet,
5e650bfb3S猫头猫    TouchableWithoutFeedback,
6e650bfb3S猫头猫    View,
7e650bfb3S猫头猫    StatusBar as OriginalStatusBar,
8e650bfb3S猫头猫} from 'react-native';
9e650bfb3S猫头猫import rpx from '@/utils/rpx';
10e650bfb3S猫头猫import useColors from '@/hooks/useColors';
11e650bfb3S猫头猫import StatusBar from './statusBar';
12e650bfb3S猫头猫import color from 'color';
13e650bfb3S猫头猫import IconButton from './iconButton';
14e650bfb3S猫头猫import globalStyle from '@/constants/globalStyle';
15e650bfb3S猫头猫import ThemeText from './themeText';
16e650bfb3S猫头猫import {useNavigation} from '@react-navigation/native';
17e650bfb3S猫头猫import Animated, {
18e650bfb3S猫头猫    Easing,
19e650bfb3S猫头猫    useAnimatedStyle,
20e650bfb3S猫头猫    useSharedValue,
21e650bfb3S猫头猫    withTiming,
22e650bfb3S猫头猫} from 'react-native-reanimated';
23e650bfb3S猫头猫import Portal from './portal';
24e650bfb3S猫头猫import IconTextButton from './iconTextButton';
25e650bfb3S猫头猫
26e650bfb3S猫头猫interface IAppBarProps {
27e650bfb3S猫头猫    backgroundOpacity?: number;
28e650bfb3S猫头猫    titleTextOpacity?: number;
29e650bfb3S猫头猫    withStatusBar?: boolean;
30e650bfb3S猫头猫    color?: string;
31e650bfb3S猫头猫    actions?: Array<{
32e650bfb3S猫头猫        icon: string;
33e650bfb3S猫头猫        onPress?: () => void;
34e650bfb3S猫头猫    }>;
35e650bfb3S猫头猫    menu?: Array<{
36e650bfb3S猫头猫        icon: string;
37e650bfb3S猫头猫        title: string;
38*7a8d024eS猫头猫        show?: boolean;
39e650bfb3S猫头猫        onPress?: () => void;
40e650bfb3S猫头猫    }>;
41e650bfb3S猫头猫    menuWithStatusBar?: boolean;
42e650bfb3S猫头猫    children?: string | ReactNode;
43e650bfb3S猫头猫}
44e650bfb3S猫头猫
45e650bfb3S猫头猫const ANIMATION_EASING: Animated.EasingFunction = Easing.out(Easing.exp);
46e650bfb3S猫头猫const ANIMATION_DURATION = 500;
47e650bfb3S猫头猫
48e650bfb3S猫头猫const timingConfig = {
49e650bfb3S猫头猫    duration: ANIMATION_DURATION,
50e650bfb3S猫头猫    easing: ANIMATION_EASING,
51e650bfb3S猫头猫};
52e650bfb3S猫头猫
53e650bfb3S猫头猫export default function AppBar(props: IAppBarProps) {
54e650bfb3S猫头猫    const {
55e650bfb3S猫头猫        backgroundOpacity = 1,
56e650bfb3S猫头猫        titleTextOpacity = 1,
57e650bfb3S猫头猫        withStatusBar,
58e650bfb3S猫头猫        color: _color,
59e650bfb3S猫头猫        actions = [],
60e650bfb3S猫头猫        menu = [],
61e650bfb3S猫头猫        menuWithStatusBar = true,
62e650bfb3S猫头猫        children,
63e650bfb3S猫头猫    } = props;
64e650bfb3S猫头猫
65e650bfb3S猫头猫    const colors = useColors();
66e650bfb3S猫头猫    const navigation = useNavigation();
67e650bfb3S猫头猫
68e650bfb3S猫头猫    const bgColor = color(colors.primary).alpha(backgroundOpacity).toString();
69e650bfb3S猫头猫    const contentColor = _color ?? colors.headerText;
70e650bfb3S猫头猫
71e650bfb3S猫头猫    const [showMenu, setShowMenu] = useState(false);
72e650bfb3S猫头猫    const menuIconLayoutRef = useRef<LayoutRectangle>();
73e650bfb3S猫头猫    const scaleRate = useSharedValue(0);
74e650bfb3S猫头猫
75e650bfb3S猫头猫    useEffect(() => {
76e650bfb3S猫头猫        if (showMenu) {
77e650bfb3S猫头猫            scaleRate.value = withTiming(1, timingConfig);
78e650bfb3S猫头猫        } else {
79e650bfb3S猫头猫            scaleRate.value = withTiming(0, timingConfig);
80e650bfb3S猫头猫        }
81e650bfb3S猫头猫    }, [showMenu]);
82e650bfb3S猫头猫
83e650bfb3S猫头猫    const transformStyle = useAnimatedStyle(() => {
84e650bfb3S猫头猫        return {
85e650bfb3S猫头猫            opacity: scaleRate.value,
86e650bfb3S猫头猫        };
87e650bfb3S猫头猫    });
88e650bfb3S猫头猫
89e650bfb3S猫头猫    return (
90e650bfb3S猫头猫        <>
91e650bfb3S猫头猫            {withStatusBar ? <StatusBar backgroundColor={bgColor} /> : null}
92e650bfb3S猫头猫            <View style={[styles.container, {backgroundColor: bgColor}]}>
93e650bfb3S猫头猫                <IconButton
94e650bfb3S猫头猫                    name="arrow-left"
95e650bfb3S猫头猫                    sizeType="normal"
96e650bfb3S猫头猫                    color={contentColor}
97e650bfb3S猫头猫                    style={globalStyle.notShrink}
98e650bfb3S猫头猫                    onPress={() => {
99e650bfb3S猫头猫                        navigation.goBack();
100e650bfb3S猫头猫                    }}
101e650bfb3S猫头猫                />
102e650bfb3S猫头猫                <View style={[globalStyle.grow, styles.content]}>
103e650bfb3S猫头猫                    {typeof children === 'string' ? (
104e650bfb3S猫头猫                        <ThemeText
105e650bfb3S猫头猫                            fontSize="title"
106e650bfb3S猫头猫                            fontWeight="bold"
107e650bfb3S猫头猫                            numberOfLines={1}
108e650bfb3S猫头猫                            color={
109e650bfb3S猫头猫                                titleTextOpacity !== 1
110e650bfb3S猫头猫                                    ? color(contentColor)
111e650bfb3S猫头猫                                          .alpha(titleTextOpacity)
112e650bfb3S猫头猫                                          .toString()
113e650bfb3S猫头猫                                    : contentColor
114e650bfb3S猫头猫                            }>
115e650bfb3S猫头猫                            {children}
116e650bfb3S猫头猫                        </ThemeText>
117e650bfb3S猫头猫                    ) : (
118e650bfb3S猫头猫                        children
119e650bfb3S猫头猫                    )}
120e650bfb3S猫头猫                </View>
121e650bfb3S猫头猫                {actions.map(action => (
122e650bfb3S猫头猫                    <IconButton
123e650bfb3S猫头猫                        name={action.icon}
124e650bfb3S猫头猫                        sizeType="normal"
125e650bfb3S猫头猫                        color={contentColor}
126e650bfb3S猫头猫                        style={[globalStyle.notShrink, styles.rightButton]}
127e650bfb3S猫头猫                        onPress={action.onPress}
128e650bfb3S猫头猫                    />
129e650bfb3S猫头猫                ))}
130e650bfb3S猫头猫                {menu?.length ? (
131e650bfb3S猫头猫                    <IconButton
132e650bfb3S猫头猫                        name="dots-vertical"
133e650bfb3S猫头猫                        sizeType="normal"
134e650bfb3S猫头猫                        onLayout={e => {
135e650bfb3S猫头猫                            menuIconLayoutRef.current = e.nativeEvent.layout;
136e650bfb3S猫头猫                        }}
137e650bfb3S猫头猫                        color={contentColor}
138e650bfb3S猫头猫                        style={[globalStyle.notShrink, styles.rightButton]}
139e650bfb3S猫头猫                        onPress={() => {
140e650bfb3S猫头猫                            setShowMenu(true);
141e650bfb3S猫头猫                        }}
142e650bfb3S猫头猫                    />
143e650bfb3S猫头猫                ) : null}
144e650bfb3S猫头猫            </View>
145e650bfb3S猫头猫            <Portal>
146e650bfb3S猫头猫                {showMenu ? (
147e650bfb3S猫头猫                    <TouchableWithoutFeedback
148e650bfb3S猫头猫                        onPress={() => {
149e650bfb3S猫头猫                            setShowMenu(false);
150e650bfb3S猫头猫                        }}>
151e650bfb3S猫头猫                        <View style={styles.blocker} />
152e650bfb3S猫头猫                    </TouchableWithoutFeedback>
153e650bfb3S猫头猫                ) : null}
154e650bfb3S猫头猫                <>
155e650bfb3S猫头猫                    <Animated.View
156e650bfb3S猫头猫                        pointerEvents={showMenu ? 'auto' : 'none'}
157e650bfb3S猫头猫                        style={[
158e650bfb3S猫头猫                            {
159e650bfb3S猫头猫                                borderBottomColor: colors.backdrop,
160e650bfb3S猫头猫                                left:
161e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.x ?? 0) +
162e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.width ?? 0) /
163e650bfb3S猫头猫                                        2 -
164e650bfb3S猫头猫                                    rpx(10),
165e650bfb3S猫头猫                                top:
166e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.y ?? 0) +
167e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.height ?? 0) +
168e650bfb3S猫头猫                                    (menuWithStatusBar
169e650bfb3S猫头猫                                        ? OriginalStatusBar.currentHeight ?? 0
170e650bfb3S猫头猫                                        : 0),
171e650bfb3S猫头猫                            },
172e650bfb3S猫头猫                            transformStyle,
173e650bfb3S猫头猫                            styles.bubbleCorner,
174e650bfb3S猫头猫                        ]}
175e650bfb3S猫头猫                    />
176e650bfb3S猫头猫                    <Animated.View
177e650bfb3S猫头猫                        pointerEvents={showMenu ? 'auto' : 'none'}
178e650bfb3S猫头猫                        style={[
179e650bfb3S猫头猫                            {
180e650bfb3S猫头猫                                backgroundColor: colors.headerText,
181e650bfb3S猫头猫                                right: rpx(24),
182e650bfb3S猫头猫                                top:
183e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.y ?? 0) +
184e650bfb3S猫头猫                                    (menuIconLayoutRef.current?.height ?? 0) +
185e650bfb3S猫头猫                                    rpx(20) +
186e650bfb3S猫头猫                                    (menuWithStatusBar
187e650bfb3S猫头猫                                        ? OriginalStatusBar.currentHeight ?? 0
188e650bfb3S猫头猫                                        : 0),
189e650bfb3S猫头猫                            },
190e650bfb3S猫头猫                            transformStyle,
191e650bfb3S猫头猫                            styles.menu,
192e650bfb3S猫头猫                        ]}>
193*7a8d024eS猫头猫                        {menu.map(it =>
194*7a8d024eS猫头猫                            it.show !== false ? (
195e650bfb3S猫头猫                                <IconTextButton
196e650bfb3S猫头猫                                    icon={it.icon}
197e650bfb3S猫头猫                                    onPress={() => {
198e650bfb3S猫头猫                                        it.onPress?.();
199e650bfb3S猫头猫                                        setShowMenu(false);
200e650bfb3S猫头猫                                    }}>
201e650bfb3S猫头猫                                    {it.title}
202e650bfb3S猫头猫                                </IconTextButton>
203*7a8d024eS猫头猫                            ) : null,
204*7a8d024eS猫头猫                        )}
205e650bfb3S猫头猫                    </Animated.View>
206e650bfb3S猫头猫                </>
207e650bfb3S猫头猫            </Portal>
208e650bfb3S猫头猫        </>
209e650bfb3S猫头猫    );
210e650bfb3S猫头猫}
211e650bfb3S猫头猫
212e650bfb3S猫头猫const styles = StyleSheet.create({
213e650bfb3S猫头猫    container: {
214e650bfb3S猫头猫        width: '100%',
215e650bfb3S猫头猫        zIndex: 10000,
216e650bfb3S猫头猫        height: rpx(88),
217e650bfb3S猫头猫        flexDirection: 'row',
218e650bfb3S猫头猫        paddingHorizontal: rpx(24),
219e650bfb3S猫头猫    },
220e650bfb3S猫头猫    content: {
221e650bfb3S猫头猫        flexDirection: 'row',
222e650bfb3S猫头猫        flexBasis: 0,
223e650bfb3S猫头猫        alignItems: 'center',
224e650bfb3S猫头猫        paddingHorizontal: rpx(24),
225e650bfb3S猫头猫    },
226e650bfb3S猫头猫    rightButton: {
227e650bfb3S猫头猫        marginLeft: rpx(28),
228e650bfb3S猫头猫    },
229e650bfb3S猫头猫    blocker: {
230e650bfb3S猫头猫        position: 'absolute',
231e650bfb3S猫头猫        bottom: 0,
232e650bfb3S猫头猫        left: 0,
233e650bfb3S猫头猫        width: '100%',
234e650bfb3S猫头猫        height: '100%',
235e650bfb3S猫头猫        zIndex: 10010,
236e650bfb3S猫头猫    },
237e650bfb3S猫头猫    bubbleCorner: {
238e650bfb3S猫头猫        position: 'absolute',
239e650bfb3S猫头猫        borderColor: 'transparent',
240e650bfb3S猫头猫        borderWidth: rpx(10),
241e650bfb3S猫头猫        zIndex: 10012,
242e650bfb3S猫头猫        transformOrigin: 'right top',
243e650bfb3S猫头猫        opacity: 0,
244e650bfb3S猫头猫    },
245e650bfb3S猫头猫    menu: {
246e650bfb3S猫头猫        width: rpx(340),
247e650bfb3S猫头猫        maxHeight: rpx(600),
248e650bfb3S猫头猫        borderRadius: rpx(8),
249e650bfb3S猫头猫        zIndex: 10011,
250e650bfb3S猫头猫        position: 'absolute',
251e650bfb3S猫头猫        opacity: 0,
252e650bfb3S猫头猫        shadowColor: '#000',
253e650bfb3S猫头猫        shadowOffset: {
254e650bfb3S猫头猫            width: 0,
255e650bfb3S猫头猫            height: 2,
256e650bfb3S猫头猫        },
257e650bfb3S猫头猫        shadowOpacity: 0.23,
258e650bfb3S猫头猫        shadowRadius: 2.62,
259e650bfb3S猫头猫        elevation: 4,
260e650bfb3S猫头猫    },
261e650bfb3S猫头猫});
262