tiefen_space_app/screeens/StreamerSpace/index.jsx

687 lines
25 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
View,
Text,
Image as NativeImage,
TouchableOpacity,
useWindowDimensions,
Animated,
Easing,
Modal,
} from "react-native";
import React, { useState, useEffect, useCallback, useMemo } from "react";
import { useTailwind } from "tailwind-rn";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import Toast from "react-native-toast-message";
import { Image } from "expo-image";
import { useHeaderHeight } from "@react-navigation/elements";
import { TabView, SceneMap, TabBar } from "react-native-tab-view";
import BottomSheet, { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import AllSpacePosts from "./AllSpacePosts";
import IronFanSpacePosts from "./IronFanSpacePosts";
import SuperFanSpacePosts from "./SuperFanSpacePosts";
import GetWechatModal from "../../components/GetWechatModal";
import SubmitWechatModal from "../../components/SubmitWechatModal";
import baseRequest from "../../utils/baseRequest";
import { generateSignature } from "../../utils/crypto";
import CreatePostModal from "../../components/CreatePostModal";
import { LinearProgress, Button } from "@rneui/themed";
import { LinearGradient } from "expo-linear-gradient";
import { usePreventScreenCapture } from "expo-screen-capture";
import { Svg, Path } from "react-native-svg";
import MyModal from "../../components/MyModal";
export default function StreamerSpace({ navigation, route }) {
usePreventScreenCapture();
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const headerHeight = useHeaderHeight();
//创建动态Modal是否展示
const [isCreatePostModalVisible, setIsCreatePostModalVisible] =
useState(false);
//退款中Modal是否展示
const [isRefundingModalVisible, setIsRefundingModalVisible] = useState(false);
//获取空间数据并将该空间标为已读
const [data, setData] = useState({});
const getData = async () => {
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
try {
const base = await baseRequest();
const signature = await generateSignature({
mid: route.params.mid,
...base,
});
const _response = await fetch(
`${apiUrl}/api/zone/list_by_mid?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mid: route.params.mid,
...base,
}),
}
);
const _data = await _response.json();
if (_data.ret === -1) {
Toast.show({
type: "error",
text1: _data.msg,
topOffset: 60,
});
return;
}
if (_data.data.list[0].visitor_role === 4) {
navigation.replace("SpaceIntroduce", { mid: route.params.mid });
return;
}
setData({
..._data.data.list[0],
refund_enable: _data.data.refund_enable,
refund_status: _data.data.refund_status,
});
if (_data.data.refund_status === 1) {
setIsRefundingModalVisible(true);
}
const signature2 = await generateSignature({
zid: _data.data.list[0].id,
...base,
});
const _response2 = await fetch(
`${apiUrl}/api/zone_session/upsert?signature=${signature2}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
zid: _data.data.list[0].id,
...base,
}),
}
);
const _data2 = await _response2.json();
if (_data2.ret === -1) {
Toast.show({
type: "error",
text1: _data2.msg,
topOffset: 60,
});
return;
}
} catch (error) {
console.error(error);
}
};
useEffect(() => {
getData();
}, []);
//设置header右侧按钮功能
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity
onPress={() => navigation.navigate("SpaceSetting", { data: data })}
>
<NativeImage
source={require("../../assets/icon/others/setting.png")}
/>
</TouchableOpacity>
),
});
}, [data]);
//点击查看微信按钮
const [isAddWechatModalVisible, setIsAddWechatModalVisible] = useState(false);
//tab组件相关
const layout = useWindowDimensions();
const [index, setIndex] = useState(0);
const [routes, setRoutes] = useState([
{ key: "all", title: "全部" },
{ key: "ironFan", title: "铁粉专享" },
{ key: "superFan", title: "超粉专享" },
]);
//当主播没开通超粉功能时不展示超粉专享tab
useEffect(() => {
if (data?.is_superfanship_enabled === 0)
setRoutes([
{ key: "all", title: "全部" },
{ key: "ironFan", title: "铁粉专享" },
]);
}, [data]);
const renderScene = useCallback(
SceneMap({
all: () => <AllSpacePosts zid={data?.id} />,
ironFan: () => <IronFanSpacePosts zid={data?.id} />,
superFan: () => <SuperFanSpacePosts zid={data?.id} />,
}),
[data]
);
const renderIndicator = useCallback((props) => {
const { position, navigationState, getTabWidth } = props;
const inputRange = [0, 1];
const translateX = position.interpolate({
inputRange: inputRange,
outputRange: inputRange.map((x) => {
return x * getTabWidth(navigationState.index);
}),
});
return (
<Animated.View
style={{
width: `${100 / navigationState.routes.length}%`,
transform: [
{
translateX,
},
],
paddingBottom: 12,
...tailwind("flex flex-1 items-center justify-end"),
}}
>
<NativeImage
source={require("../../assets/icon/others/pinkline.png")}
/>
</Animated.View>
);
}, []);
const renderTabBar = useCallback(
(props) => (
<TabBar
{...props}
style={tailwind("bg-transparent")}
labelStyle={tailwind("text-base font-medium")}
renderIndicator={renderIndicator}
/>
),
[]
);
//bottom sheet组件相关
const snapPoints = useMemo(() => ["73%", "100%"], []);
//成为铁粉Modal组件
const [isIronFanModalVisible, setIsIronFanModalVisible] = useState(false);
const ironFanProgress = useMemo(
() => Math.floor((data?.expenditure / data?.ironfanship_price) * 100),
[data]
);
const BecomeIronFanModal = useCallback(
() => (
<Modal
visible={isIronFanModalVisible}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<TouchableOpacity
activeOpacity={1}
style={{
backgroundColor: "#00000080",
...tailwind("flex-1 justify-center items-center"),
}}
onPress={() => setIsIronFanModalVisible(false)}
>
<TouchableOpacity
activeOpacity={1}
style={tailwind(
"flex flex-col p-4 rounded-2xl bg-[#17161A] items-center w-3/4"
)}
>
<View style={tailwind("flex-row items-end w-full")}>
<Text style={tailwind("text-base text-white font-medium")}>
当前铁粉解锁进度
</Text>
<Text style={tailwind("text-2xl text-[#FF669E] font-medium")}>
{`${ironFanProgress}%`}
</Text>
</View>
<LinearProgress
style={tailwind("flex-row w-full h-2 mt-2 rounded-full")}
value={ironFanProgress / 100}
color="#FF669E"
variant="determinate"
/>
<Text style={tailwind("text-sm text-[#FF669E] font-medium")}>{`${
data?.expenditure / 100
} / ${data?.ironfanship_price / 100}`}</Text>
<Text style={tailwind("text-sm font-medium text-[#FFFFFF80] mt-2")}>
空间内累计消费达到¥{data?.ironfanship_price / 100}即可成为
<Text style={tailwind("text-[#FF669E]")}>铁粉</Text>
可查看所有铁粉专享内容哦快来成为我的铁粉吧
</Text>
<Button
onPress={() => {
setIndex(1);
setIsIronFanModalVisible(false);
}}
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 mt-4")}
>
查看铁粉专享内容
</Button>
</TouchableOpacity>
</TouchableOpacity>
</Modal>
),
[isIronFanModalVisible]
);
//刷新动画
const [rotateValue] = useState(new Animated.Value(0));
const startRotation = () => {
getData();
Animated.timing(rotateValue, {
toValue: 1,
duration: 500,
easing: Easing.linear,
useNativeDriver: true,
}).start(() => {
rotateValue.setValue(0);
});
};
const spin = rotateValue.interpolate({
inputRange: [0, 1],
outputRange: ["0deg", "360deg"],
});
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<BottomSheetModalProvider>
<View
style={{
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
<View style={tailwind("absolute top-0 left-0")}>
<Image
source={data?.streamer_ext?.cover?.images[0]?.urls[0]}
contentFit="cover"
transition={1000}
placeholder={blurhash}
cachePolicy="disk"
style={{
aspectRatio: "15/13",
...tailwind("w-full"),
}}
/>
<View
style={{
backgroundColor: "#000000B2",
...tailwind("absolute w-full h-full"),
}}
></View>
</View>
<View
style={{
marginTop: headerHeight,
...tailwind("flex flex-col flex-1"),
}}
>
<View style={tailwind("flex flex-row items-center px-4 h-24")}>
<Image
style={tailwind(
"w-[4.6rem] h-[4.6rem] rounded-full border-2 border-white"
)}
source={data?.streamer_ext?.avatar?.images[0]?.urls[0]}
placeholder={blurhash}
contentFit="cover"
transition={1000}
cachePolicy="disk"
/>
<View
style={tailwind("flex flex-col shrink mx-2 justify-between")}
>
<Text
style={{
fontSize: 22,
...tailwind("text-white font-medium"),
}}
numberOfLines={1}
ellipsizeMode="tail"
>
{data?.streamer_ext?.name}
</Text>
<View style={tailwind("flex-row flex-wrap mt-1.5")}>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/ID.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{data?.streamer_ext?.user_id}
</Text>
</View>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/edit.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{data?.zone_moment_count}
</Text>
</View>
</View>
</View>
<TouchableOpacity
onPress={() =>
navigation.navigate("ShareSpace", { data: data })
}
style={tailwind(
"flex items-center justify-center ml-auto h-8 px-4 bg-[#FF669E] rounded-full"
)}
>
<Text style={tailwind("text-white text-sm font-medium")}>
分享
</Text>
</TouchableOpacity>
</View>
<View style={{ gap: 22, ...tailwind("flex flex-row px-6 mt-2") }}>
<TouchableOpacity
onPress={() => setIsAddWechatModalVisible(true)}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/wechat_bg.png")}
/>
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
查看微信
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setIsIronFanModalVisible(true)}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/tiefen_bg.png")}
/>
<View style={tailwind("flex flex-col items-center")}>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
{data?.is_ironfanship_unlocked === 1
? "已是铁粉"
: "成为铁粉"}
</Text>
<Text
style={{
fontSize: 10,
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
{`${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
</Text>
</View>
</TouchableOpacity>
{data?.is_superfanship_enabled === 1 && (
<TouchableOpacity
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.id +
"/h5_zone_superfanship/0",
})
}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/chaofen_bg.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
{data?.is_superfanship_unlocked === 1
? "尊贵超粉"
: "成为超粉"}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() =>
navigation.navigate("MessageDetail", {
mid: 1,
})
}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/report_bg.png")}
/>
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
举报
</Text>
</TouchableOpacity>
{data?.visitor_role === 3 && (
<TouchableOpacity
onPress={() =>
navigation.navigate("VisibleToOneselfSpacePosts")
}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/review_fail_bg.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
审核未通过
</Text>
</TouchableOpacity>
)}
</View>
<BottomSheet
snapPoints={snapPoints}
backgroundStyle={tailwind("bg-[#07050A]")}
handleIndicatorStyle={tailwind("bg-white")}
handleStyle={{ paddingBottom: 0 }}
>
<TabView
navigationState={{ index, routes }}
swipeEnabled={false}
renderScene={renderScene}
renderTabBar={renderTabBar}
onIndexChange={setIndex}
initialLayout={{ width: layout.width }}
/>
</BottomSheet>
</View>
{data?.visitor_role === 3 ? (
<TouchableOpacity
onPress={() =>
setIsCreatePostModalVisible(!isCreatePostModalVisible)
}
style={{
...tailwind("absolute"),
bottom: insets.bottom + 20,
right: 16,
}}
>
<NativeImage
source={require("../../assets/icon/others/createpost.png")}
/>
</TouchableOpacity>
) : (
<View
style={{
...tailwind(
"absolute bottom-0 flex flex-row w-full py-3 px-6 justify-around border-t border-[#FFFFFF26] bg-[#07050A]"
),
height: 72 + insets.bottom,
}}
>
<TouchableOpacity
onPress={() => setIsAddWechatModalVisible(true)}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/wechat.png")}
/>
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
查看微信
</Text>
</TouchableOpacity>
{data?.is_superfanship_enabled === 1 && (
<TouchableOpacity
onPress={
data?.is_superfanship_unlocked === 1
? () => setIndex(2)
: () =>
navigation.navigate("WebWithoutHeader", {
uri:
process.env.EXPO_PUBLIC_WEB_URL +
"/zone/pay/" +
data?.id +
"/h5_zone_superfanship/0",
})
}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/chaofen.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
{data?.is_superfanship_unlocked === 1
? "尊贵超粉"
: "成为超粉"}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity
onPress={() => setIsIronFanModalVisible(true)}
style={tailwind("flex flex-col items-center")}
>
<NativeImage
source={require("../../assets/icon/others/tiefen.png")}
/>
<View style={tailwind("flex flex-col items-center")}>
<Text
style={tailwind("text-white text-xs font-medium mt-0.5")}
>
成为铁粉
</Text>
<Text
style={{
fontSize: 10,
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
}}
>
{`${parseInt(data?.expenditure / 100, 10)}/${parseInt(
data?.ironfanship_price / 100,
10
)}`}
</Text>
</View>
</TouchableOpacity>
</View>
)}
{/* 点击成为铁粉Modal */}
<BecomeIronFanModal />
{/* 创建帖子Modal */}
<CreatePostModal
visible={isCreatePostModalVisible}
setVisible={setIsCreatePostModalVisible}
/>
{/* 查看微信Modal */}
{data?.streamer_ext?.wechat_lock_type === 0 ? (
<GetWechatModal
visible={isAddWechatModalVisible}
setVisible={setIsAddWechatModalVisible}
streamerMid={route.params.mid}
/>
) : (
<SubmitWechatModal
visible={isAddWechatModalVisible}
setVisible={setIsAddWechatModalVisible}
streamerMid={route.params.mid}
/>
)}
{/* 退款中禁止查看Modal */}
<MyModal
visible={isRefundingModalVisible}
setVisible={setIsRefundingModalVisible}
title="当前空间正在退款中"
content="退款中空间不支持查看,请关注原支付渠道退款进度,退款后无法再次进入当前空间。"
cancel={() => {
setIsRefundingModalVisible(false);
setTimeout(() => navigation.replace("HomeTab"), 500);
}}
confirm={() => {
setIsRefundingModalVisible(false);
setTimeout(() => navigation.replace("HomeTab"), 500);
}}
/>
</View>
{/* 刷新按钮 */}
<TouchableOpacity
style={{
...tailwind("absolute bg-[#13121F] p-1 rounded-full"),
bottom: insets.bottom + 100,
right: 16,
}}
onPress={startRotation}
>
<Animated.View style={{ transform: [{ rotate: spin }] }}>
<Svg viewBox="0 0 1024 1024" width="30" height="30">
<Path
d="M855.7 546.3c-16.6 0-30-13.5-30-30.1 0.1-72.8-25.1-143.9-71-200.4l-1-1.3c-31.5-38.5-72.1-69.2-117.3-88.9l-0.6-0.2-2.2-1c-6.8-2.9-14.3-5.6-22.9-8.4l-0.6-0.2-6.5-2.3c-7.1-2.1-14.7-3.9-20.6-5.3-1.2-0.3-2.3-0.5-3.5-0.8-2.1-0.5-4-1-5.6-1.3l-0.4-0.1c-6.8-1.4-14.1-2.5-21.7-3.3l-0.8-0.1-8.4-1.2c-73.7-7.1-147.4 12.6-207.8 55.6-13.5 9.6-32.2 6.5-41.8-7-9.6-13.5-6.5-32.2 7-41.8 72.3-51.5 160.8-75.1 249.1-66.4l1.3 0.2 8.7 1.2c9 1 17.8 2.4 26 4 3.1 0.6 6 1.3 8.6 1.9 1 0.2 1.9 0.5 2.9 0.7 7 1.6 16.2 3.8 25.2 6.5l1.2 0.4 6.9 2.4c10.2 3.4 19.3 6.7 27.7 10.3l0.8 0.4 2.4 1.1c54.1 23.6 102.4 60.4 139.9 106.3l1 1.4c54.4 67.1 84.2 151.5 84.1 237.9-0.1 16.4-13.6 29.8-30.1 29.8z"
fill="#ffffff"
></Path>
<Path
d="M872.5 661.6l78.9-114.5c9-13.1-0.3-30.9-16.3-30.9H777.4c-15.9 0-25.3 17.8-16.3 30.9L840 661.6c7.9 11.4 24.7 11.4 32.5 0zM513.3 884.1c-12 0-24-0.6-36-1.8l-1.3-0.2-8.6-1.2c-9-1-17.8-2.4-26-4-3.1-0.6-6-1.3-8.6-1.9-1-0.2-1.9-0.5-2.9-0.7-7-1.6-16.2-3.8-25.2-6.5l-1.2-0.4-6.9-2.4c-10.2-3.4-19.3-6.7-27.7-10.3l-0.8-0.4-2.4-1.1c-54.1-23.6-102.4-60.4-139.9-106.3l-1-1.4c-54.4-67.1-84.2-151.5-84.1-237.9 0-16.6 13.5-29.9 30-29.9h0.1c16.6 0 30 13.5 29.9 30.1-0.1 72.8 25.1 143.9 71 200.4l1 1.3c31.5 38.5 72.1 69.2 117.3 88.9l2.8 1.3c6.8 2.9 14.3 5.6 22.9 8.4l0.6 0.2 6.5 2.3c7.1 2.1 14.7 3.9 20.6 5.3 1.2 0.3 2.3 0.5 3.5 0.8 2.1 0.5 4 1 5.6 1.3l0.4 0.1c6.8 1.3 14.1 2.5 21.7 3.3l0.8 0.1 8.4 1.2c73.7 7.1 147.4-12.6 207.8-55.6 13.5-9.6 32.2-6.5 41.8 7 9.6 13.5 6.5 32.2-7 41.8-62.5 44.5-137 68.2-213.1 68.2z"
fill="#ffffff"
></Path>
<Path
d="M153.8 362.4L74.9 476.9c-9 13.1 0.3 30.9 16.3 30.9H249c15.9 0 25.3-17.8 16.3-30.9l-78.9-114.5c-7.9-11.4-24.7-11.4-32.6 0z"
fill="#ffffff"
></Path>
</Svg>
</Animated.View>
</TouchableOpacity>
</BottomSheetModalProvider>
</GestureHandlerRootView>
);
}