1bcc58947S猫头猫import React, {ReactNode, useEffect, useState} from 'react'; 2e650bfb3S猫头猫import { 3e650bfb3S猫头猫 LayoutRectangle, 4*5589cdf3S猫头猫 StatusBar as OriginalStatusBar, 5*5589cdf3S猫头猫 StyleProp, 6e650bfb3S猫头猫 StyleSheet, 7e650bfb3S猫头猫 TouchableWithoutFeedback, 8e650bfb3S猫头猫 View, 91119c2eaS猫头猫 ViewStyle, 10e650bfb3S猫头猫} from 'react-native'; 11e650bfb3S猫头猫import rpx from '@/utils/rpx'; 12e650bfb3S猫头猫import useColors from '@/hooks/useColors'; 13e650bfb3S猫头猫import StatusBar from './statusBar'; 14e650bfb3S猫头猫import color from 'color'; 15e650bfb3S猫头猫import IconButton from './iconButton'; 16e650bfb3S猫头猫import globalStyle from '@/constants/globalStyle'; 17e650bfb3S猫头猫import ThemeText from './themeText'; 18e650bfb3S猫头猫import {useNavigation} from '@react-navigation/native'; 19e650bfb3S猫头猫import Animated, { 20e650bfb3S猫头猫 Easing, 21e650bfb3S猫头猫 useAnimatedStyle, 22e650bfb3S猫头猫 useSharedValue, 23e650bfb3S猫头猫 withTiming, 24e650bfb3S猫头猫} from 'react-native-reanimated'; 25e650bfb3S猫头猫import Portal from './portal'; 261119c2eaS猫头猫import ListItem from './listItem'; 27*5589cdf3S猫头猫import {IIconName} from '@/components/base/icon.tsx'; 28e650bfb3S猫头猫 29e650bfb3S猫头猫interface IAppBarProps { 30e650bfb3S猫头猫 titleTextOpacity?: number; 31e650bfb3S猫头猫 withStatusBar?: boolean; 32e650bfb3S猫头猫 color?: string; 33e650bfb3S猫头猫 actions?: Array<{ 34*5589cdf3S猫头猫 icon: IIconName; 35e650bfb3S猫头猫 onPress?: () => void; 36e650bfb3S猫头猫 }>; 37e650bfb3S猫头猫 menu?: Array<{ 38*5589cdf3S猫头猫 icon: IIconName; 39e650bfb3S猫头猫 title: string; 407a8d024eS猫头猫 show?: boolean; 41e650bfb3S猫头猫 onPress?: () => void; 42e650bfb3S猫头猫 }>; 43e650bfb3S猫头猫 menuWithStatusBar?: boolean; 44e650bfb3S猫头猫 children?: string | ReactNode; 451119c2eaS猫头猫 containerStyle?: StyleProp<ViewStyle>; 461119c2eaS猫头猫 contentStyle?: StyleProp<ViewStyle>; 47a27adc20S猫头猫 actionComponent?: ReactNode; 48e650bfb3S猫头猫} 49e650bfb3S猫头猫 50e650bfb3S猫头猫const ANIMATION_EASING: Animated.EasingFunction = Easing.out(Easing.exp); 51e650bfb3S猫头猫const ANIMATION_DURATION = 500; 52e650bfb3S猫头猫 53e650bfb3S猫头猫const timingConfig = { 54e650bfb3S猫头猫 duration: ANIMATION_DURATION, 55e650bfb3S猫头猫 easing: ANIMATION_EASING, 56e650bfb3S猫头猫}; 57e650bfb3S猫头猫 58e650bfb3S猫头猫export default function AppBar(props: IAppBarProps) { 59e650bfb3S猫头猫 const { 60e650bfb3S猫头猫 titleTextOpacity = 1, 61e650bfb3S猫头猫 withStatusBar, 62e650bfb3S猫头猫 color: _color, 63e650bfb3S猫头猫 actions = [], 64e650bfb3S猫头猫 menu = [], 65e650bfb3S猫头猫 menuWithStatusBar = true, 661119c2eaS猫头猫 containerStyle, 671119c2eaS猫头猫 contentStyle, 68e650bfb3S猫头猫 children, 69a27adc20S猫头猫 actionComponent, 70e650bfb3S猫头猫 } = props; 71e650bfb3S猫头猫 72e650bfb3S猫头猫 const colors = useColors(); 73e650bfb3S猫头猫 const navigation = useNavigation(); 74e650bfb3S猫头猫 75f2a4767cS猫头猫 const bgColor = color(colors.appBar ?? colors.primary).toString(); 76277c5280S猫头猫 const contentColor = _color ?? colors.appBarText; 77e650bfb3S猫头猫 78e650bfb3S猫头猫 const [showMenu, setShowMenu] = useState(false); 79bcc58947S猫头猫 const [menuIconLayout, setMenuIconLayout] = 80bcc58947S猫头猫 useState<LayoutRectangle | null>(null); 81e650bfb3S猫头猫 const scaleRate = useSharedValue(0); 82e650bfb3S猫头猫 83e650bfb3S猫头猫 useEffect(() => { 84e650bfb3S猫头猫 if (showMenu) { 85e650bfb3S猫头猫 scaleRate.value = withTiming(1, timingConfig); 86e650bfb3S猫头猫 } else { 87e650bfb3S猫头猫 scaleRate.value = withTiming(0, timingConfig); 88e650bfb3S猫头猫 } 89e650bfb3S猫头猫 }, [showMenu]); 90e650bfb3S猫头猫 91e650bfb3S猫头猫 const transformStyle = useAnimatedStyle(() => { 92e650bfb3S猫头猫 return { 93e650bfb3S猫头猫 opacity: scaleRate.value, 94e650bfb3S猫头猫 }; 95e650bfb3S猫头猫 }); 96e650bfb3S猫头猫 97e650bfb3S猫头猫 return ( 98e650bfb3S猫头猫 <> 99e650bfb3S猫头猫 {withStatusBar ? <StatusBar backgroundColor={bgColor} /> : null} 1001119c2eaS猫头猫 <View 1011119c2eaS猫头猫 style={[ 1021119c2eaS猫头猫 styles.container, 1031119c2eaS猫头猫 containerStyle, 1041119c2eaS猫头猫 {backgroundColor: bgColor}, 1051119c2eaS猫头猫 ]}> 106e650bfb3S猫头猫 <IconButton 107e650bfb3S猫头猫 name="arrow-left" 108e650bfb3S猫头猫 sizeType="normal" 109e650bfb3S猫头猫 color={contentColor} 110e650bfb3S猫头猫 style={globalStyle.notShrink} 111e650bfb3S猫头猫 onPress={() => { 112e650bfb3S猫头猫 navigation.goBack(); 113e650bfb3S猫头猫 }} 114e650bfb3S猫头猫 /> 1151119c2eaS猫头猫 <View style={[globalStyle.grow, styles.content, contentStyle]}> 116e650bfb3S猫头猫 {typeof children === 'string' ? ( 117e650bfb3S猫头猫 <ThemeText 118e650bfb3S猫头猫 fontSize="title" 119e650bfb3S猫头猫 fontWeight="bold" 120e650bfb3S猫头猫 numberOfLines={1} 121e650bfb3S猫头猫 color={ 122e650bfb3S猫头猫 titleTextOpacity !== 1 123e650bfb3S猫头猫 ? color(contentColor) 124e650bfb3S猫头猫 .alpha(titleTextOpacity) 125e650bfb3S猫头猫 .toString() 126e650bfb3S猫头猫 : contentColor 127e650bfb3S猫头猫 }> 128e650bfb3S猫头猫 {children} 129e650bfb3S猫头猫 </ThemeText> 130e650bfb3S猫头猫 ) : ( 131e650bfb3S猫头猫 children 132e650bfb3S猫头猫 )} 133e650bfb3S猫头猫 </View> 134f643c584S猫头猫 {actions.map((action, index) => ( 135e650bfb3S猫头猫 <IconButton 136f643c584S猫头猫 key={index} 137e650bfb3S猫头猫 name={action.icon} 138e650bfb3S猫头猫 sizeType="normal" 139e650bfb3S猫头猫 color={contentColor} 140e650bfb3S猫头猫 style={[globalStyle.notShrink, styles.rightButton]} 141e650bfb3S猫头猫 onPress={action.onPress} 142e650bfb3S猫头猫 /> 143e650bfb3S猫头猫 ))} 144a27adc20S猫头猫 {actionComponent ?? null} 145e650bfb3S猫头猫 {menu?.length ? ( 146e650bfb3S猫头猫 <IconButton 147*5589cdf3S猫头猫 name="ellipsis-vertical" 148e650bfb3S猫头猫 sizeType="normal" 149*5589cdf3S猫头猫 onLayout={evt => { 150*5589cdf3S猫头猫 setMenuIconLayout(evt.nativeEvent.layout); 151e650bfb3S猫头猫 }} 152e650bfb3S猫头猫 color={contentColor} 153e650bfb3S猫头猫 style={[globalStyle.notShrink, styles.rightButton]} 154e650bfb3S猫头猫 onPress={() => { 155e650bfb3S猫头猫 setShowMenu(true); 156e650bfb3S猫头猫 }} 157e650bfb3S猫头猫 /> 158e650bfb3S猫头猫 ) : null} 159e650bfb3S猫头猫 </View> 160e650bfb3S猫头猫 <Portal> 161e650bfb3S猫头猫 {showMenu ? ( 162e650bfb3S猫头猫 <TouchableWithoutFeedback 163e650bfb3S猫头猫 onPress={() => { 164e650bfb3S猫头猫 setShowMenu(false); 165e650bfb3S猫头猫 }}> 166e650bfb3S猫头猫 <View style={styles.blocker} /> 167e650bfb3S猫头猫 </TouchableWithoutFeedback> 168e650bfb3S猫头猫 ) : null} 169e650bfb3S猫头猫 <> 170e650bfb3S猫头猫 <Animated.View 171e650bfb3S猫头猫 pointerEvents={showMenu ? 'auto' : 'none'} 172e650bfb3S猫头猫 style={[ 173e650bfb3S猫头猫 { 174ab55f125S猫头猫 borderBottomColor: colors.background, 175e650bfb3S猫头猫 left: 176bcc58947S猫头猫 (menuIconLayout?.x ?? 0) + 177bcc58947S猫头猫 (menuIconLayout?.width ?? 0) / 2 - 178e650bfb3S猫头猫 rpx(10), 179e650bfb3S猫头猫 top: 180bcc58947S猫头猫 (menuIconLayout?.y ?? 0) + 181bcc58947S猫头猫 (menuIconLayout?.height ?? 0) + 182e650bfb3S猫头猫 (menuWithStatusBar 183e650bfb3S猫头猫 ? OriginalStatusBar.currentHeight ?? 0 184e650bfb3S猫头猫 : 0), 185e650bfb3S猫头猫 }, 186e650bfb3S猫头猫 transformStyle, 187e650bfb3S猫头猫 styles.bubbleCorner, 188e650bfb3S猫头猫 ]} 189e650bfb3S猫头猫 /> 190e650bfb3S猫头猫 <Animated.View 191e650bfb3S猫头猫 pointerEvents={showMenu ? 'auto' : 'none'} 192e650bfb3S猫头猫 style={[ 193e650bfb3S猫头猫 { 1946cfecf1cS猫头猫 backgroundColor: colors.background, 195e650bfb3S猫头猫 right: rpx(24), 196e650bfb3S猫头猫 top: 197bcc58947S猫头猫 (menuIconLayout?.y ?? 0) + 198bcc58947S猫头猫 (menuIconLayout?.height ?? 0) + 199e650bfb3S猫头猫 rpx(20) + 200e650bfb3S猫头猫 (menuWithStatusBar 201e650bfb3S猫头猫 ? OriginalStatusBar.currentHeight ?? 0 202e650bfb3S猫头猫 : 0), 2036cfecf1cS猫头猫 shadowColor: colors.shadow, 204e650bfb3S猫头猫 }, 205e650bfb3S猫头猫 transformStyle, 206e650bfb3S猫头猫 styles.menu, 207e650bfb3S猫头猫 ]}> 2087a8d024eS猫头猫 {menu.map(it => 2097a8d024eS猫头猫 it.show !== false ? ( 2101119c2eaS猫头猫 <ListItem 211f643c584S猫头猫 key={it.title} 212*5589cdf3S猫头猫 withHorizontalPadding 2131119c2eaS猫头猫 heightType="small" 214e650bfb3S猫头猫 onPress={() => { 215e650bfb3S猫头猫 it.onPress?.(); 216e650bfb3S猫头猫 setShowMenu(false); 217e650bfb3S猫头猫 }}> 2181119c2eaS猫头猫 <ListItem.ListItemIcon icon={it.icon} /> 2191119c2eaS猫头猫 <ListItem.Content title={it.title} /> 2201119c2eaS猫头猫 </ListItem> 2217a8d024eS猫头猫 ) : null, 2227a8d024eS猫头猫 )} 223e650bfb3S猫头猫 </Animated.View> 224e650bfb3S猫头猫 </> 225e650bfb3S猫头猫 </Portal> 226e650bfb3S猫头猫 </> 227e650bfb3S猫头猫 ); 228e650bfb3S猫头猫} 229e650bfb3S猫头猫 230e650bfb3S猫头猫const styles = StyleSheet.create({ 231e650bfb3S猫头猫 container: { 232e650bfb3S猫头猫 width: '100%', 233e650bfb3S猫头猫 zIndex: 10000, 234e650bfb3S猫头猫 height: rpx(88), 235e650bfb3S猫头猫 flexDirection: 'row', 236*5589cdf3S猫头猫 alignItems: 'center', 237e650bfb3S猫头猫 paddingHorizontal: rpx(24), 238e650bfb3S猫头猫 }, 239e650bfb3S猫头猫 content: { 240e650bfb3S猫头猫 flexDirection: 'row', 241e650bfb3S猫头猫 flexBasis: 0, 242e650bfb3S猫头猫 alignItems: 'center', 243e650bfb3S猫头猫 paddingHorizontal: rpx(24), 244e650bfb3S猫头猫 }, 245e650bfb3S猫头猫 rightButton: { 246e650bfb3S猫头猫 marginLeft: rpx(28), 247e650bfb3S猫头猫 }, 248e650bfb3S猫头猫 blocker: { 249e650bfb3S猫头猫 position: 'absolute', 250e650bfb3S猫头猫 bottom: 0, 251e650bfb3S猫头猫 left: 0, 252e650bfb3S猫头猫 width: '100%', 253e650bfb3S猫头猫 height: '100%', 254e650bfb3S猫头猫 zIndex: 10010, 255e650bfb3S猫头猫 }, 256e650bfb3S猫头猫 bubbleCorner: { 257e650bfb3S猫头猫 position: 'absolute', 258e650bfb3S猫头猫 borderColor: 'transparent', 259e650bfb3S猫头猫 borderWidth: rpx(10), 260e650bfb3S猫头猫 zIndex: 10012, 261e650bfb3S猫头猫 transformOrigin: 'right top', 262e650bfb3S猫头猫 opacity: 0, 263e650bfb3S猫头猫 }, 264e650bfb3S猫头猫 menu: { 265e650bfb3S猫头猫 width: rpx(340), 266e650bfb3S猫头猫 maxHeight: rpx(600), 267e650bfb3S猫头猫 borderRadius: rpx(8), 268e650bfb3S猫头猫 zIndex: 10011, 269e650bfb3S猫头猫 position: 'absolute', 270e650bfb3S猫头猫 opacity: 0, 271e650bfb3S猫头猫 shadowOffset: { 272e650bfb3S猫头猫 width: 0, 273e650bfb3S猫头猫 height: 2, 274e650bfb3S猫头猫 }, 275e650bfb3S猫头猫 shadowOpacity: 0.23, 276e650bfb3S猫头猫 shadowRadius: 2.62, 277e650bfb3S猫头猫 elevation: 4, 278e650bfb3S猫头猫 }, 279e650bfb3S猫头猫}); 280