Skip to content

Commit

Permalink
Revert "Revert "NFT lightbox on mobile (#2460)" (#2469)"
Browse files Browse the repository at this point in the history
This reverts commit 8a7866b.
  • Loading branch information
Rohan-cp committed May 16, 2024
1 parent 8a7866b commit 99b6317
Show file tree
Hide file tree
Showing 8 changed files with 552 additions and 297 deletions.
33 changes: 18 additions & 15 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,73 @@
"@react-navigation/material-top-tabs": "^6.6.0",
"@react-navigation/native": "^6.1.4",
"@react-navigation/native-stack": "^6.9.10",
"@sentry/react-native": "5.19.1",
"@sentry/react-native": "~5.20.0",
"@shopify/flash-list": "1.6.3",
"@types/node": "20.11.16",
"@walletconnect/modal-react-native": "^1.0.0-rc.10",
"clsx": "^1.2.1",
"date-fns": "^2.29.3",
"dotenv": "^16.0.3",
"ethers": "6.11.1",
"expo": "^50.0.17",
"expo-application": "~5.8.3",
"expo-application": "~5.8.4",
"expo-asset": "~9.0.2",
"expo-av": "~13.10.5",
"expo-av": "~13.10.6",
"expo-barcode-scanner": "~12.9.3",
"expo-blur": "~12.9.2",
"expo-build-properties": "^0.11.1",
"expo-constants": "~15.4.5",
"expo-constants": "~15.4.6",
"expo-crypto": "~12.8.1",
"expo-dev-client": "~3.3.9",
"expo-device": "~5.9.3",
"expo-file-system": "~16.0.8",
"expo-dev-client": "~3.3.11",
"expo-device": "~5.9.4",
"expo-file-system": "~16.0.9",
"expo-font": "~11.10.3",
"expo-linear-gradient": "^12.7.2",
"expo-linking": "~6.2.2",
"expo-notifications": "~0.27.6",
"expo-notifications": "~0.27.7",
"expo-secure-store": "~12.8.1",
"expo-splash-screen": "~0.26.4",
"expo-splash-screen": "~0.26.5",
"expo-status-bar": "~1.11.1",
"expo-system-ui": "~2.9.3",
"expo-updates": "~0.24.11",
"expo-system-ui": "~2.9.4",
"expo-updates": "~0.24.12",
"expo-web-browser": "~12.8.2",
"lodash.merge": "^4.6.2",
"lru-cache": "^9.1.1",
"mixpanel-react-native": "^3.0.0-beta.2",
"nativewind": "^2.0.11",
"node-html-parser": "^6.1.5",
"react": "18.2.0",
"react-native": "0.73.4",
"react": "18.2.45",
"react-native": "0.73.6",
"react-native-collapsible-tab-view": "^6.1.4",
"react-native-fast-image": "^8.6.3",
"react-native-fetch-api": "^3.0.0",
"react-native-gesture-handler": "^2.15.0",
"react-native-get-random-values": "~1.8.0",
"react-native-haptic-feedback": "^2.2.0",
"react-native-ios-context-menu": "^1.15.3",
"react-native-lightbox-v2": "^0.9.0",
"react-native-linear-gradient": "^2.6.2",
"react-native-markdown-display": "https://github.com/jonasmerlin/react-native-markdown-display.git",
"react-native-mmkv": "^2.12.2",
"react-native-modal": "^13.0.1",
"react-native-pager-view": "6.2.3",
"react-native-polyfill-globals": "^3.1.0",
"react-native-qrcode-svg": "^6.2.0",
"react-native-reanimated": "^3.8.1",
"react-native-reanimated": "~3.6.2",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "~3.29.0",
"react-native-skeleton-placeholder": "^5.2.4",
"react-native-svg": "14.1.0",
"react-native-tab-view": "^3.4.0",
"react-native-url-polyfill": "^1.3.0",
"react-native-webview": "13.6.4",
"react-native-zoom-reanimated": "^1.4.5",
"rfdc": "^1.3.1",
"sentry-expo": "~7.2.0",
"siwe": "^2.1.4",
"swr": "^2.1.1",
"text-encoding": "^0.7.0",
"typescript": "^5.1.3",
"typescript": "^5.3.3",
"viem": "^1.19.11",
"web-streams-polyfill": "^3.2.1",
"zod": "^3.22.3"
Expand Down
5 changes: 3 additions & 2 deletions apps/mobile/src/components/IconContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type IconContainerProps = {
onPress: () => void;
size?: 'xs' | 'sm' | 'md';
border?: boolean;
color?: 'default' | 'white' | 'black' | 'active';
color?: 'default' | 'white' | 'black' | 'faint' | 'active';
} & GalleryTouchableOpacityProps;

export function IconContainer({
Expand All @@ -28,10 +28,11 @@ export function IconContainer({
md: 'h-8 w-8',
};

const colorVariants: { [color in 'default' | 'white' | 'black' | 'active']: string } = {
const colorVariants: { [color in 'default' | 'white' | 'black' | 'faint' | 'active']: string } = {
default: 'bg-faint dark:bg-black-500',
white: 'bg-white dark:bg-black-900',
black: 'bg-black-900 dark:bg-white',
faint: 'bg-black-700',
active: 'bg-porcelain dark:bg-white',
};

Expand Down
10 changes: 10 additions & 0 deletions apps/mobile/src/icons/CloseIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import Svg, { Path, SvgProps } from 'react-native-svg';

export function CloseIcon({ ...props }: SvgProps) {
return (
<Svg width="18" height="18" fill="none" viewBox="0 0 16 16" {...props}>
<Path d="M12.6663 3.33398L3.33301 12.6673" stroke="#F9F9F9" stroke-miterlimit="10" />
<Path d="M3.33301 3.33398L12.6663 12.6673" stroke="#F9F9F9" stroke-miterlimit="10" />
</Svg>
);
}
39 changes: 39 additions & 0 deletions apps/mobile/src/icons/MaximizeIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useColorScheme } from 'nativewind';
import React from 'react';
import Svg, { Path, SvgProps } from 'react-native-svg';

import colors from '~/shared/theme/colors';

export function MaximizeIcon({ ...props }: SvgProps) {
const { colorScheme } = useColorScheme();
const strokeColor = colorScheme === 'dark' ? colors.white : colors.black['800'];

return (
<Svg width="16" height="16" viewBox="0 0 16 16" fill="none" {...props}>
<Path
d="M13.9997 6.66667V2H9.33301"
stroke={strokeColor}
stroke-width="0.666667"
stroke-miterlimit="10"
/>
<Path
d="M13.9997 2L9.33301 6.66667"
stroke={strokeColor}
stroke-width="0.666667"
stroke-miterlimit="10"
/>
<Path
d="M2 9.33398V14.0007H6.66667"
stroke={strokeColor}
stroke-width="0.666667"
stroke-miterlimit="10"
/>
<Path
d="M2 13.9993L6.33333 9.66602"
stroke={strokeColor}
stroke-width="0.666667"
stroke-miterlimit="10"
/>
</Svg>
);
}
158 changes: 148 additions & 10 deletions apps/mobile/src/screens/NftDetailScreen/NftDetailSection.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import { useColorScheme } from 'nativewind';
import { useCallback, useMemo } from 'react';
import { ScrollView, View } from 'react-native';
import { useCallback, useMemo, useRef, useState } from 'react';
import { Dimensions, ScrollView, View } from 'react-native';
import FastImage from 'react-native-fast-image';
import Lightbox from 'react-native-lightbox-v2';
import Zoom from 'react-native-zoom-reanimated';
import { graphql, useFragment } from 'react-relay';
import { useNavigateToCommunityScreen } from 'src/hooks/useNavigateToCommunityScreen';
import { useToggleTokenAdmire } from 'src/hooks/useToggleTokenAdmire';
import { BookmarkIcon } from 'src/icons/BookmarkIcon';
import { CloseIcon } from 'src/icons/CloseIcon';
import { MaximizeIcon } from 'src/icons/MaximizeIcon';
import { PoapIcon } from 'src/icons/PoapIcon';
import { ShareIcon } from 'src/icons/ShareIcon';

Expand All @@ -22,6 +26,7 @@ import {
CreatorProfilePictureAndUsernameOrAddress,
OwnerProfilePictureAndUsername,
} from '~/components/ProfilePicture/ProfilePictureAndUserOrAddress';
import { useSafeAreaPadding } from '~/components/SafeAreaViewWithPadding';
import { Typography } from '~/components/Typography';
import { NftDetailSectionQueryFragment$key } from '~/generated/NftDetailSectionQueryFragment.graphql';
import { PostIcon } from '~/navigation/MainTabNavigator/PostIcon';
Expand All @@ -41,6 +46,8 @@ type Props = {
queryRef: NftDetailSectionQueryFragment$key;
};

const { width } = Dimensions.get('window');

export function NftDetailSection({ onShare, queryRef }: Props) {
const route = useRoute<RouteProp<MainTabStackNavigatorParamList, 'NftDetail'>>();

Expand Down Expand Up @@ -96,6 +103,7 @@ export function NftDetailSection({ onShare, queryRef }: Props) {
);

const { colorScheme } = useColorScheme();
const [isLightboxOpen, setIsLightboxOpen] = useState(false);

const token = query.tokenById;
const ownerWalletAddress =
Expand All @@ -120,6 +128,8 @@ export function NftDetailSection({ onShare, queryRef }: Props) {
}
}, [navigateToCommunity, tokenDefinition.community]);

const { top } = useSafeAreaPadding();

const handleCreatePost = useCallback(() => {
if (token.dbid) {
navigation.navigate('PostComposer', {
Expand Down Expand Up @@ -162,13 +172,117 @@ export function NftDetailSection({ onShare, queryRef }: Props) {
queryRef: query,
});

const customHeader = useCallback(
(close: () => void) => {
return (
<View
className="flex-row justify-end items-center px-3 bg-black-800"
style={{
paddingTop: top,
}}
>
<IconContainer
color="faint"
icon={<CloseIcon />}
onPress={close}
eventElementId={null}
eventName={null}
eventContext={null}
/>
</View>
);
},
[top]
);

const { contractName } = extractRelevantMetadataFromToken(token);

const blueToDisplay = useMemo(
() => (colorScheme === 'dark' ? 'darkModeBlue' : 'activeBlue'),
[colorScheme]
);

const handleMaximizeToggle = useCallback(() => {
setIsLightboxOpen((currIsLightboxOpen) => !currIsLightboxOpen);
}, []);

const thumbnailRef = useRef<View | null>(null);
const [thumbnailPosition, setThumbnailPosition] = useState({
width: width,
height: width,
x: 0,
y: 0,
});

const updateThumbnailPosition = useCallback(() => {
if (thumbnailRef.current) {
thumbnailRef.current.measure((x, y, w, h, pageX, pageY) => {
setThumbnailPosition({
width: w,
height: h,
x: pageX,
y: pageY,
});
});
}
}, []);

const handleOpenLightbox = useCallback(() => {
updateThumbnailPosition();
setIsLightboxOpen(true);
}, [updateThumbnailPosition]);

const handleCloseLightbox = useCallback(() => {
setIsLightboxOpen(false);
}, []);

const contentStyle = useMemo(
() => ({
width: width * 0.92,
minHeight: width * 0.92,
}),
[]
);

const zoomContentContainerStyle = useMemo(
() => ({
display: 'flex' as const,
width: width,
flexGrow: 1,
backgroundColor: colors.black['800'],
}),
[]
);

const renderContent = useCallback(
() => (
<TokenFailureBoundary tokenRef={token} variant="large">
<NftDetailAssetCacheSwapper cachedPreviewAssetUrl={route.params.cachedPreviewAssetUrl}>
<Zoom
contentContainerStyle={zoomContentContainerStyle}
style={{ display: 'flex', flexGrow: 1 }}
doubleTapConfig={{
minZoomScale: 1,
}}
>
<NftDetailAsset tokenRef={token} />
</Zoom>
</NftDetailAssetCacheSwapper>
</TokenFailureBoundary>
),
[token, route.params.cachedPreviewAssetUrl, zoomContentContainerStyle]
);

const tokenOrigin = useMemo(
() => ({
x: thumbnailPosition.x,
y: thumbnailPosition.y,
width: thumbnailPosition.width,
height: thumbnailPosition.height,
}),
[thumbnailPosition]
);

return (
<ScrollView>
<View className="flex flex-col space-y-3 px-4 pb-4">
Expand All @@ -188,14 +302,30 @@ export function NftDetailSection({ onShare, queryRef }: Props) {
/>
</View>

<View className="w-full mb-3">
<TokenFailureBoundary tokenRef={token} variant="large">
<NftDetailAssetCacheSwapper
cachedPreviewAssetUrl={route.params.cachedPreviewAssetUrl}
>
<NftDetailAsset tokenRef={token} />
</NftDetailAssetCacheSwapper>
</TokenFailureBoundary>
<View className="flex justify-between w-full mb-3">
<Lightbox
{...{
isOpen: isLightboxOpen,
onClose: handleCloseLightbox,
onOpen: handleOpenLightbox,
backgroundColor: colors.black['800'],
swipeToDismiss: false,
renderHeader: customHeader,
doubleTapZoomEnabled: false,
renderContent: renderContent,
origin: tokenOrigin,
}}
>
<View ref={thumbnailRef} style={contentStyle} onLayout={updateThumbnailPosition}>
<TokenFailureBoundary tokenRef={token} variant="large">
<NftDetailAssetCacheSwapper
cachedPreviewAssetUrl={route.params.cachedPreviewAssetUrl}
>
<NftDetailAsset tokenRef={token} />
</NftDetailAssetCacheSwapper>
</TokenFailureBoundary>
</View>
</Lightbox>
</View>
</View>

Expand All @@ -211,6 +341,14 @@ export function NftDetailSection({ onShare, queryRef }: Props) {
{tokenDefinition.name}
</Typography>
</View>
<GalleryTouchableOpacity
onPress={handleMaximizeToggle}
eventElementId="NFT Detail Maximize Icon"
eventName="NFT Detail Maximize Icon Pressed"
eventContext={contexts['NFT Detail']}
>
<MaximizeIcon />
</GalleryTouchableOpacity>
</View>
<GalleryTouchableOpacity
eventElementId="NFT Detail Contract Name Pill"
Expand Down
Loading

0 comments on commit 99b6317

Please sign in to comment.