yolo mode
This commit is contained in:
@@ -191,6 +191,7 @@ module.exports = function (config) {
|
|||||||
channel: UPDATES_CHANNEL,
|
channel: UPDATES_CHANNEL,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
'expo-video',
|
||||||
'expo-localization',
|
'expo-localization',
|
||||||
USE_SENTRY && [
|
USE_SENTRY && [
|
||||||
'@sentry/react-native/expo',
|
'@sentry/react-native/expo',
|
||||||
|
|||||||
@@ -272,6 +272,9 @@ func serve(cctx *cli.Context) error {
|
|||||||
e.GET("/messages", server.WebGeneric)
|
e.GET("/messages", server.WebGeneric)
|
||||||
e.GET("/messages/:conversation", server.WebGeneric)
|
e.GET("/messages/:conversation", server.WebGeneric)
|
||||||
|
|
||||||
|
// temp
|
||||||
|
e.GET("/temp-yolo", server.WebGeneric)
|
||||||
|
|
||||||
// profile endpoints; only first populates info
|
// profile endpoints; only first populates info
|
||||||
e.GET("/profile/:handleOrDID", server.WebProfile)
|
e.GET("/profile/:handleOrDID", server.WebProfile)
|
||||||
e.GET("/profile/:handleOrDID/follows", server.WebGeneric)
|
e.GET("/profile/:handleOrDID/follows", server.WebGeneric)
|
||||||
|
|||||||
@@ -145,6 +145,7 @@
|
|||||||
"expo-system-ui": "^4.0.4",
|
"expo-system-ui": "^4.0.4",
|
||||||
"expo-task-manager": "~12.0.3",
|
"expo-task-manager": "~12.0.3",
|
||||||
"expo-updates": "~0.26.10",
|
"expo-updates": "~0.26.10",
|
||||||
|
"expo-video": "^2.0.5",
|
||||||
"expo-web-browser": "~14.0.1",
|
"expo-web-browser": "~14.0.1",
|
||||||
"fast-text-encoding": "^1.0.6",
|
"fast-text-encoding": "^1.0.6",
|
||||||
"history": "^5.3.0",
|
"history": "^5.3.0",
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ import {Wizard} from '#/screens/StarterPack/Wizard'
|
|||||||
import {useTheme} from '#/alf'
|
import {useTheme} from '#/alf'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
import {Referrer} from '../modules/expo-bluesky-swiss-army'
|
import {Referrer} from '../modules/expo-bluesky-swiss-army'
|
||||||
|
import {YoloScreen} from './screens/Feeds/YoloScreen'
|
||||||
import {AboutSettingsScreen} from './screens/Settings/AboutSettings'
|
import {AboutSettingsScreen} from './screens/Settings/AboutSettings'
|
||||||
import {AccessibilitySettingsScreen} from './screens/Settings/AccessibilitySettings'
|
import {AccessibilitySettingsScreen} from './screens/Settings/AccessibilitySettings'
|
||||||
import {AccountSettingsScreen} from './screens/Settings/AccountSettings'
|
import {AccountSettingsScreen} from './screens/Settings/AccountSettings'
|
||||||
@@ -422,6 +423,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
|||||||
getComponent={() => Wizard}
|
getComponent={() => Wizard}
|
||||||
options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
|
options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
|
||||||
/>
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="TempYolo"
|
||||||
|
getComponent={() => YoloScreen}
|
||||||
|
options={{title: title(msg`Yolo mode`), requireAuth: true}}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -538,7 +538,7 @@ export function VideoModeEntranceInterstitial() {
|
|||||||
</Text>
|
</Text>
|
||||||
<Link
|
<Link
|
||||||
label={_(msg`Start watching`)}
|
label={_(msg`Start watching`)}
|
||||||
to="/temp-thevids"
|
to="/temp-yolo"
|
||||||
size="small"
|
size="small"
|
||||||
// why don't the gradient ones work?
|
// why don't the gradient ones work?
|
||||||
color="secondary_inverted"
|
color="secondary_inverted"
|
||||||
|
|||||||
@@ -122,7 +122,11 @@ export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
|
|||||||
shape="square"
|
shape="square"
|
||||||
onPress={onPressBack}
|
onPress={onPressBack}
|
||||||
hitSlop={HITSLOP_30}
|
hitSlop={HITSLOP_30}
|
||||||
style={[{marginLeft: -BUTTON_VISUAL_ALIGNMENT_OFFSET}, style]}
|
style={[
|
||||||
|
{marginLeft: -BUTTON_VISUAL_ALIGNMENT_OFFSET},
|
||||||
|
a.bg_transparent,
|
||||||
|
style,
|
||||||
|
]}
|
||||||
{...props}>
|
{...props}>
|
||||||
<ButtonIcon icon={ArrowLeft} size="lg" />
|
<ButtonIcon icon={ArrowLeft} size="lg" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export type CommonNavigatorParams = {
|
|||||||
StarterPackShort: {code: string}
|
StarterPackShort: {code: string}
|
||||||
StarterPackWizard: undefined
|
StarterPackWizard: undefined
|
||||||
StarterPackEdit: {rkey?: string}
|
StarterPackEdit: {rkey?: string}
|
||||||
|
TempYolo: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BottomTabNavigatorParams = CommonNavigatorParams & {
|
export type BottomTabNavigatorParams = CommonNavigatorParams & {
|
||||||
|
|||||||
@@ -64,4 +64,6 @@ export const router = new Router({
|
|||||||
StarterPack: '/starter-pack/:name/:rkey',
|
StarterPack: '/starter-pack/:name/:rkey',
|
||||||
StarterPackShort: '/starter-pack-short/:code',
|
StarterPackShort: '/starter-pack-short/:code',
|
||||||
StarterPackWizard: '/starter-pack/create',
|
StarterPackWizard: '/starter-pack/create',
|
||||||
|
// temp
|
||||||
|
TempYolo: '/temp-yolo',
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -152,6 +152,9 @@ let List = React.forwardRef<ListMethods, ListProps>(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FlatList_INTERNAL
|
<FlatList_INTERNAL
|
||||||
|
showsVerticalScrollIndicator={!isAndroid} // overridable
|
||||||
|
onViewableItemsChanged={onViewableItemsChanged}
|
||||||
|
viewabilityConfig={viewabilityConfig}
|
||||||
{...props}
|
{...props}
|
||||||
automaticallyAdjustsScrollIndicatorInsets={
|
automaticallyAdjustsScrollIndicatorInsets={
|
||||||
automaticallyAdjustsScrollIndicatorInsets
|
automaticallyAdjustsScrollIndicatorInsets
|
||||||
@@ -166,9 +169,6 @@ let List = React.forwardRef<ListMethods, ListProps>(
|
|||||||
onScroll={scrollHandler}
|
onScroll={scrollHandler}
|
||||||
scrollsToTop={!activeLightbox}
|
scrollsToTop={!activeLightbox}
|
||||||
scrollEventThrottle={1}
|
scrollEventThrottle={1}
|
||||||
onViewableItemsChanged={onViewableItemsChanged}
|
|
||||||
viewabilityConfig={viewabilityConfig}
|
|
||||||
showsVerticalScrollIndicator={!isAndroid}
|
|
||||||
style={style}
|
style={style}
|
||||||
// @ts-expect-error FlatList_INTERNAL ref type is wrong -sfn
|
// @ts-expect-error FlatList_INTERNAL ref type is wrong -sfn
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
|||||||
@@ -10688,6 +10688,11 @@ expo-updates@~0.26.10:
|
|||||||
ignore "^5.3.1"
|
ignore "^5.3.1"
|
||||||
resolve-from "^5.0.0"
|
resolve-from "^5.0.0"
|
||||||
|
|
||||||
|
expo-video@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/expo-video/-/expo-video-2.0.5.tgz#5c5311b0a20dcb7897d06cd4f9d7fb0ce13711d9"
|
||||||
|
integrity sha512-K5Q4bFKtYq0wEC38mckWUYeaTXsmhl6duidhSdbA63VBy6cwxDOk8uPsFPTQD3FXKJg6wFB0z8ZUASSPuUaY5A==
|
||||||
|
|
||||||
expo-web-browser@~14.0.1:
|
expo-web-browser@~14.0.1:
|
||||||
version "14.0.1"
|
version "14.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-14.0.1.tgz#97f3f141b0897364bc8364d90d6e29df0beec8aa"
|
resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-14.0.1.tgz#97f3f141b0897364bc8364d90d6e29df0beec8aa"
|
||||||
|
|||||||
Reference in New Issue
Block a user