yolo mode

This commit is contained in:
Samuel Newman
2025-01-14 19:37:34 +00:00
committed by Eric Bailey
parent 2c0e8136bc
commit 25b5579bb3
8 changed files with 237 additions and 5 deletions
+3
View File
@@ -272,6 +272,9 @@ func serve(cctx *cli.Context) error {
e.GET("/messages", server.WebGeneric)
e.GET("/messages/:conversation", server.WebGeneric)
// temp
e.GET("/temp-yolo", server.WebGeneric)
// profile endpoints; only first populates info
e.GET("/profile/:handleOrDID", server.WebProfile)
e.GET("/profile/:handleOrDID/follows", server.WebGeneric)
+6
View File
@@ -89,6 +89,7 @@ import {Wizard} from '#/screens/StarterPack/Wizard'
import {useTheme} from '#/alf'
import {router} from '#/routes'
import {Referrer} from '../modules/expo-bluesky-swiss-army'
import {YoloScreen} from './screens/Feeds/YoloScreen'
import {AboutSettingsScreen} from './screens/Settings/AboutSettings'
import {AccessibilitySettingsScreen} from './screens/Settings/AccessibilitySettings'
import {AccountSettingsScreen} from './screens/Settings/AccountSettings'
@@ -422,6 +423,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
getComponent={() => Wizard}
options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
/>
<Stack.Screen
name="TempYolo"
getComponent={() => YoloScreen}
options={{title: title(msg`Yolo mode`), requireAuth: true}}
/>
</>
)
}
+1 -1
View File
@@ -546,7 +546,7 @@ export function VideoModeEntranceInterstitial() {
</Text>
<Link
label={_(msg`Start watching`)}
to="/temp-thevids"
to="/temp-yolo"
size="small"
// why don't the gradient ones work?
color="secondary_inverted"
+5 -1
View File
@@ -122,7 +122,11 @@ export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
shape="square"
onPress={onPressBack}
hitSlop={HITSLOP_30}
style={[{marginLeft: -BUTTON_VISUAL_ALIGNMENT_OFFSET}, style]}
style={[
{marginLeft: -BUTTON_VISUAL_ALIGNMENT_OFFSET},
a.bg_transparent,
style,
]}
{...props}>
<ButtonIcon icon={ArrowLeft} size="lg" />
</Button>
+1
View File
@@ -57,6 +57,7 @@ export type CommonNavigatorParams = {
StarterPackShort: {code: string}
StarterPackWizard: undefined
StarterPackEdit: {rkey?: string}
TempYolo: undefined
}
export type BottomTabNavigatorParams = CommonNavigatorParams & {
+2
View File
@@ -64,4 +64,6 @@ export const router = new Router({
StarterPack: '/starter-pack/:name/:rkey',
StarterPackShort: '/starter-pack-short/:code',
StarterPackWizard: '/starter-pack/create',
// temp
TempYolo: '/temp-yolo',
})
+216
View File
@@ -0,0 +1,216 @@
import {useCallback, useEffect, useState} from 'react'
import {
ListRenderItem,
SafeAreaView,
useWindowDimensions,
View,
ViewToken,
} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {useEvent} from 'expo'
import {BlurView} from 'expo-blur'
import {useVideoPlayer, VideoPlayer, VideoView} from 'expo-video'
import {AppBskyEmbedVideo, AppBskyFeedDefs} from '@atproto/api'
import {Trans} from '@lingui/macro'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {THEVIDS_FEED_URI} from '#/lib/constants'
import {CommonNavigatorParams} from '#/lib/routes/types'
import {FeedPostSliceItem, usePostFeedQuery} from '#/state/queries/post-feed'
import {useSetMinimalShellMode} from '#/state/shell'
import {List} from '#/view/com/util/List'
import {atoms as a, useTheme} from '#/alf'
import * as Layout from '#/components/Layout'
import {ListFooter} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
export function YoloScreen({}: Props) {
const {top} = useSafeAreaInsets()
const t = useTheme()
const [headerHeight, setHeaderHeight] = useState(0)
const setMinShellMode = useSetMinimalShellMode()
useFocusEffect(
useCallback(() => {
setMinShellMode(true)
return () => {
setMinShellMode(false)
}
}, [setMinShellMode]),
)
return (
<Layout.Screen noInsetTop style={{backgroundColor: 'black'}}>
<BlurView
intensity={100}
tint={
t.scheme === 'dark' ? 'systemMaterialDark' : 'systemMaterialLight'
}
style={[
a.absolute,
a.z_10,
{top: 0, left: 0, right: 0, paddingTop: top},
]}
onLayout={({nativeEvent}) =>
setHeaderHeight(nativeEvent.layout.height)
}>
<Layout.Header.Outer>
<Layout.Header.BackButton />
<Layout.Header.Content>
<Layout.Header.TitleText>
<Trans>Yolo mode</Trans>
</Layout.Header.TitleText>
</Layout.Header.Content>
<Layout.Header.Slot />
</Layout.Header.Outer>
</BlurView>
<YoloFeed headerHeight={headerHeight} />
</Layout.Screen>
)
}
function YoloFeed({headerHeight}: {headerHeight: number}) {
const {
data,
isFetching,
refetch,
hasNextPage,
isFetchingNextPage,
fetchNextPage,
} = usePostFeedQuery(`feedgen|${THEVIDS_FEED_URI}`)
const player1 = useVideoPlayer('', p => {
p.loop = true
})
const player2 = useVideoPlayer('', p => {
p.loop = true
})
const player3 = useVideoPlayer('', p => {
p.loop = true
})
const videos = data?.pages.flatMap(page =>
page.slices.flatMap(slice => slice.items),
)
const [currentIndex, setCurrentIndex] = useState(0)
const renderItem: ListRenderItem<FeedPostSliceItem> = useCallback(
({item, index}) => {
const {post} = item
if (!post.embed || !AppBskyEmbedVideo.isView(post.embed)) {
return null
}
const player = [player1, player2, player3][index % 3]
return (
<VideoScreen
player={player}
post={post}
embed={post.embed}
loaded={Math.abs(index - currentIndex) < 2}
active={index === currentIndex}
headerHeight={headerHeight}
/>
)
},
[player1, player2, player3, currentIndex, headerHeight],
)
const onViewableItemsChanged = useCallback(
({viewableItems}: {viewableItems: ViewToken[]; changed: ViewToken[]}) => {
if (viewableItems[0] && viewableItems[0].index !== null) {
setCurrentIndex(viewableItems[0].index)
}
},
[],
)
return (
<List
data={videos}
renderItem={renderItem}
keyExtractor={keyExtractor}
pagingEnabled={true}
refreshing={isFetching}
onRefresh={refetch}
ListFooterComponent={
<ListFooter
hasNextPage={hasNextPage}
isFetchingNextPage={isFetchingNextPage}
onRetry={refetch}
/>
}
onEndReached={() => {
if (hasNextPage && !isFetchingNextPage) {
fetchNextPage()
}
}}
showsVerticalScrollIndicator={false}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={{itemVisiblePercentThreshold: 75}}
/>
)
}
function keyExtractor(item: FeedPostSliceItem) {
return item._reactKey
}
function VideoScreen({
player,
embed,
active,
loaded,
headerHeight,
}: {
player: VideoPlayer
post: AppBskyFeedDefs.PostView
embed: AppBskyEmbedVideo.View
active: boolean
loaded: boolean
headerHeight: number
}) {
const {height, width} = useWindowDimensions()
const source = embed.playlist
const sourceChangeEvent = useEvent(player, 'sourceChange') as {
// incorrect types
source: {uri?: string}
oldSource: {uri?: string}
}
useEffect(() => {
if (loaded && sourceChangeEvent?.source?.uri !== source) {
player.replace(source)
}
}, [sourceChangeEvent?.source?.uri, loaded, source, player])
useEffect(() => {
if (active) {
player.play()
}
return () => {
player.pause()
}
}, [active, player])
return (
<View
style={{
height,
width,
}}>
<SafeAreaView style={[a.flex_1, {paddingTop: headerHeight}]}>
{active && (
<VideoView
style={[a.flex_1]}
player={player}
nativeControls={false}
/>
)}
</SafeAreaView>
</View>
)
}
+3 -3
View File
@@ -152,6 +152,9 @@ let List = React.forwardRef<ListMethods, ListProps>(
return (
<FlatList_INTERNAL
showsVerticalScrollIndicator={!isAndroid} // overridable
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
{...props}
automaticallyAdjustsScrollIndicatorInsets={
automaticallyAdjustsScrollIndicatorInsets
@@ -166,9 +169,6 @@ let List = React.forwardRef<ListMethods, ListProps>(
onScroll={scrollHandler}
scrollsToTop={!activeLightbox}
scrollEventThrottle={1}
onViewableItemsChanged={onViewableItemsChanged}
viewabilityConfig={viewabilityConfig}
showsVerticalScrollIndicator={!isAndroid}
style={style}
// @ts-expect-error FlatList_INTERNAL ref type is wrong -sfn
ref={ref}