diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 49d54579f72..a096d342d4f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -606,6 +606,8 @@ PODS: - React-Core - SDWebImage (~> 5.11.1) - SDWebImageWebPCoder (~> 0.8.4) + - RNFlashList (1.4.0): + - React-Core - RNGestureHandler (2.5.0): - React-Core - RNGoogleSignin (6.0.0): @@ -823,6 +825,7 @@ DEPENDENCIES: - "RNDateTimePicker (from `../node_modules/@react-native-community/datetimepicker`)" - RNDeviceInfo (from `../node_modules/react-native-device-info`) - RNFastImage (from `../node_modules/react-native-fast-image`) + - "RNFlashList (from `../node_modules/@shopify/flash-list`)" - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)" - RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`) @@ -1064,6 +1067,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-device-info" RNFastImage: :path: "../node_modules/react-native-fast-image" + RNFlashList: + :path: "../node_modules/@shopify/flash-list" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNGoogleSignin: @@ -1241,6 +1246,7 @@ SPEC CHECKSUMS: RNDateTimePicker: 6f1f0b4cf7c71b6e2aea7a3aa62969111084bbd1 RNDeviceInfo: 3266783bcb6aa4b0c785d6080a407f8a5fc68326 RNFastImage: 1f2cab428712a4baaf78d6169eaec7f622556dd7 + RNFlashList: 399bf6a0db68f594ad2c86aaff3ea39564f39f8a RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50 RNGoogleSignin: 111fd4792913208f338fe3178005f7a22e490ff9 RNImageCropPicker: 16951bc02411f50c4d197488ed6406a23dc3b5f1 diff --git a/package.json b/package.json index 0c619e2f220..92ccf15b00b 100644 --- a/package.json +++ b/package.json @@ -123,6 +123,7 @@ "@segment/analytics-react-native-appboy": "1.5.0", "@sentry/cli": "2.7.0", "@sentry/react-native": "3.2.13", + "@shopify/flash-list": "1.4.0", "@storybook/addon-actions": "6.3.13", "@storybook/addon-controls": "6.3.13", "@storybook/addon-ondevice-actions": "6.0.1-beta.5", diff --git a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx index 757d0384ea6..166fa189040 100644 --- a/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx +++ b/src/app/Components/Artist/ArtistArtworks/ArtistArtworks.tsx @@ -1,4 +1,4 @@ -import { OwnerType } from "@artsy/cohesion" +import { MasonryFlashList, MasonryFlashListProps } from "@shopify/flash-list" import { ArtistArtworks_artist$data } from "__generated__/ArtistArtworks_artist.graphql" import { ArtworkFilterNavigator, FilterModalMode } from "app/Components/ArtworkFilter" import { Aggregations, FilterArray } from "app/Components/ArtworkFilter/ArtworkFilterHelpers" @@ -13,19 +13,24 @@ import { useArtworkFilters, useSelectedFiltersCount, } from "app/Components/ArtworkFilter/useArtworkFilters" +import ArtworkGridItem from "app/Components/ArtworkGrids/ArtworkGridItem" import { ArtworksFilterHeader } from "app/Components/ArtworkGrids/ArtworksFilterHeader" import { FilteredArtworkGridZeroState } from "app/Components/ArtworkGrids/FilteredArtworkGridZeroState" -import { - InfiniteScrollArtworksGridContainer as InfiniteScrollArtworksGrid, - Props as InfiniteScrollGridProps, -} from "app/Components/ArtworkGrids/InfiniteScrollArtworksGrid" +import { Props as InfiniteScrollGridProps } from "app/Components/ArtworkGrids/InfiniteScrollArtworksGrid" +import { PAGE_SIZE } from "app/Components/constants" +import { useNativeValue } from "app/Components/StickyTabPage/reanimatedHelpers" +import { useStickyTabPageContext } from "app/Components/StickyTabPage/StickyTabPageContext" import { StickyTabPageFlatListContext } from "app/Components/StickyTabPage/StickyTabPageFlatList" -import { StickyTabPageScrollView } from "app/Components/StickyTabPage/StickyTabPageScrollView" +import { StickyTabPageView } from "app/Components/StickyTabPage/StickyTabPageView" +import { extractNodes } from "app/utils/extractNodes" import { Schema } from "app/utils/track" -import { Box, Message, Spacer } from "palette" +import { Box, Flex, Message, useSpace } from "palette" import React, { useContext, useEffect, useState } from "react" +import { ActivityIndicator, Platform, useWindowDimensions } from "react-native" +import Animated from "react-native-reanimated" import { createPaginationContainer, graphql, RelayPaginationProp } from "react-relay" import { useTracking } from "react-tracking" +import { useScreenDimensions } from "shared/hooks" import { SavedSearchButtonV2 } from "./SavedSearchButtonV2" interface ArtworksGridProps extends InfiniteScrollGridProps { @@ -74,7 +79,7 @@ const ArtworksGrid: React.FC = ({ artist, relay, ...props }) return ( - + = ({ artist, relay, ...props }) mode={FilterModalMode.ArtistArtworks} shouldShowCreateAlertButton /> - + ) } @@ -193,19 +198,109 @@ const ArtistArtworksContainer: React.FC ) } else { + const space = useSpace() + const { width } = useScreenDimensions() + const artworkdata = extractNodes(artist.artworks) + + const fetchNextPage = () => { + if (!relay.hasMore() || relay.isLoading()) { + return + } + + relay.loadMore(PAGE_SIZE) + } + + const { height } = useWindowDimensions() + const { + headerOffsetY, + stickyHeaderHeight, + staticHeaderHeight, + staticHeaderHeightRawValue, + stickyHeaderHeightRawValue, + } = useStickyTabPageContext() + + // TODO: remaining stuff + // 1. top list inset (better way than this?) + // 2. set proper header height vs 150 + // 3. scroll behaviour down and up when should we make the header go back down? + // const staticHeaderHeightValue = useNativeValue(staticHeaderHeight!, 0) + console.warn({ staticHeaderHeightRawValue }) + + const handleOnScroll: MasonryFlashListProps["onScroll"] = ({ + nativeEvent: { + contentOffset: { y: contentOffsetY }, + }, + }) => { + console.warn("handleOnScroll START initial onscroll raw", staticHeaderHeightRawValue) + console.warn("handleOnScroll START initial onscroll", staticHeaderHeight) + let newHeaderOffset = -contentOffsetY + + if (newHeaderOffset > 0) { + newHeaderOffset = 0 + } + + if (newHeaderOffset < -staticHeaderHeightRawValue) { + newHeaderOffset = -staticHeaderHeightRawValue + } + + headerOffsetY.setValue(newHeaderOffset) + // flatlist/flashlist works while MAsonryFlashlist doesnt work 🤯 + console.warn("handleOnScroll END", newHeaderOffset, staticHeaderHeightRawValue) + } + + const stickyHeaderHeightValue = useNativeValue( + stickyHeaderHeight ?? new Animated.Value(0), + 150 + ) + const staticHeaderHeightValue = useNativeValue( + staticHeaderHeight ?? new Animated.Value(0), + 50 + ) + return ( - <> - - + { + const imgAspectRatio = item.image?.aspectRatio ?? 1 + const imgWidth = width / 2 - space(2) - space(1) + const imgHeight = imgWidth / imgAspectRatio + + return ( + + + + ) + }} + ListFooterComponent={() => + relay.isLoading() ? ( + + + + ) : null + } + onEndReachedThreshold={0.2} + onEndReached={() => { + fetchNextPage() + }} /> - + ) } } @@ -268,12 +363,22 @@ export default createPaginationContainer( edges { node { id + title + image { + url(version: "large") + aspectRatio + } + ...ArtworkGridItem_artwork } } + pageInfo { + hasNextPage + startCursor + endCursor + } counts { total } - ...InfiniteScrollArtworksGrid_connection } statuses { artworks diff --git a/src/app/Components/StickyTabPage/StickyTabPage.tsx b/src/app/Components/StickyTabPage/StickyTabPage.tsx index b2ac653e02c..3209072d890 100644 --- a/src/app/Components/StickyTabPage/StickyTabPage.tsx +++ b/src/app/Components/StickyTabPage/StickyTabPage.tsx @@ -3,7 +3,7 @@ import { useUpdateShouldHideBackButton } from "app/utils/hideBackButtonOnScroll" import { Schema } from "app/utils/track" import { useAutoCollapsingMeasuredView } from "app/utils/useAutoCollapsingMeasuredView" import { useGlobalState } from "app/utils/useGlobalState" -import { Box } from "palette" +import { Box, Text } from "palette" import React, { EffectCallback, useEffect, useMemo, useRef, useState } from "react" import { View } from "react-native" import Animated from "react-native-reanimated" @@ -50,7 +50,7 @@ interface StickyTabPageProps { */ export const StickyTabPage: React.FC = ({ tabs, - staticHeaderContent = <>, + staticHeaderContent = YOLO, stickyHeaderContent = , bottomContent, disableBackButtonUpdate, @@ -72,8 +72,11 @@ export const StickyTabPage: React.FC = ({ Array >([]) - const { jsx: staticHeader, nativeHeight: staticHeaderHeight } = - useAutoCollapsingMeasuredView(staticHeaderContent) + const { + jsx: staticHeader, + nativeHeight: staticHeaderHeight, + nativeHeightRawValue: staticHeaderHeightRawValue, + } = useAutoCollapsingMeasuredView(staticHeaderContent) const stickyRailRef = useRef(null) @@ -86,8 +89,11 @@ export const StickyTabPage: React.FC = ({ return useAutoCollapsingMeasuredView(tabSpecificStickyHeaderContent[i]) }) - const { jsx: stickyHeader, nativeHeight: stickyHeaderHeight } = - useAutoCollapsingMeasuredView(stickyHeaderContent) + const { + jsx: stickyHeader, + nativeHeight: stickyHeaderHeight, + nativeHeightRawValue: stickyHeaderHeightRawValue, + } = useAutoCollapsingMeasuredView(stickyHeaderContent) const tracking = useTracking() @@ -118,6 +124,8 @@ export const StickyTabPage: React.FC = ({ activeTabIndex, staticHeaderHeight, stickyHeaderHeight, + stickyHeaderHeightRawValue, + staticHeaderHeightRawValue, headerOffsetY, tabLabels: tabs.map((tab) => tab.title), tabVisualClues: tabs.map((tab) => tab.visualClues), diff --git a/src/app/Components/StickyTabPage/StickyTabPageContext.tsx b/src/app/Components/StickyTabPage/StickyTabPageContext.tsx index 80ce190383f..742e0b4dceb 100644 --- a/src/app/Components/StickyTabPage/StickyTabPageContext.tsx +++ b/src/app/Components/StickyTabPage/StickyTabPageContext.tsx @@ -6,6 +6,8 @@ import { TabVisualClues } from "./StickyTabPage" export const StickyTabPageContext = React.createContext<{ staticHeaderHeight: Animated.Node | null stickyHeaderHeight: Animated.Node | null + stickyHeaderHeightRawValue: number + staticHeaderHeightRawValue: number headerOffsetY: Animated.Value tabLabels: string[] tabVisualClues: Array diff --git a/src/app/Components/StickyTabPage/StickyTabPageView.tsx b/src/app/Components/StickyTabPage/StickyTabPageView.tsx new file mode 100644 index 00000000000..e462475db58 --- /dev/null +++ b/src/app/Components/StickyTabPage/StickyTabPageView.tsx @@ -0,0 +1,10 @@ +import { Flex } from "palette" +import { ReactNode } from "react" + +interface StickyTabPageViewProps { + children: ReactNode +} + +export const StickyTabPageView: React.FC = ({ children }) => { + return {children} +} diff --git a/src/app/Scenes/NewWorksForYou/NewWorksForYou.tsx b/src/app/Scenes/NewWorksForYou/NewWorksForYou.tsx index 1636e4003b3..eb9fda963e6 100644 --- a/src/app/Scenes/NewWorksForYou/NewWorksForYou.tsx +++ b/src/app/Scenes/NewWorksForYou/NewWorksForYou.tsx @@ -1,15 +1,18 @@ import { OwnerType } from "@artsy/cohesion" +import { MasonryFlashList, MasonryFlashListScrollEvent } from "@shopify/flash-list" import { NewWorksForYou_viewer$data } from "__generated__/NewWorksForYou_viewer.graphql" import { NewWorksForYouQuery } from "__generated__/NewWorksForYouQuery.graphql" import { InfiniteScrollArtworksGridContainer } from "app/Components/ArtworkGrids/InfiniteScrollArtworksGrid" import { PageWithSimpleHeader } from "app/Components/PageWithSimpleHeader" import { defaultEnvironment } from "app/relay/createEnvironment" +import { extractNodes } from "app/utils/extractNodes" import { PlaceholderGrid, ProvidePlaceholderContext } from "app/utils/placeholders" import { renderWithPlaceholder } from "app/utils/renderWithPlaceholder" import { ProvideScreenTrackingWithCohesionSchema } from "app/utils/track" import { screen } from "app/utils/track/helpers" -import { Box, SimpleMessage, Spacer } from "palette" +import { Box, OpaqueImageView, SimpleMessage, Spacer, Text, useSpace } from "palette" import { createPaginationContainer, graphql, QueryRenderer, RelayPaginationProp } from "react-relay" +import { useScreenDimensions } from "shared/hooks" const SCREEN_TITLE = "New Works for You" const PAGE_SIZE = 100 @@ -20,13 +23,18 @@ interface NewWorksForYouProps { } const NewWorksForYou: React.FC = ({ viewer }) => { + const space = useSpace() + const test = extractNodes(viewer.artworks) + const { width } = useScreenDimensions() + console.warn({ test }) + return ( - - {!!viewer.artworks?.edges?.length ? ( + {/* */} + {/* {!!viewer.artworks?.edges?.length ? ( null} @@ -40,8 +48,30 @@ const NewWorksForYou: React.FC = ({ viewer }) => { /> ) : ( Nothing yet. Please check back later. - )} - + )} */} + { + console.warn({ img: item.image?.url }) + return ( + + + {item.title} + + ) + }} + ListEmptyComponent={ + Nothing yet. Please check back later. + } + /> + {/* */} ) @@ -62,9 +92,13 @@ export const NewWorksForYouFragmentContainer = createPaginationContainer( edges { node { id + title + image { + url(version: "large") + aspectRatio + } } } - ...InfiniteScrollArtworksGrid_connection } } `, diff --git a/src/app/Websockets/auctions/useArtworkBidding.tsx b/src/app/Websockets/auctions/useArtworkBidding.tsx index 82089b38996..6fe87f2324b 100644 --- a/src/app/Websockets/auctions/useArtworkBidding.tsx +++ b/src/app/Websockets/auctions/useArtworkBidding.tsx @@ -11,9 +11,6 @@ export interface UseArtworkBiddingProps { export const useArtworkBidding = (props: UseArtworkBiddingProps) => { const { lotID, lotEndAt, biddingEndAt, onDataReceived } = props - if (!lotID) { - return { currentBiddingEndAt: null, lotSaleExtended: false } - } const biddingEndTime = biddingEndAt ?? lotEndAt const [currentBiddingEndAt, setCurrentBiddingEndAt] = useState(biddingEndTime) @@ -36,5 +33,9 @@ export const useArtworkBidding = (props: UseArtworkBiddingProps) => { }, }) + if (!lotID) { + return { currentBiddingEndAt: null, lotSaleExtended: false } + } + return { currentBiddingEndAt, lotSaleExtended } } diff --git a/src/app/Websockets/auctions/useAuctionWebsocket.tsx b/src/app/Websockets/auctions/useAuctionWebsocket.tsx index ffc1357c8d4..81dff7f5635 100644 --- a/src/app/Websockets/auctions/useAuctionWebsocket.tsx +++ b/src/app/Websockets/auctions/useAuctionWebsocket.tsx @@ -6,7 +6,7 @@ interface AuctionWebsocketData { } interface AuctionWebsocketParams { - lotID: string + lotID: string | null | undefined onChange: (data: AuctionWebsocketData) => void } diff --git a/src/app/utils/useAutoCollapsingMeasuredView.tsx b/src/app/utils/useAutoCollapsingMeasuredView.tsx index 2ffbfd5eac9..8373d725866 100644 --- a/src/app/utils/useAutoCollapsingMeasuredView.tsx +++ b/src/app/utils/useAutoCollapsingMeasuredView.tsx @@ -1,14 +1,16 @@ -import { useRef } from "react" +import { useRef, useState } from "react" import { View } from "react-native" import Animated from "react-native-reanimated" export function useAutoCollapsingMeasuredView(content: React.ReactChild | null) { + const [nativeHeightRawValue, setNativeHeightRawValue] = useState(__TEST__ ? 100 : -1) const nativeHeight = useRef>( __TEST__ ? new Animated.Value(100) : new Animated.Value(-1) ).current return { nativeHeight, + nativeHeightRawValue, jsx: ( { nativeHeight.setValue(e.nativeEvent.layout.height) + setNativeHeightRawValue(e.nativeEvent.layout.height) }} > {content} diff --git a/yarn.lock b/yarn.lock index f6b8ad03a6c..2d5c6e918c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3633,6 +3633,14 @@ xcode "3.0.1" yargs "^16.2.0" +"@shopify/flash-list@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@shopify/flash-list/-/flash-list-1.4.0.tgz#cf299486ec9a7c97b7a8b1e8b6bf144a78141ed6" + integrity sha512-PvPOyk353LuETFnNA038+QaJsAFlCQ2TYC7DHP3YnYqTX72g2BM6qLoLsPaptXKuoXX+dinOo0MbEm7HDjTy1g== + dependencies: + recyclerlistview "4.2.0" + tslib "2.4.0" + "@sideway/address@^4.1.3": version "4.1.3" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" @@ -10317,7 +10325,7 @@ lodash.compact@^3.0.1: resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5" integrity sha1-VAzjg3dFl1gHRx4WtKK6IeclbKU= -lodash.debounce@^4.0.8: +lodash.debounce@4.0.8, lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= @@ -12159,7 +12167,7 @@ prop-types@15.7.2: object-assign "^4.1.1" react-is "^16.8.1" -prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@15.8.1, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -12985,6 +12993,15 @@ recursive-readdir-sync@1.0.6: resolved "https://registry.yarnpkg.com/recursive-readdir-sync/-/recursive-readdir-sync-1.0.6.tgz#1dbf6d32f3c5bb8d3cde97a6c588d547a9e13d56" integrity sha1-Hb9tMvPFu4083pemxYjVR6nhPVY= +recyclerlistview@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/recyclerlistview/-/recyclerlistview-4.2.0.tgz#a140149aaa470c9787a1426452651934240d69ef" + integrity sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A== + dependencies: + lodash.debounce "4.0.8" + prop-types "15.8.1" + ts-object-utils "0.0.5" + redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -14616,6 +14633,11 @@ ts-node@8.4.1: source-map-support "^0.5.6" yn "^3.0.0" +ts-object-utils@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/ts-object-utils/-/ts-object-utils-0.0.5.tgz#95361cdecd7e52167cfc5e634c76345e90a26077" + integrity sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA== + ts-toolbelt@^6.1.6: version "6.15.5" resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83" @@ -14626,6 +14648,11 @@ tslib@1.10.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tslib@^1, tslib@^1.10.0, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"