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 samuel/exp-cli 224 lines 5.7 kB view raw
1import React from 'react' 2import { 3 Pressable, 4 type StyleProp, 5 StyleSheet, 6 TouchableOpacity, 7 View, 8 type ViewStyle, 9} from 'react-native' 10import {msg, Trans} from '@lingui/macro' 11import {useLingui} from '@lingui/react' 12 13import {HITSLOP_20} from '#/lib/constants' 14import {type EmbedPlayerParams} from '#/lib/strings/embed-player' 15import {isWeb} from '#/platform/detection' 16import {useAutoplayDisabled} from '#/state/preferences' 17import {useLargeAltBadgeEnabled} from '#/state/preferences/large-alt-badge' 18import {atoms as a, useTheme} from '#/alf' 19import {Fill} from '#/components/Fill' 20import {Loader} from '#/components/Loader' 21import * as Prompt from '#/components/Prompt' 22import {Text} from '#/components/Typography' 23import {PlayButtonIcon} from '#/components/video/PlayButtonIcon' 24import {GifView} from '../../../../../modules/expo-bluesky-gif-view' 25import {type GifViewStateChangeEvent} from '../../../../../modules/expo-bluesky-gif-view/src/GifView.types' 26 27function PlaybackControls({ 28 onPress, 29 isPlaying, 30 isLoaded, 31}: { 32 onPress: () => void 33 isPlaying: boolean 34 isLoaded: boolean 35}) { 36 const {_} = useLingui() 37 const t = useTheme() 38 39 return ( 40 <Pressable 41 accessibilityRole="button" 42 accessibilityHint={_(msg`Plays or pauses the GIF`)} 43 accessibilityLabel={isPlaying ? _(msg`Pause`) : _(msg`Play`)} 44 style={[ 45 a.absolute, 46 a.align_center, 47 a.justify_center, 48 !isLoaded && a.border, 49 t.atoms.border_contrast_medium, 50 a.inset_0, 51 a.w_full, 52 a.h_full, 53 { 54 zIndex: 2, 55 backgroundColor: !isLoaded 56 ? t.atoms.bg_contrast_25.backgroundColor 57 : undefined, 58 }, 59 ]} 60 onPress={onPress}> 61 {!isLoaded ? ( 62 <View> 63 <View style={[a.align_center, a.justify_center]}> 64 <Loader size="xl" /> 65 </View> 66 </View> 67 ) : !isPlaying ? ( 68 <PlayButtonIcon /> 69 ) : undefined} 70 </Pressable> 71 ) 72} 73 74export function GifEmbed({ 75 params, 76 thumb, 77 altText, 78 isPreferredAltText, 79 hideAlt, 80 style = {width: '100%'}, 81}: { 82 params: EmbedPlayerParams 83 thumb: string | undefined 84 altText: string 85 isPreferredAltText: boolean 86 hideAlt?: boolean 87 style?: StyleProp<ViewStyle> 88}) { 89 const t = useTheme() 90 const {_} = useLingui() 91 const autoplayDisabled = useAutoplayDisabled() 92 93 const playerRef = React.useRef<GifView>(null) 94 95 const [playerState, setPlayerState] = React.useState<{ 96 isPlaying: boolean 97 isLoaded: boolean 98 }>({ 99 isPlaying: !autoplayDisabled, 100 isLoaded: false, 101 }) 102 103 const onPlayerStateChange = React.useCallback( 104 (e: GifViewStateChangeEvent) => { 105 setPlayerState(e.nativeEvent) 106 }, 107 [], 108 ) 109 110 const onPress = React.useCallback(() => { 111 playerRef.current?.toggleAsync() 112 }, []) 113 114 return ( 115 <View 116 style={[ 117 a.rounded_md, 118 a.overflow_hidden, 119 a.border, 120 t.atoms.border_contrast_low, 121 {aspectRatio: params.dimensions!.width / params.dimensions!.height}, 122 style, 123 ]}> 124 <View 125 style={[ 126 a.absolute, 127 /* 128 * Aspect ratio was being clipped weirdly on web -esb 129 */ 130 { 131 top: -2, 132 bottom: -2, 133 left: -2, 134 right: -2, 135 }, 136 ]}> 137 <PlaybackControls 138 onPress={onPress} 139 isPlaying={playerState.isPlaying} 140 isLoaded={playerState.isLoaded} 141 /> 142 <GifView 143 source={params.playerUri} 144 placeholderSource={thumb} 145 style={[a.flex_1]} 146 autoplay={!autoplayDisabled} 147 onPlayerStateChange={onPlayerStateChange} 148 ref={playerRef} 149 accessibilityHint={_(msg`Animated GIF`)} 150 accessibilityLabel={altText} 151 /> 152 {!playerState.isPlaying && ( 153 <Fill 154 style={[ 155 t.name === 'light' ? t.atoms.bg_contrast_975 : t.atoms.bg, 156 { 157 opacity: 0.3, 158 }, 159 ]} 160 /> 161 )} 162 {!hideAlt && isPreferredAltText && <AltText text={altText} />} 163 </View> 164 </View> 165 ) 166} 167 168function AltText({text}: {text: string}) { 169 const control = Prompt.usePromptControl() 170 const largeAltBadge = useLargeAltBadgeEnabled() 171 172 const {_} = useLingui() 173 return ( 174 <> 175 <TouchableOpacity 176 testID="altTextButton" 177 accessibilityRole="button" 178 accessibilityLabel={_(msg`Show alt text`)} 179 accessibilityHint="" 180 hitSlop={HITSLOP_20} 181 onPress={control.open} 182 style={styles.altContainer}> 183 <Text 184 style={[styles.alt, largeAltBadge && a.text_xs]} 185 accessible={false}> 186 <Trans>ALT</Trans> 187 </Text> 188 </TouchableOpacity> 189 <Prompt.Outer control={control}> 190 <Prompt.TitleText> 191 <Trans>Alt Text</Trans> 192 </Prompt.TitleText> 193 <Prompt.DescriptionText selectable>{text}</Prompt.DescriptionText> 194 <Prompt.Actions> 195 <Prompt.Action 196 onPress={() => control.close()} 197 cta={_(msg`Close`)} 198 color="secondary" 199 /> 200 </Prompt.Actions> 201 </Prompt.Outer> 202 </> 203 ) 204} 205 206const styles = StyleSheet.create({ 207 altContainer: { 208 backgroundColor: 'rgba(0, 0, 0, 0.75)', 209 borderRadius: 6, 210 paddingHorizontal: isWeb ? 8 : 6, 211 paddingVertical: isWeb ? 6 : 3, 212 position: 'absolute', 213 // Related to margin/gap hack. This keeps the alt label in the same position 214 // on all platforms 215 right: isWeb ? 8 : 5, 216 bottom: isWeb ? 8 : 5, 217 zIndex: 2, 218 }, 219 alt: { 220 color: 'white', 221 fontSize: isWeb ? 10 : 7, 222 fontWeight: '600', 223 }, 224})