diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 363875dcb6..0596ce21a5 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -333,11 +333,10 @@ function HomeTabNavigator() { return ( HomeScreen} /> @@ -351,11 +350,10 @@ function SearchTabNavigator() { return ( SearchScreen} /> @@ -369,11 +367,10 @@ function FeedsTabNavigator() { return ( FeedsScreen} /> @@ -387,11 +384,10 @@ function NotificationsTabNavigator() { return ( { screenListeners={screenListeners} screenOptions={{ gestureEnabled: true, - fullScreenGestureEnabled: true, headerShown: false, - animationDuration: 250, + animationDuration: 350, contentStyle: pal.view, }}> + {message.text} + + ) +} + +function renderItem({item}: ListRenderItemInfo) { + return +} + +function keyExtractor(item: ClipClopInterface, index: number) { + return `${item.id}-${index}` +} + +function HeaderPlaceholder({height}: {height: number}) { + return +} + +export function ClipClopList({clipClops}: {clipClops: ClipClopInterface[]}) { + const flatlistRef = React.useRef(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; changed: Array}) => { + const lastVisibleItem = + info.viewableItems[info.viewableItems.length - 1] + const lastViewableIndex = lastVisibleItem?.index ?? -1 + + isAtBottom.current = lastViewableIndex >= totalClipClops.current - 2 + }, + { + itemVisiblePercentThreshold: 100, + minimumViewTime: 100, + }, + ] + }, []) + + return ( + + } + onViewableItemsChanged={onViewableItemsChanged} + viewabilityConfig={viewabilityConfig} + ref={flatlistRef} + onContentSizeChange={onContentSizeChange} + /> + + ) +} diff --git a/src/components/ClipClopTest/RandomClipClops.ts b/src/components/ClipClopTest/RandomClipClops.ts new file mode 100644 index 0000000000..e36e0e7f98 --- /dev/null +++ b/src/components/ClipClopTest/RandomClipClops.ts @@ -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?'", +] diff --git a/src/view/com/util/List.tsx b/src/view/com/util/List.tsx index 5729a43a52..a9e1226130 100644 --- a/src/view/com/util/List.tsx +++ b/src/view/com/util/List.tsx @@ -97,9 +97,9 @@ function ListImpl( scrollEventThrottle={1} style={style} ref={ref} - showsVerticalScrollIndicator={ - isWeb || !gate('hide_vertical_scroll_indicators') - } + // showsVerticalScrollIndicator={ + // isWeb || !gate('hide_vertical_scroll_indicators') + // } /> ) } diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 3eaa1b8757..363cfc3b23 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -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 + +/** + * 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 ( - - ) - } else { - return ( - - - - ) + const lastMessageId = React.useRef(0) + const [clipClops, setClipClops] = React.useState([]) + + 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 ( + + +