mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at verify-intent 323 lines 9.0 kB view raw
1import React, {useImperativeHandle} from 'react' 2import { 3 Dimensions, 4 Keyboard, 5 Pressable, 6 StyleProp, 7 View, 8 ViewStyle, 9} from 'react-native' 10import Animated, {useAnimatedStyle} from 'react-native-reanimated' 11import {useSafeAreaInsets} from 'react-native-safe-area-context' 12import BottomSheet, { 13 BottomSheetBackdropProps, 14 BottomSheetFlatList, 15 BottomSheetFlatListMethods, 16 BottomSheetScrollView, 17 BottomSheetScrollViewMethods, 18 BottomSheetTextInput, 19 BottomSheetView, 20 useBottomSheet, 21 WINDOW_HEIGHT, 22} from '@discord/bottom-sheet/src' 23import {BottomSheetFlatListProps} from '@discord/bottom-sheet/src/components/bottomSheetScrollable/types' 24 25import {logger} from '#/logger' 26import {useDialogStateControlContext} from '#/state/dialogs' 27import {atoms as a, flatten, useTheme} from '#/alf' 28import {Context} from '#/components/Dialog/context' 29import { 30 DialogControlProps, 31 DialogInnerProps, 32 DialogOuterProps, 33} from '#/components/Dialog/types' 34import {createInput} from '#/components/forms/TextField' 35import {FullWindowOverlay} from '#/components/FullWindowOverlay' 36import {Portal} from '#/components/Portal' 37 38export {useDialogContext, useDialogControl} from '#/components/Dialog/context' 39export * from '#/components/Dialog/types' 40export * from '#/components/Dialog/utils' 41// @ts-ignore 42export const Input = createInput(BottomSheetTextInput) 43 44function Backdrop(props: BottomSheetBackdropProps) { 45 const t = useTheme() 46 const bottomSheet = useBottomSheet() 47 48 const animatedStyle = useAnimatedStyle(() => { 49 const opacity = 50 (Math.abs(WINDOW_HEIGHT - props.animatedPosition.value) - 50) / 1000 51 52 return { 53 opacity: Math.min(Math.max(opacity, 0), 0.55), 54 } 55 }) 56 57 const onPress = React.useCallback(() => { 58 bottomSheet.close() 59 }, [bottomSheet]) 60 61 return ( 62 <Animated.View 63 style={[ 64 t.atoms.bg_contrast_300, 65 { 66 top: 0, 67 left: 0, 68 right: 0, 69 bottom: 0, 70 position: 'absolute', 71 }, 72 animatedStyle, 73 ]}> 74 <Pressable 75 accessibilityRole="button" 76 accessibilityLabel="Dialog backdrop" 77 accessibilityHint="Press the backdrop to close the dialog" 78 style={{flex: 1}} 79 onPress={onPress} 80 /> 81 </Animated.View> 82 ) 83} 84 85export function Outer({ 86 children, 87 control, 88 onClose, 89 nativeOptions, 90 testID, 91}: React.PropsWithChildren<DialogOuterProps>) { 92 const t = useTheme() 93 const sheet = React.useRef<BottomSheet>(null) 94 const sheetOptions = nativeOptions?.sheet || {} 95 const hasSnapPoints = !!sheetOptions.snapPoints 96 const insets = useSafeAreaInsets() 97 const closeCallbacks = React.useRef<(() => void)[]>([]) 98 const {setDialogIsOpen} = useDialogStateControlContext() 99 100 /* 101 * Used to manage open/closed, but index is otherwise handled internally by `BottomSheet` 102 */ 103 const [openIndex, setOpenIndex] = React.useState(-1) 104 105 /* 106 * `openIndex` is the index of the snap point to open the bottom sheet to. If >0, the bottom sheet is open. 107 */ 108 const isOpen = openIndex > -1 109 110 const callQueuedCallbacks = React.useCallback(() => { 111 for (const cb of closeCallbacks.current) { 112 try { 113 cb() 114 } catch (e: any) { 115 logger.error('Error running close callback', e) 116 } 117 } 118 119 closeCallbacks.current = [] 120 }, []) 121 122 const open = React.useCallback<DialogControlProps['open']>( 123 ({index} = {}) => { 124 // Run any leftover callbacks that might have been queued up before calling `.open()` 125 callQueuedCallbacks() 126 127 setDialogIsOpen(control.id, true) 128 // can be set to any index of `snapPoints`, but `0` is the first i.e. "open" 129 setOpenIndex(index || 0) 130 sheet.current?.snapToIndex(index || 0) 131 }, 132 [setDialogIsOpen, control.id, callQueuedCallbacks], 133 ) 134 135 // This is the function that we call when we want to dismiss the dialog. 136 const close = React.useCallback<DialogControlProps['close']>(cb => { 137 if (typeof cb === 'function') { 138 closeCallbacks.current.push(cb) 139 } 140 sheet.current?.close() 141 }, []) 142 143 // This is the actual thing we are doing once we "confirm" the dialog. We want the dialog's close animation to 144 // happen before we run this. It is passed to the `BottomSheet` component. 145 const onCloseAnimationComplete = React.useCallback(() => { 146 // This removes the dialog from our list of stored dialogs. Not super necessary on iOS, but on Android this 147 // tells us that we need to toggle the accessibility overlay setting 148 setDialogIsOpen(control.id, false) 149 setOpenIndex(-1) 150 151 callQueuedCallbacks() 152 onClose?.() 153 }, [callQueuedCallbacks, control.id, onClose, setDialogIsOpen]) 154 155 useImperativeHandle( 156 control.ref, 157 () => ({ 158 open, 159 close, 160 }), 161 [open, close], 162 ) 163 164 React.useEffect(() => { 165 return () => { 166 setDialogIsOpen(control.id, false) 167 } 168 }, [control.id, setDialogIsOpen]) 169 170 const context = React.useMemo(() => ({close}), [close]) 171 172 return ( 173 isOpen && ( 174 <Portal> 175 <FullWindowOverlay> 176 <View 177 // iOS 178 accessibilityViewIsModal 179 // Android 180 importantForAccessibility="yes" 181 style={[a.absolute, a.inset_0]} 182 testID={testID} 183 onTouchMove={() => Keyboard.dismiss()}> 184 <BottomSheet 185 enableDynamicSizing={!hasSnapPoints} 186 enablePanDownToClose 187 keyboardBehavior="interactive" 188 android_keyboardInputMode="adjustResize" 189 keyboardBlurBehavior="restore" 190 topInset={insets.top} 191 {...sheetOptions} 192 snapPoints={sheetOptions.snapPoints || ['100%']} 193 ref={sheet} 194 index={openIndex} 195 backgroundStyle={{backgroundColor: 'transparent'}} 196 backdropComponent={Backdrop} 197 handleIndicatorStyle={{backgroundColor: t.palette.primary_500}} 198 handleStyle={{display: 'none'}} 199 onClose={onCloseAnimationComplete}> 200 <Context.Provider value={context}> 201 <View 202 style={[ 203 a.absolute, 204 a.inset_0, 205 t.atoms.bg, 206 { 207 borderTopLeftRadius: 40, 208 borderTopRightRadius: 40, 209 height: Dimensions.get('window').height * 2, 210 }, 211 ]} 212 /> 213 {children} 214 </Context.Provider> 215 </BottomSheet> 216 </View> 217 </FullWindowOverlay> 218 </Portal> 219 ) 220 ) 221} 222 223export function Inner({children, style}: DialogInnerProps) { 224 const insets = useSafeAreaInsets() 225 return ( 226 <BottomSheetView 227 style={[ 228 a.py_xl, 229 a.px_xl, 230 { 231 paddingTop: 40, 232 borderTopLeftRadius: 40, 233 borderTopRightRadius: 40, 234 paddingBottom: insets.bottom + a.pb_5xl.paddingBottom, 235 }, 236 flatten(style), 237 ]}> 238 {children} 239 </BottomSheetView> 240 ) 241} 242 243export const ScrollableInner = React.forwardRef< 244 BottomSheetScrollViewMethods, 245 DialogInnerProps 246>(function ScrollableInner({children, style}, ref) { 247 const insets = useSafeAreaInsets() 248 return ( 249 <BottomSheetScrollView 250 keyboardShouldPersistTaps="handled" 251 style={[ 252 a.flex_1, // main diff is this 253 a.p_xl, 254 a.h_full, 255 { 256 paddingTop: 40, 257 borderTopLeftRadius: 40, 258 borderTopRightRadius: 40, 259 }, 260 style, 261 ]} 262 contentContainerStyle={a.pb_4xl} 263 ref={ref}> 264 {children} 265 <View style={{height: insets.bottom + a.pt_5xl.paddingTop}} /> 266 </BottomSheetScrollView> 267 ) 268}) 269 270export const InnerFlatList = React.forwardRef< 271 BottomSheetFlatListMethods, 272 BottomSheetFlatListProps<any> & {webInnerStyle?: StyleProp<ViewStyle>} 273>(function InnerFlatList({style, contentContainerStyle, ...props}, ref) { 274 const insets = useSafeAreaInsets() 275 276 return ( 277 <BottomSheetFlatList 278 keyboardShouldPersistTaps="handled" 279 contentContainerStyle={[a.pb_4xl, flatten(contentContainerStyle)]} 280 ListFooterComponent={ 281 <View style={{height: insets.bottom + a.pt_5xl.paddingTop}} /> 282 } 283 ref={ref} 284 {...props} 285 style={[ 286 a.flex_1, 287 a.p_xl, 288 a.pt_0, 289 a.h_full, 290 { 291 marginTop: 40, 292 }, 293 flatten(style), 294 ]} 295 /> 296 ) 297}) 298 299export function Handle() { 300 const t = useTheme() 301 302 return ( 303 <View style={[a.absolute, a.w_full, a.align_center, a.z_10, {height: 40}]}> 304 <View 305 style={[ 306 a.rounded_sm, 307 { 308 top: a.pt_lg.paddingTop, 309 width: 35, 310 height: 4, 311 alignSelf: 'center', 312 backgroundColor: t.palette.contrast_900, 313 opacity: 0.5, 314 }, 315 ]} 316 /> 317 </View> 318 ) 319} 320 321export function Close() { 322 return null 323}