tiefen_space_app/screeens/StreamerProfile/index.jsx

670 lines
22 KiB
React
Raw Normal View History

2023-12-29 00:27:44 +08:00
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={32}
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
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>
);
}