Merge pull request '重新封装ImageViewer组件;为ImageViewer组件增加付费跳转功能;完善空间相关功能' () from imageviewer into main

Reviewed-on: https://git.wishpal.cn/wishpal_ironfan/tiefen_space_app/pulls/6
This commit is contained in:
yezian 2024-04-23 22:22:47 +08:00
commit ad6a1a89d8
9 changed files with 674 additions and 573 deletions
App.jsx
components
ImageViewer
Post
SpacePost
context
screeens
SpaceIntroduce
SpaceSetting
AgencySetting
CollaboratorSetting
StreamerProfile

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}
/>
</>
);
};