重新封装ImageViewer组件;为ImageViewer组件增加付费跳转功能;完善空间相关功能 #6

Merged
yezian merged 1 commits from imageviewer into main 2024-04-23 22:22:48 +08:00
9 changed files with 674 additions and 573 deletions

1017
App.jsx

File diff suppressed because it is too large Load Diff

View File

@ -16,23 +16,37 @@ import Toast from "react-native-toast-message";
import { get } from "../../utils/storeInfo";
import { useNavigation } from "@react-navigation/native";
import MyModal from "../MyModal";
import { Image } from "expo-image";
import { LinearProgress, Button } from "@rneui/themed";
import { LinearGradient } from "expo-linear-gradient";
//isVisible boolean
//setIsVisible function
//imageUrls [{ url: string }]
//index int
export default function ImageViewer({
isVisible,
setIsVisible,
export function ImageViewer({
isShow,
onClose,
imageUrls,
index,
lockedStartIndex,
unlockUrl,
onChange,
}) {
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const navigation = useNavigation();
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
setIsVisible(isShow);
}, [isShow]);
const closeImageViewer = () => {
setIsVisible(false);
onClose && onClose();
};
const checkRole = useCallback(async () => {
const account = await get("account");
const role = account.role;
@ -73,7 +87,7 @@ export default function ImageViewer({
saveToLocal();
return;
}
setIsVisible(false);
closeImageViewer();
navigation.navigate("WebWithoutHeader", {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
});
@ -130,10 +144,50 @@ export default function ImageViewer({
<OriginImageViewer
imageUrls={imageUrls}
index={index}
onClick={() => setIsVisible(false)}
onSwipeDown={() => setIsVisible(false)}
onClick={closeImageViewer}
onSwipeDown={closeImageViewer}
onChange={(index) => onChange(index)}
enableSwipeDown
backgroundColor="#07050A"
renderImage={(props) => {
if (index >= lockedStartIndex) {
return (
<View>
<Image
{...props}
blurRadius={Platform.OS === "ios" ? 100 : 10}
/>
<View
style={tailwind(
"absolute flex justify-center items-center top-0 left-0 bg-[#00000080] w-full h-full"
)}
>
<Button
onPress={() => {
closeImageViewer();
navigation.navigate("WebWithoutHeader", {
uri: unlockUrl,
});
}}
ViewComponent={LinearGradient}
radius="999"
size="md"
linearGradientProps={{
colors: ["#FF668B", "#FF66F0"],
start: { x: 0, y: 0.5 },
end: { x: 1, y: 0.5 },
}}
titleStyle={tailwind("text-base font-medium")}
containerStyle={tailwind("w-full px-4")}
>
立即解锁
</Button>
</View>
</View>
);
}
return <Image {...props} />;
}}
renderFooter={
Platform.OS === "android"
? (index) => (
@ -178,7 +232,7 @@ export default function ImageViewer({
}}
confirm={() => {
setIsVipModalVisible(false);
setIsVisible(false);
closeImageViewer();
navigation.navigate("WebWithoutHeader", {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
});

View File

@ -10,7 +10,6 @@ import {
import React, { useEffect, useState, useCallback } from "react";
import { useTailwind } from "tailwind-rn";
import { Image } from "expo-image";
import ImageViewer from "../ImageViewer";
import VideoModal from "../VideoModal";
import { useNavigation } from "@react-navigation/native";
import { follow, unfollow, block } from "../../utils/relation";
@ -18,6 +17,7 @@ import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
import Toast from "react-native-toast-message";
import { get } from "../../utils/storeInfo";
import { useImageViewer } from "../../context/ImageViewProvider";
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
@ -303,10 +303,10 @@ export default function Post({ isBlur, data }) {
function ImageDisplay({ blur, media }) {
const navigation = useNavigation();
const tailwind = useTailwind();
const [isModalVisible, setIsModalVisible] = useState(false);
const [imageIndex, setImageIndex] = useState();
const images = media.map((item) => ({ url: item.urls[0] }));
const { showImageViewer } = useImageViewer();
if (images.length === 0) return null;
return (
@ -323,8 +323,10 @@ function ImageDisplay({ blur, media }) {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
})
: () => {
setIsModalVisible(true);
setImageIndex(index);
showImageViewer({
imageUrls: images,
index: index,
});
}
}
style={{ aspectRatio: 1, ...tailwind("basis-1/3 p-0.5") }}
@ -350,8 +352,10 @@ function ImageDisplay({ blur, media }) {
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
})
: () => {
setIsModalVisible(true);
setImageIndex(0);
showImageViewer({
imageUrls: images,
index: 0,
});
}
}
style={{
@ -373,12 +377,6 @@ function ImageDisplay({ blur, media }) {
/>
</TouchableOpacity>
)}
<ImageViewer
isVisible={isModalVisible}
setIsVisible={setIsModalVisible}
imageUrls={images}
index={imageIndex}
/>
</View>
);
}

View File

@ -10,7 +10,6 @@ import {
import React, { useEffect, useState } from "react";
import { useTailwind } from "tailwind-rn";
import { Image } from "expo-image";
import ImageViewer from "../ImageViewer";
import VideoModal from "../VideoModal";
import { useNavigation } from "@react-navigation/native";
import formatTimestamp from "../../utils/formatTimestamp";
@ -22,6 +21,7 @@ import { get } from "../../utils/storeInfo";
import { Icon } from "@rneui/themed";
import ParsedText from "react-native-parsed-text";
import * as Linking from "expo-linking";
import { useImageViewer } from "../../context/ImageViewProvider";
//todo:
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
@ -200,6 +200,7 @@ export default function SpacePost({ data }) {
{data.media_component.video_ids?.length === 0 ||
data.media_component.video_ids === null ? (
<ImageDisplay
data={data}
isUnlocked={data.is_zone_moment_unlocked}
visibleRange={data.media_visible_range}
mediaAmount={data.media_amount}
@ -208,9 +209,21 @@ export default function SpacePost({ data }) {
) : (
<TouchableOpacity
activeOpacity={1}
onPress={() => {
setShowVideo(true);
}}
onPress={
data.is_zone_moment_unlocked === 1
? () => {
setShowVideo(true);
}
: () =>
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.zid +
"/h5_zone_moment/" +
data?.id,
})
}
>
<View>
<PosterDisplay
@ -442,17 +455,15 @@ export default function SpacePost({ data }) {
}
//
function ImageDisplay({ isUnlocked, visibleRange, mediaAmount, media }) {
const navigation = useNavigation();
function ImageDisplay({ data, isUnlocked, visibleRange, mediaAmount, media }) {
const tailwind = useTailwind();
const [isModalVisible, setIsModalVisible] = useState(false);
//url使
const displayMedia = media.concat(
new Array(mediaAmount - media.length).fill(media[0])
);
const [imageIndex, setImageIndex] = useState();
const { showImageViewer } = useImageViewer();
const images = displayMedia.map((item) => {
return { url: item.urls[0] };
});
@ -470,8 +481,17 @@ function ImageDisplay({ isUnlocked, visibleRange, mediaAmount, media }) {
activeOpacity={1}
key={index}
onPress={() => {
setIsModalVisible(true);
setImageIndex(index);
showImageViewer({
imageUrls: images,
index: index,
lockedStartIndex: visibleRange,
unlockUrl:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.zid +
"/h5_zone_moment/" +
data?.id,
});
}}
style={
displayMedia.length > 1
@ -546,12 +566,6 @@ function ImageDisplay({ isUnlocked, visibleRange, mediaAmount, media }) {
</TouchableOpacity>
);
})}
<ImageViewer
isVisible={isModalVisible}
setIsVisible={setIsModalVisible}
imageUrls={images}
index={imageIndex}
/>
</View>
);
}

View File

@ -0,0 +1,37 @@
import React, { useState, createContext, useContext } from "react";
import { ImageViewer } from "../components/ImageViewer";
const ImageViewerContext = createContext();
export const ImageViewerProvider = ({ children }) => {
const [imageViewerProps, setImageViewerProps] = useState(null);
const showImageViewer = (props) => {
setImageViewerProps({ ...props, isShow: true });
};
const closeImageViewer = () => {
setImageViewerProps(null);
};
const changeImageViewerIndex = (index) => {
setImageViewerProps((prev) => {
return { ...prev, index: index };
});
};
return (
<ImageViewerContext.Provider value={{ showImageViewer }}>
{children}
{imageViewerProps && (
<ImageViewer
{...imageViewerProps}
onClose={closeImageViewer}
onChange={changeImageViewerIndex}
/>
)}
</ImageViewerContext.Provider>
);
};
export const useImageViewer = () => useContext(ImageViewerContext);

View File

@ -19,7 +19,7 @@ import VideoModal from "../../components/VideoModal";
import SpaceIntroduceSkeleton from "./skeleton";
import { usePreventScreenCapture } from "expo-screen-capture";
import { useFocusEffect } from "@react-navigation/native";
import ImageViewer from "../../components/ImageViewer";
import { useImageViewer } from "../../context/ImageViewProvider";
export default function SpaceIntroduce({ navigation, route }) {
usePreventScreenCapture();
@ -27,6 +27,8 @@ export default function SpaceIntroduce({ navigation, route }) {
const insets = useSafeAreaInsets();
const headerHeight = useHeaderHeight();
const { showImageViewer } = useImageViewer();
const [data, setData] = useState({});
const [isLoading, setIsloading] = useState(true);
const getData = async () => {
@ -79,10 +81,6 @@ export default function SpaceIntroduce({ navigation, route }) {
}, [])
);
//modal
const [imagesVisible, setImagesVisible] = useState(false);
//modal
const [imageIndex, setImageIndex] = useState("");
const images = data?.streamer_ext?.album?.images?.map((image, index) => {
if (index > 4) return;
return image?.urls[0];
@ -277,8 +275,10 @@ export default function SpaceIntroduce({ navigation, route }) {
<TouchableOpacity
activeOpacity={1}
onPress={() => {
setImageIndex(index);
setImagesVisible(true);
showImageViewer({
imageUrls: imagesForImageViewer,
index: index,
});
}}
key={index}
style={tailwind("basis-1/3 p-0.5")}
@ -384,13 +384,6 @@ export default function SpaceIntroduce({ navigation, route }) {
setVisible={setShowVideo}
url={data?.streamer_ext?.shorts?.videos[0]?.urls[0]}
/>
{/* 展示图片的modal */}
<ImageViewer
isVisible={imagesVisible}
setIsVisible={setImagesVisible}
imageUrls={imagesForImageViewer}
index={imageIndex}
/>
</View>
);
}

View File

@ -328,7 +328,7 @@ export default function AgencySetting({ navigation, route }) {
ID{data.third_partner_account.user_id}
</Text>
<Text style={tailwind("text-white text-base font-medium")}>
分成比例{data.sharing_ratio * 100}%
分成比例{(data.sharing_ratio * 100).toFixed()}%
</Text>
</View>
)}

View File

@ -313,7 +313,7 @@ export default function CollaboratorSetting({ navigation, route }) {
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{item?.sharing_ratio * 100}%
{(item?.sharing_ratio * 100).toFixed()}%
</Text>
</View>
</View>
@ -374,7 +374,7 @@ export default function CollaboratorSetting({ navigation, route }) {
ID{selfData[0]?.collaborator_account?.user_id}
</Text>
<Text style={tailwind("text-white text-base font-medium")}>
分成比例{selfData[0]?.sharing_ratio * 100}%
分成比例{(selfData[0]?.sharing_ratio * 100).toFixed()}%
</Text>
</View>
<View style={tailwind("mt-8")}>
@ -411,7 +411,7 @@ export default function CollaboratorSetting({ navigation, route }) {
总分成比例
</Text>
<Text style={tailwind("text-[#F53030] text-3xl font-medium my-2")}>
{data?.zone_third_partner?.sharing_ratio * 100}%
{(data?.zone_third_partner?.sharing_ratio * 100).toFixed()}%
</Text>
<Text style={tailwind("text-[#FFFFFF80] text-sm")}>
修改比例请联系平台客服

View File

@ -14,7 +14,6 @@ import React, { useState, useEffect } from "react";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useTailwind } from "tailwind-rn";
import { Image } from "expo-image";
import ImageViewer from "../../components/ImageViewer";
import Swiper from "react-native-swiper";
import { Divider, Icon } from "@rneui/themed";
import VideoModal from "../../components/VideoModal";
@ -30,6 +29,7 @@ import { get } from "../../utils/storeInfo";
import StreamerProfileSkeleton from "./skeleton";
import { generateSignature } from "../../utils/crypto";
import Svg, { Path } from "react-native-svg";
import { useImageViewer } from "../../context/ImageViewProvider";
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
@ -257,10 +257,9 @@ export default function StreamerProfile({ navigation, route }) {
const MySwiper = () => {
//modal
const [videoVisible, setVideoVisible] = useState(false);
//modal
const [imagesVisible, setImagesVisible] = useState(false);
//modal
const [imageIndex, setImageIndex] = useState("");
const { showImageViewer } = useImageViewer();
const images = data?.album?.images?.map((image) => image?.urls[0]);
const imagesForImageViewer = images?.map((url) => ({ url }));
return (
@ -312,8 +311,10 @@ export default function StreamerProfile({ navigation, route }) {
) : (
<TouchableWithoutFeedback
onPress={() => {
setImageIndex(index - 1);
setImagesVisible(true);
showImageViewer({
imageUrls: imagesForImageViewer,
index: index - 1,
});
}}
>
<Image
@ -335,13 +336,6 @@ export default function StreamerProfile({ navigation, route }) {
setVisible={setVideoVisible}
url={data?.shorts?.videos[0]?.urls[0]}
/>
{/* 展示图片的modal */}
<ImageViewer
isVisible={imagesVisible}
setIsVisible={setImagesVisible}
imageUrls={imagesForImageViewer}
index={imageIndex}
/>
</>
);
};