tiefen_space_app/screeens/StreamerProfile/index.jsx

671 lines
22 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,
Dimensions,
TouchableOpacity,
TouchableWithoutFeedback,
Modal,
ActivityIndicator,
Text,
Alert,
ScrollView,
Image as NativeImage,
} from "react-native";
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 "react-native-image-zoom-viewer";
import Swiper from "react-native-swiper";
import { Divider, Icon } from "@rneui/themed";
import VideoModal from "../../components/VideoModal";
import { useHeaderHeight } from "@react-navigation/elements";
import * as Clipboard from "expo-clipboard";
import * as Linking from "expo-linking";
import GetWechatModal from "../../components/GetWechatModal";
import SubmitWechatModal from "../../components/SubmitWechatModal";
import Toast from "react-native-toast-message";
import baseRequest from "../../utils/baseRequest";
import { follow, unfollow, checkRelation, block } from "../../utils/relation";
import { get } from "../../utils/storeInfo";
import StreamerProfileSkeleton from "./skeleton";
import { generateSignature } from "../../utils/crypto";
import Svg, { Path } from "react-native-svg";
export default function StreamerProfile({ navigation, route }) {
const screenWidth = Dimensions.get("window").width;
const tailwind = useTailwind();
const insets = useSafeAreaInsets();
const headerHeight = useHeaderHeight();
//设置header右侧按钮功能
useEffect(() => {
navigation.setOptions({
headerRight: () => (
<Icon
type="ionicon"
name="ellipsis-vertical"
size={24}
color="white"
onPress={() => setNavModal(true)}
/>
),
});
}, []);
//页面数据
const [data, setData] = useState({});
const [isLoading, setIsloading] = useState(true);
useEffect(() => {
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 detailResponse = await fetch(
`${apiUrl}/api/streamer/list_ext_by_mid?signature=${signature}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mid: route.params.mid,
...base,
}),
}
);
const detailData = await detailResponse.json();
if (detailData.ret === -1) {
Toast.show({
type: "error",
text1: detailData.msg,
topOffset: 60,
});
return;
}
//获取当前所有平台
const signature2 = await generateSignature({
...base,
});
const allPlatformsResponse = await fetch(
`${apiUrl}/api/platform/list?signature=${signature2}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...base,
}),
}
);
const allPlatformsData = await allPlatformsResponse.json();
if (allPlatformsData.ret === -1) {
Toast.show({
type: "error",
text1: allPlatformsData.msg,
topOffset: 60,
});
return;
}
//获取主播当前所有平台
const signature3 = await generateSignature({
mid: route.params.mid,
...base,
});
const streamerPlatformResponse = await fetch(
`${apiUrl}/api/streamer_link/list_by_mid?signature=${signature3}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
mid: route.params.mid,
...base,
}),
}
);
const streamerPlatformData = await streamerPlatformResponse.json();
if (streamerPlatformData.ret === -1) {
Toast.show({
type: "error",
text1: streamerPlatformData.msg,
topOffset: 60,
});
return;
}
const platformsWithIcon = streamerPlatformData.data.list.map((item) => {
return {
...item,
link_icon: allPlatformsData.data[item.link_no]?.icon,
};
});
setData({
...detailData.data.streamer_ext,
wechat_lock_type: detailData.data.wechat_lock_type,
platforms: platformsWithIcon,
});
setIsloading(false);
} catch (error) {
console.error(error);
}
};
getData();
}, []);
//媒体展示组件
const MySwiper = () => {
//控制视频modal可见性
const [videoVisible, setVideoVisible] = useState(false);
//控制图片modal可见性
const [imagesVisible, setImagesVisible] = useState(false);
//控制图片modal中打开的图片索引
const [imageIndex, setImageIndex] = useState("");
const images = data?.album?.images?.map((image) => image?.urls[0]);
const imagesForImageViewer = images?.map((url) => ({ url }));
return (
<>
<Swiper
autoplay
width={screenWidth}
height={screenWidth}
activeDotStyle={tailwind("bg-[#FF669E]")}
>
{data?.album !== undefined &&
data?.cover !== undefined &&
[...data?.cover?.images, ...data?.album?.images].map(
(item, index) => (
<View key={index}>
{index === 0 ? (
<TouchableOpacity
activeOpacity={1}
style={tailwind(
"w-full h-full flex items-center justify-center"
)}
onPress={() => setVideoVisible(true)}
>
<Image
source={item?.urls[0]}
contentFit="cover"
transition={1000}
cachePolicy="disk"
style={tailwind("w-full h-full")}
/>
<View
style={tailwind(
"absolute flex items-center justify-center"
)}
>
<Svg viewBox="0 0 1024 1024" width="50" height="50">
<Path
d="M512 512m-512 0a44 44 0 1 0 1024 0 44 44 0 1 0-1024 0Z"
fill="#000000"
opacity="0.5"
></Path>
<Path
d="M746.327273 534.035416 418.181818 723.708144C401.890909 733.017235 380.945455 721.380871 380.945455 701.599053L380.945455 322.253598C380.945455 303.635416 401.890909 290.835416 418.181818 300.144507L746.327273 489.817235C763.781818 500.289962 763.781818 523.562689 746.327273 534.035416L746.327273 534.035416Z"
fill="#FFFFFF"
></Path>
</Svg>
</View>
</TouchableOpacity>
) : (
<TouchableWithoutFeedback
onPress={() => {
setImageIndex(index - 1);
setImagesVisible(true);
}}
>
<Image
source={item?.urls[0]}
contentFit="cover"
transition={1000}
cachePolicy="disk"
style={tailwind("w-full h-full")}
/>
</TouchableWithoutFeedback>
)}
</View>
)
)}
</Swiper>
{/* 展示视频的modal */}
<VideoModal
visible={videoVisible}
setVisible={setVideoVisible}
url={data?.shorts?.videos[0]?.urls[0]}
/>
{/* 展示图片的modal */}
<Modal visible={imagesVisible} statusBarTranslucent transparent={true}>
<TouchableWithoutFeedback onPress={() => setImagesVisible(false)}>
<ImageViewer
imageUrls={imagesForImageViewer}
enableSwipeDown
saveToLocalByLongPress={false}
onSwipeDown={() => setImagesVisible(false)}
index={imageIndex}
loadingRender={() => <ActivityIndicator size="large" />}
/>
</TouchableWithoutFeedback>
</Modal>
</>
);
};
//拉黑、举报组件
const [navModal, setNavModal] = useState(false);
const NavbarRightModal = () => {
const handleFeedback = () => {
navigation.navigate("MessageDetail", { mid: 1 });
setNavModal(false);
};
const handleBlock = async () => {
const account = await get("account");
const subMid = account.mid;
const objMid = route.params.mid;
await block(subMid, objMid);
setNavModal(false);
};
return (
<Modal
visible={navModal}
transparent={true}
statusBarTranslucent
animationType="fade"
>
<TouchableWithoutFeedback onPress={() => setNavModal(false)}>
<View
style={{
backgroundColor: "rgba(0,0,0,0.3)",
...tailwind("flex-1"),
}}
>
<View
style={{
...tailwind("items-center absolute bg-white rounded-lg p-2"),
top: headerHeight,
right: 24,
}}
>
<TouchableOpacity
onPress={handleBlock}
style={tailwind("flex-row items-center px-4")}
>
<Icon
type="ionicon"
name="remove-circle"
color="#f87171"
size={24}
/>
<Text style={tailwind("text-base")}>拉黑</Text>
</TouchableOpacity>
<Divider style={tailwind("w-full my-2")} />
<TouchableOpacity
onPress={handleFeedback}
style={tailwind("flex-row items-center px-4")}
>
<Icon type="ionicon" name="warning" color="#60a5fa" size={24} />
<Text style={tailwind("text-base")}>举报</Text>
</TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</Modal>
);
};
// 平台列表
const PlatformList = ({ item }) => {
return (
<View
style={tailwind(
"flex-row justify-between items-center h-12 mt-2 p-2 rounded-xl border-2 border-[#2c2b2f]"
)}
>
<View style={tailwind("flex-row items-center w-1/3")}>
<Image
source={item?.link_icon?.images[0]?.urls[0]}
style={{ aspectRatio: "1/1", ...tailwind("w-8") }}
/>
<Text style={tailwind("text-sm text-white ml-1")}>
{item?.link_name}
</Text>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={tailwind("text-sm text-white ml-1")}
>
{item?.nickname}
</Text>
</View>
<View style={tailwind("flex-row")}>
<TouchableOpacity
onPress={async () => {
await Clipboard.setStringAsync(item.url);
Alert.alert(null, "复制成功");
}}
style={tailwind("flex-row items-center")}
>
<NativeImage source={require("../../assets/icon/24DP/copy.png")} />
<Text style={tailwind("text-xs text-white")}>复制</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => Linking.openURL(item.url)}
style={tailwind("flex-row items-center ml-4")}
>
<NativeImage source={require("../../assets/icon/24DP/goto.png")} />
<Text style={tailwind("text-xs text-white")}>前往</Text>
</TouchableOpacity>
</View>
</View>
);
};
//点击关注按钮
const [isFollowed, setIsFollowed] = useState(false);
const handleFollow = async () => {
const account = await get("account");
if (isFollowed) {
await unfollow(account.mid, data?.mid);
setIsFollowed(!isFollowed);
} else {
await follow(account.mid, data?.mid);
setIsFollowed(!isFollowed);
}
};
//加载页面时检查关注状态
useEffect(() => {
const getRelationData = async () => {
const account = await get("account");
const subMid = account.mid;
const objMid = route.params.mid;
const temIsFollowed = await checkRelation(subMid, objMid, 0);
setIsFollowed(temIsFollowed);
};
getRelationData();
}, []);
//点击私聊
const handleSendMessage = () => {
navigation.navigate("MessageDetail", {
mid: route.params.mid,
});
};
//点击查看微信按钮
const [isAddWechatModalVisible, setIsAddWechatModalVisible] = useState(false);
//加载初始骨架屏
if (isLoading) return <StreamerProfileSkeleton />;
return (
<View style={{ ...tailwind("flex-1"), paddingBottom: insets.bottom }}>
<ScrollView
style={{
paddingBottom: insets.bottom,
paddingLeft: insets.left,
paddingRight: insets.right,
...tailwind("flex-1"),
}}
>
{/* 媒体展示、在线状态 */}
<MySwiper />
<View style={tailwind("flex flex-1 mt-4")}>
<View style={tailwind("flex-1 px-4")}>
{/* 昵称、认证 */}
<View style={tailwind("flex flex-row items-center")}>
<Text
style={tailwind("text-2xl text-white font-medium mr-1")}
numberOfLines={1}
ellipsizeMode="tail"
>
{data?.name}
</Text>
<NativeImage
source={require("../../assets/icon/others/verification.png")}
/>
</View>
{/* tag*/}
<View style={tailwind("flex-row my-2.5")}>
{data?.tag !== undefined &&
data?.tag.map((item, index) => {
if (index > 2) return;
return (
<View
key={index}
style={{
...tailwind("py-1 px-2 rounded-md mr-2"),
backgroundColor: "#FF669E",
}}
>
<Text style={tailwind("text-xs text-white")}>{item}</Text>
</View>
);
})}
</View>
{/* 标签 */}
<View style={tailwind("flex-row flex-wrap pb-4")}>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 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?.user_id}
</Text>
</View>
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/fan.png")}
/>
<Text style={tailwind("text-white text-xs font-medium ml-0.5")}>
{`全网粉丝 : ${data?.fans}`}
</Text>
</View>
{data?.age && (
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
{data?.gender === 1 ? (
<NativeImage
source={require("../../assets/icon/12DP/female.png")}
/>
) : (
<NativeImage
source={require("../../assets/icon/12DP/male.png")}
/>
)}
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{data?.age}
</Text>
</View>
)}
{data?.height && (
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/height.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{`${data?.height}cm`}
</Text>
</View>
)}
{data?.weight && (
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/weight.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{`${data?.weight}kg`}
</Text>
</View>
)}
{data?.constellation && (
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/constellation.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{data?.constellation}
</Text>
</View>
)}
{data?.city && (
<View
style={tailwind(
"flex-row items-center py-0.5 px-2 mr-2 my-1 bg-[#FFFFFF1A] rounded-full"
)}
>
<NativeImage
source={require("../../assets/icon/12DP/location.png")}
/>
<Text
style={tailwind("text-white text-xs font-medium ml-0.5")}
>
{data?.city}
</Text>
</View>
)}
</View>
<View
style={tailwind("h-[3px] rounded-full bg-[#FFFFFF26]")}
></View>
{/* 个性签名 */}
<View style={tailwind("my-4")}>
<Text style={tailwind("text-base font-medium text-white mb-2")}>
个性签名
</Text>
<Text style={tailwind("text-sm text-[#FFFFFFB2]")}>
{data?.bio}
</Text>
</View>
<View
style={tailwind("h-[3px] rounded-full bg-[#FFFFFF26]")}
></View>
{/* 平台 */}
<View style={tailwind("my-4")}>
<Text style={tailwind("text-base text-white font-medium mb-2")}>
来这找我玩
</Text>
<View
style={tailwind(
"flex-row items-center p-2 h-12 rounded-xl border-2 border-[#2c2b2f]"
)}
>
<NativeImage
source={require("../../assets/images/platform_wechat.png")}
style={{ aspectRatio: "1/1", ...tailwind("w-8") }}
/>
<Text style={tailwind("text-sm text-white ml-1")}>微信</Text>
<Text
onPress={() => setIsAddWechatModalVisible(true)}
style={tailwind("text-sm text-[#3B69B8] ml-1")}
numberOfLines={1}
ellipsizeMode="tail"
>
点击查看
</Text>
</View>
{data?.platforms?.map((item) => (
<PlatformList key={item?.id} item={item} />
))}
</View>
</View>
</View>
</ScrollView>
{/* 关注、私聊、查看微信 */}
<View
style={{
borderTopColor: "#FFFFFF26",
...tailwind(
"flex-row py-2 px-4 h-[4.5rem] border-t items-center justify-between"
),
}}
>
<TouchableOpacity
onPress={handleFollow}
style={{
backgroundColor: "#FFFFFF1A",
...tailwind(
"flex-row items-center justify-center h-10 px-6 rounded-full mr-4"
),
}}
>
<Text style={tailwind("text-base text-white font-medium")}>
{isFollowed ? "已关注" : "关注"}
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={handleSendMessage}
style={tailwind(
"flex-row bg-[#FFFFFF1A] items-center justify-center h-10 px-6 rounded-full mr-4"
)}
>
<Text style={tailwind("text-base text-white font-medium")}>私聊</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setIsAddWechatModalVisible(true)}
style={tailwind(
"flex-row flex-1 bg-[#FF669E] items-center justify-center h-10 rounded-full"
)}
>
<Text style={tailwind("text-base text-white font-medium")}>
添加微信
</Text>
</TouchableOpacity>
</View>
{/* 拉黑、举报Modal */}
<NavbarRightModal />
{/* 查看微信Modal */}
{data?.wechat_lock_type === 0 ? (
<GetWechatModal
visible={isAddWechatModalVisible}
setVisible={setIsAddWechatModalVisible}
streamerMid={route.params.mid}
/>
) : (
<SubmitWechatModal
visible={isAddWechatModalVisible}
setVisible={setIsAddWechatModalVisible}
streamerMid={route.params.mid}
/>
)}
</View>
);
}