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/fancy-queue 212 lines 6.3 kB view raw
1import React, {useRef} from 'react' 2import {Pressable, StyleProp, View, ViewStyle} from 'react-native' 3import Animated, {FadeInDown} from 'react-native-reanimated' 4import {AppBskyEmbedVideo} from '@atproto/api' 5import {BlueskyVideoView} from '@haileyok/bluesky-video' 6import {msg} from '@lingui/macro' 7import {useLingui} from '@lingui/react' 8 9import {HITSLOP_30} from '#/lib/constants' 10import {useAutoplayDisabled} from '#/state/preferences' 11import {useVideoMuteState} from '#/view/com/util/post-embeds/VideoVolumeContext' 12import {atoms as a, useTheme} from '#/alf' 13import {useIsWithinMessage} from '#/components/dms/MessageContext' 14import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute' 15import {Pause_Filled_Corner0_Rounded as PauseIcon} from '#/components/icons/Pause' 16import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play' 17import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker' 18import {MediaInsetBorder} from '#/components/MediaInsetBorder' 19import {TimeIndicator} from './TimeIndicator' 20 21export const VideoEmbedInnerNative = React.forwardRef( 22 function VideoEmbedInnerNative( 23 { 24 embed, 25 setStatus, 26 setIsLoading, 27 setIsActive, 28 }: { 29 embed: AppBskyEmbedVideo.View 30 setStatus: (status: 'playing' | 'paused') => void 31 setIsLoading: (isLoading: boolean) => void 32 setIsActive: (isActive: boolean) => void 33 }, 34 ref: React.Ref<{togglePlayback: () => void}>, 35 ) { 36 const {_} = useLingui() 37 const videoRef = useRef<BlueskyVideoView>(null) 38 const autoplayDisabled = useAutoplayDisabled() 39 const isWithinMessage = useIsWithinMessage() 40 const [muted, setMuted] = useVideoMuteState() 41 42 const [isPlaying, setIsPlaying] = React.useState(false) 43 const [timeRemaining, setTimeRemaining] = React.useState(0) 44 const [error, setError] = React.useState<string>() 45 46 React.useImperativeHandle(ref, () => ({ 47 togglePlayback: () => { 48 videoRef.current?.togglePlayback() 49 }, 50 })) 51 52 if (error) { 53 throw new Error(error) 54 } 55 56 return ( 57 <View style={[a.flex_1, a.relative]}> 58 <BlueskyVideoView 59 url={embed.playlist} 60 autoplay={!autoplayDisabled && !isWithinMessage} 61 beginMuted={autoplayDisabled ? false : muted} 62 style={[a.rounded_sm]} 63 onActiveChange={e => { 64 setIsActive(e.nativeEvent.isActive) 65 }} 66 onLoadingChange={e => { 67 setIsLoading(e.nativeEvent.isLoading) 68 }} 69 onMutedChange={e => { 70 setMuted(e.nativeEvent.isMuted) 71 }} 72 onStatusChange={e => { 73 setStatus(e.nativeEvent.status) 74 setIsPlaying(e.nativeEvent.status === 'playing') 75 }} 76 onTimeRemainingChange={e => { 77 setTimeRemaining(e.nativeEvent.timeRemaining) 78 }} 79 onError={e => { 80 setError(e.nativeEvent.error) 81 }} 82 ref={videoRef} 83 accessibilityLabel={ 84 embed.alt ? _(msg`Video: ${embed.alt}`) : _(msg`Video`) 85 } 86 accessibilityHint="" 87 /> 88 <VideoControls 89 enterFullscreen={() => { 90 videoRef.current?.enterFullscreen(true) 91 }} 92 toggleMuted={() => { 93 videoRef.current?.toggleMuted() 94 }} 95 togglePlayback={() => { 96 videoRef.current?.togglePlayback() 97 }} 98 isPlaying={isPlaying} 99 timeRemaining={timeRemaining} 100 /> 101 <MediaInsetBorder /> 102 </View> 103 ) 104 }, 105) 106 107function VideoControls({ 108 enterFullscreen, 109 toggleMuted, 110 togglePlayback, 111 timeRemaining, 112 isPlaying, 113}: { 114 enterFullscreen: () => void 115 toggleMuted: () => void 116 togglePlayback: () => void 117 timeRemaining: number 118 isPlaying: boolean 119}) { 120 const {_} = useLingui() 121 const t = useTheme() 122 const [muted] = useVideoMuteState() 123 124 // show countdown when: 125 // 1. timeRemaining is a number - was seeing NaNs 126 // 2. duration is greater than 0 - means metadata has loaded 127 // 3. we're less than 5 second into the video 128 const showTime = !isNaN(timeRemaining) 129 130 return ( 131 <View style={[a.absolute, a.inset_0]}> 132 <Pressable 133 onPress={enterFullscreen} 134 style={a.flex_1} 135 accessibilityLabel={_(msg`Video`)} 136 accessibilityHint={_(msg`Tap to enter full screen`)} 137 accessibilityRole="button" 138 /> 139 <ControlButton 140 onPress={togglePlayback} 141 label={isPlaying ? _(msg`Pause`) : _(msg`Play`)} 142 accessibilityHint={_(msg`Tap to play or pause`)} 143 style={{left: 6}}> 144 {isPlaying ? ( 145 <PauseIcon width={13} fill={t.palette.white} /> 146 ) : ( 147 <PlayIcon width={13} fill={t.palette.white} /> 148 )} 149 </ControlButton> 150 {showTime && <TimeIndicator time={timeRemaining} style={{left: 33}} />} 151 152 <ControlButton 153 onPress={toggleMuted} 154 label={ 155 muted 156 ? _(msg({message: `Unmute`, context: 'video'})) 157 : _(msg({message: `Mute`, context: 'video'})) 158 } 159 accessibilityHint={_(msg`Tap to toggle sound`)} 160 style={{right: 6}}> 161 {muted ? ( 162 <MuteIcon width={13} fill={t.palette.white} /> 163 ) : ( 164 <UnmuteIcon width={13} fill={t.palette.white} /> 165 )} 166 </ControlButton> 167 </View> 168 ) 169} 170 171function ControlButton({ 172 onPress, 173 children, 174 label, 175 accessibilityHint, 176 style, 177}: { 178 onPress: () => void 179 children: React.ReactNode 180 label: string 181 accessibilityHint: string 182 style?: StyleProp<ViewStyle> 183}) { 184 return ( 185 <Animated.View 186 entering={FadeInDown.duration(300)} 187 style={[ 188 a.absolute, 189 a.rounded_full, 190 a.justify_center, 191 { 192 backgroundColor: 'rgba(0, 0, 0, 0.5)', 193 paddingHorizontal: 4, 194 paddingVertical: 4, 195 bottom: 6, 196 minHeight: 21, 197 minWidth: 21, 198 }, 199 style, 200 ]}> 201 <Pressable 202 onPress={onPress} 203 style={a.flex_1} 204 accessibilityLabel={label} 205 accessibilityHint={accessibilityHint} 206 accessibilityRole="button" 207 hitSlop={HITSLOP_30}> 208 {children} 209 </Pressable> 210 </Animated.View> 211 ) 212}