some testing
This commit is contained in:
+11
-17
@@ -333,11 +333,10 @@ function HomeTabNavigator() {
|
||||
return (
|
||||
<HomeTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
animation: isAndroid ? 'none' : 'ios',
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<HomeTab.Screen name="Home" getComponent={() => HomeScreen} />
|
||||
@@ -351,11 +350,10 @@ function SearchTabNavigator() {
|
||||
return (
|
||||
<SearchTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
animation: isAndroid ? 'none' : 'ios',
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<SearchTab.Screen name="Search" getComponent={() => SearchScreen} />
|
||||
@@ -369,11 +367,10 @@ function FeedsTabNavigator() {
|
||||
return (
|
||||
<FeedsTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
animation: isAndroid ? 'none' : 'ios',
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<FeedsTab.Screen name="Feeds" getComponent={() => FeedsScreen} />
|
||||
@@ -387,11 +384,10 @@ function NotificationsTabNavigator() {
|
||||
return (
|
||||
<NotificationsTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
animation: isAndroid ? 'none' : 'ios',
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<NotificationsTab.Screen
|
||||
@@ -409,11 +405,10 @@ function MyProfileTabNavigator() {
|
||||
return (
|
||||
<MyProfileTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
animation: isAndroid ? 'none' : 'ios',
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<MyProfileTab.Screen
|
||||
@@ -444,9 +439,8 @@ const FlatNavigator = () => {
|
||||
screenListeners={screenListeners}
|
||||
screenOptions={{
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
animationDuration: 350,
|
||||
contentStyle: pal.view,
|
||||
}}>
|
||||
<Flat.Screen
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
FlatList,
|
||||
LayoutChangeEvent,
|
||||
ListRenderItemInfo,
|
||||
View,
|
||||
ViewToken,
|
||||
} from 'react-native'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {ClipClop as ClipClopInterface} from '#/components/ClipClopTest/RandomClipClops'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
function ClipClop({message}: {message: ClipClopInterface}) {
|
||||
const t = useTheme()
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.px_md,
|
||||
a.py_md,
|
||||
a.my_md,
|
||||
{
|
||||
backgroundColor: t.palette.primary_500,
|
||||
maxWidth: '50%',
|
||||
borderRadius: 10,
|
||||
},
|
||||
]}>
|
||||
<Text style={{lineHeight: 1.2}}>{message.text}</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function renderItem({item}: ListRenderItemInfo<ClipClopInterface>) {
|
||||
return <ClipClop message={item} />
|
||||
}
|
||||
|
||||
function keyExtractor(item: ClipClopInterface, index: number) {
|
||||
return `${item.id}-${index}`
|
||||
}
|
||||
|
||||
function HeaderPlaceholder({height}: {height: number}) {
|
||||
return <View style={{height}} />
|
||||
}
|
||||
|
||||
export function ClipClopList({clipClops}: {clipClops: ClipClopInterface[]}) {
|
||||
const flatlistRef = React.useRef<FlatList>(null)
|
||||
const contentHeight = React.useRef(0)
|
||||
|
||||
const totalClipClops = React.useRef(0)
|
||||
|
||||
const isAtBottom = React.useRef(true)
|
||||
const [placeholderHeight, setPlaceholderHeight] = React.useState(0)
|
||||
|
||||
// This creates a placeholder that adjusts with the whitespace above the last chat item
|
||||
const onScreenLayout = React.useCallback((e: LayoutChangeEvent) => {
|
||||
setPlaceholderHeight(e.nativeEvent.layout.height)
|
||||
}, [])
|
||||
|
||||
const onContentSizeChange = React.useCallback(
|
||||
(_: number, height: number) => {
|
||||
if (isAtBottom.current) {
|
||||
flatlistRef.current?.scrollToOffset({offset: height, animated: true})
|
||||
}
|
||||
|
||||
contentHeight.current = height
|
||||
totalClipClops.current = clipClops.length
|
||||
},
|
||||
[clipClops],
|
||||
)
|
||||
|
||||
const [onViewableItemsChanged, viewabilityConfig] = React.useMemo(() => {
|
||||
return [
|
||||
(info: {viewableItems: Array<ViewToken>; changed: Array<ViewToken>}) => {
|
||||
const lastVisibleItem =
|
||||
info.viewableItems[info.viewableItems.length - 1]
|
||||
const lastViewableIndex = lastVisibleItem?.index ?? -1
|
||||
|
||||
isAtBottom.current = lastViewableIndex >= totalClipClops.current - 2
|
||||
},
|
||||
{
|
||||
itemVisiblePercentThreshold: 100,
|
||||
minimumViewTime: 100,
|
||||
},
|
||||
]
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<View style={{flex: 1}} onLayout={onScreenLayout}>
|
||||
<FlatList
|
||||
data={clipClops}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={keyExtractor}
|
||||
// maintainVisibleContentPosition={{
|
||||
// minIndexForVisible: 0,
|
||||
// }}
|
||||
// ListHeaderComponent={<HeaderPlaceholder height={placeholderHeight} />}
|
||||
onViewableItemsChanged={onViewableItemsChanged}
|
||||
viewabilityConfig={viewabilityConfig}
|
||||
ref={flatlistRef}
|
||||
onContentSizeChange={onContentSizeChange}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import {AppBskyEmbedRecord, AppBskyRichtextFacet} from '@atproto/api'
|
||||
|
||||
export interface ClipClop {
|
||||
id: string
|
||||
text: string
|
||||
facets?: AppBskyRichtextFacet.Main[]
|
||||
embed?: AppBskyEmbedRecord.Main | {$type: string; [k: string]: unknown}
|
||||
[k: string]: unknown
|
||||
}
|
||||
|
||||
export const placeholderClops = [
|
||||
'When horses clip-clop in sync, is it considered a hoofbeat remix?',
|
||||
'Ever heard a horse go clip-clop in flip flops?',
|
||||
'Clip clop! That’s just my horse tap-dancing in the kitchen.',
|
||||
'Why did the horse clip-clop into the bar? Because it couldn’t find the neigh-borhood pub!',
|
||||
"A horse's clip-clop is just their way of laying down a sick beat.",
|
||||
'Is it still clip-clop if the horse is wearing sneakers?',
|
||||
"If a horse clip-clops in the forest and no one's around, does it still make a sound?",
|
||||
"I told my horse to stop the clip-clop but he just wouldn't hoof it!",
|
||||
"The horse's clip-clop was so loud, it started its own podcast!",
|
||||
'Clip clop goes the horse, trotting into the comedy club for open mic night.',
|
||||
'Do horses practice clip-clopping, or are they just naturally that cloggy?',
|
||||
'When the horse clip-clops backwards, is it called clop-clip?',
|
||||
"A horse walks into a cafe. The barista says, 'Why the loud clip-clop?' The horse says, 'I like my coffee hoof-brewed.'",
|
||||
"I asked the horse why it clip-clops, and it said, 'To keep my hooves in clop-top shape!'",
|
||||
'Clip-clop in the streets, neigh in the sheets.',
|
||||
'Horses clip-clop to keep their hooves from going clippity-flop.',
|
||||
"Clip clop, clip clop, that's just my horse walking in stilettos.",
|
||||
'Did the horse clip-clop over the bridge because it wanted to stirrup some trouble?',
|
||||
'If a unicorn clip-clops, does it sound like a sparkle?',
|
||||
'When a horse clip-clops on a tiled floor, is it just practicing for its moonwalk audition?',
|
||||
"A horse's clip-clop is just prehistoric tap dancing.",
|
||||
'Clip clop? More like hip hop when my horse starts dancing!',
|
||||
"Who needs a metronome when you have a horse's clip-clop?",
|
||||
'Clip-clop chaos: when multiple horses decide to start a flash mob.',
|
||||
'The only thing my horse clip-clops for is a hoof-full of treats.',
|
||||
'If a horse could DJ, would it remix the clip-clop?',
|
||||
'What do you call a horse that can clip-clop and whistle? A multi-talented showoff!',
|
||||
'Why do horses clip-clop? Because galloping is just too mainstream.',
|
||||
'Every horse’s clip-clop is just a step away from a full-blown musical.',
|
||||
'Can a horse clip-clop on water? Only if it doesn’t want to get its hooves wet.',
|
||||
'Clip clop, clip clop, is that a horse or someone in high heels?',
|
||||
'The only clip-clop my horse does is when he’s late for dinner.',
|
||||
"Clip clop goes the horse, sounding like he's got a new pair of boots.",
|
||||
'When a knight’s horse clip-clops, is it just medieval rock music?',
|
||||
'If a horse could talk, it would probably complain about the clip-clop stereotype.',
|
||||
"Clip clop is just the horse’s way of saying, 'I’m walking here!'",
|
||||
"When the horse heard clip-clop, it thought, 'Hey, that’s my line!'",
|
||||
'Can a horse do a clip-clop remix with a cowbell for extra flair?',
|
||||
'Why did the horse clip-clop to the beat? Because it had rhythm in its hooves!',
|
||||
'Is it really clip-clop if the horse is just trying to sneak into the kitchen?',
|
||||
"A horse clip-clops into a grocery store: 'I’m just here for the carrots.'",
|
||||
'If a horse clip-clops in slippers, does it make a sound?',
|
||||
'The horse’s clip-clop was louder than my last concert.',
|
||||
'Clip-clop or not, my horse prefers to moonwalk.',
|
||||
'Horses that clip-clop are just trying to keep the beat alive.',
|
||||
'When you hear clip-clop, remember, it might just be a horse in disguise.',
|
||||
'What’s louder: a horse’s clip-clop or my dad’s snoring?',
|
||||
'Clip-clop: the original horse-powered beat.',
|
||||
'Do zebras clip-clop, or is it more of a zebra-crossing sound?',
|
||||
"Clip-clop is just horse for 'where's my hay?'",
|
||||
]
|
||||
@@ -97,9 +97,9 @@ function ListImpl<ItemT>(
|
||||
scrollEventThrottle={1}
|
||||
style={style}
|
||||
ref={ref}
|
||||
showsVerticalScrollIndicator={
|
||||
isWeb || !gate('hide_vertical_scroll_indicators')
|
||||
}
|
||||
// showsVerticalScrollIndicator={
|
||||
// isWeb || !gate('hide_vertical_scroll_indicators')
|
||||
// }
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
+67
-18
@@ -1,5 +1,11 @@
|
||||
import React from 'react'
|
||||
import {ActivityIndicator, AppState, StyleSheet, View} from 'react-native'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
AppState,
|
||||
Button,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {useFocusEffect} from '@react-navigation/native'
|
||||
|
||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
||||
@@ -26,28 +32,71 @@ import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
|
||||
import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
|
||||
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
|
||||
import {CenteredView} from 'view/com/util/Views'
|
||||
import {ClipClopList} from '#/components/ClipClopTest/ClipClopList'
|
||||
import {
|
||||
ClipClop,
|
||||
placeholderClops,
|
||||
} from '#/components/ClipClopTest/RandomClipClops'
|
||||
import {HomeHeader} from '../com/home/HomeHeader'
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* - If we are scrolled to the bottom of the page, then the items get added correctly. The screen stays at the bottom
|
||||
* as we'd expect
|
||||
*
|
||||
*/
|
||||
|
||||
export function HomeScreen(props: Props) {
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
const {data: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
|
||||
usePinnedFeedsInfos()
|
||||
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
|
||||
return (
|
||||
<HomeScreenReady
|
||||
{...props}
|
||||
preferences={preferences}
|
||||
pinnedFeedInfos={pinnedFeedInfos}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<View style={styles.loading}>
|
||||
<ActivityIndicator size="large" />
|
||||
</View>
|
||||
)
|
||||
const lastMessageId = React.useRef(0)
|
||||
const [clipClops, setClipClops] = React.useState<ClipClop[]>([])
|
||||
|
||||
const addMessage = () => {
|
||||
lastMessageId.current += 1
|
||||
|
||||
setClipClops(prev => {
|
||||
return [
|
||||
...prev,
|
||||
|
||||
{
|
||||
id: lastMessageId.current.toString(),
|
||||
text: `${
|
||||
placeholderClops[lastMessageId.current % placeholderClops.length]
|
||||
}`,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
const addMessages = (count: number) => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
addMessage()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<CenteredView style={{flex: 1, marginBottom: 100}}>
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
<Button
|
||||
title="Add One"
|
||||
onPress={() => {
|
||||
addMessages(1)
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
title="Add Five"
|
||||
onPress={() => {
|
||||
addMessages(5)
|
||||
}}
|
||||
/>
|
||||
<Button title="Reset" onPress={() => setClipClops([])} />
|
||||
</View>
|
||||
<ClipClopList clipClops={clipClops} />
|
||||
</CenteredView>
|
||||
)
|
||||
}
|
||||
|
||||
function HomeScreenReady({
|
||||
|
||||
Reference in New Issue
Block a user