2024-04-18 22:58:59 +08:00
|
|
|
|
import {
|
|
|
|
|
View,
|
|
|
|
|
Text,
|
|
|
|
|
ScrollView,
|
|
|
|
|
TouchableOpacity,
|
|
|
|
|
KeyboardAvoidingView,
|
|
|
|
|
Platform,
|
|
|
|
|
ActivityIndicator,
|
|
|
|
|
} from "react-native";
|
2024-09-27 16:04:56 +08:00
|
|
|
|
import React, { useState, useEffect, useCallback } from "react";
|
2024-04-18 22:58:59 +08:00
|
|
|
|
import { useTailwind } from "tailwind-rn";
|
|
|
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
|
|
|
import { Divider, Icon, Button } from "@rneui/themed";
|
|
|
|
|
import { Image } from "expo-image";
|
|
|
|
|
import { Formik } from "formik";
|
|
|
|
|
import MediaPicker from "../../components/MediaPicker";
|
|
|
|
|
import Toast from "react-native-toast-message";
|
|
|
|
|
import { get } from "../../utils/storeInfo";
|
|
|
|
|
import { multiUpload } from "../../utils/upload";
|
|
|
|
|
import baseRequest from "../../utils/baseRequest";
|
|
|
|
|
import { generateSignature } from "../../utils/crypto";
|
2024-05-29 16:39:34 +08:00
|
|
|
|
import MediaGrid from "../../components/MediaGrid";
|
2024-09-27 16:04:56 +08:00
|
|
|
|
import * as ImagePicker from "expo-image-picker";
|
|
|
|
|
import * as VideoThumbnails from "expo-video-thumbnails";
|
2024-04-18 22:58:59 +08:00
|
|
|
|
|
|
|
|
|
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
|
|
|
|
|
|
|
|
|
export default function EditStreamerMedia({ navigation, route }) {
|
|
|
|
|
const tailwind = useTailwind();
|
|
|
|
|
const insets = useSafeAreaInsets();
|
|
|
|
|
|
2024-09-27 16:04:56 +08:00
|
|
|
|
//保存封面图
|
2024-04-18 22:58:59 +08:00
|
|
|
|
const [displayImage, setDisplayImage] = useState([]);
|
|
|
|
|
|
2024-09-27 16:04:56 +08:00
|
|
|
|
//选择封面图
|
|
|
|
|
const pickDisPlayImage = async () => {
|
|
|
|
|
let result = await ImagePicker.launchImageLibraryAsync({
|
|
|
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
|
|
|
|
quality: 1,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!result.canceled) {
|
|
|
|
|
setDisplayImage(result.assets);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//保存展示视频
|
2024-04-18 22:58:59 +08:00
|
|
|
|
const [displayVideo, setDisplayVideo] = useState([]);
|
|
|
|
|
|
2024-09-27 16:04:56 +08:00
|
|
|
|
//为视频生成封面
|
|
|
|
|
const generateThumbnail = useCallback(async (uri) => {
|
|
|
|
|
try {
|
|
|
|
|
const videoCover = await VideoThumbnails.getThumbnailAsync(uri);
|
|
|
|
|
return videoCover;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn(e);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
//选择视频
|
|
|
|
|
const pickDisPlayVideo = async () => {
|
|
|
|
|
let result = await ImagePicker.launchImageLibraryAsync({
|
|
|
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Videos,
|
|
|
|
|
quality: 1,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!result.canceled) {
|
|
|
|
|
for (let i = 0; i < result.assets.length; i++) {
|
|
|
|
|
if (result.assets[i].duration > 0) {
|
|
|
|
|
const videoCover = await generateThumbnail(result.assets[i].uri);
|
|
|
|
|
result.assets[i].cover = videoCover.uri;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setDisplayVideo(result.assets);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-18 22:58:59 +08:00
|
|
|
|
//保存新添加的相册图片
|
|
|
|
|
const [photos, setPhotos] = useState([]);
|
|
|
|
|
//展示旧相册图片组件
|
|
|
|
|
const [oldPhotos, setOldPhotos] = useState([]);
|
|
|
|
|
|
|
|
|
|
//正在加载数据
|
|
|
|
|
const [isLoading, setIsloading] = useState(true);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const getData = async () => {
|
|
|
|
|
const account = await get("account");
|
|
|
|
|
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
|
|
|
|
const base = await baseRequest();
|
|
|
|
|
const signature = await generateSignature({
|
|
|
|
|
mid: account?.mid,
|
|
|
|
|
...base,
|
|
|
|
|
});
|
|
|
|
|
try {
|
|
|
|
|
//获取主播数据
|
|
|
|
|
const streamerResponse = await fetch(
|
|
|
|
|
`${apiUrl}/api/streamer/list_by_mid?signature=${signature}`,
|
|
|
|
|
{
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
mid: account?.mid,
|
|
|
|
|
...base,
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
const streamerData = await streamerResponse.json();
|
|
|
|
|
if (streamerData.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
type: "error",
|
|
|
|
|
text1: streamerData.msg,
|
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setDisplayImage([
|
|
|
|
|
{
|
|
|
|
|
notChanged: true,
|
|
|
|
|
id: { image_ids: streamerData.data.streamer.cover.image_ids },
|
|
|
|
|
uri: streamerData.data.streamer.cover.images[0].urls[0],
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
setDisplayVideo([
|
|
|
|
|
{
|
|
|
|
|
notChanged: true,
|
|
|
|
|
id: { video_ids: streamerData.data.streamer.shorts.video_ids },
|
2024-09-27 16:04:56 +08:00
|
|
|
|
cover:
|
2024-04-18 22:58:59 +08:00
|
|
|
|
streamerData?.data?.streamer?.shorts?.videos[0]?.cover_urls[0],
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
setOldPhotos(streamerData.data.streamer.album.images);
|
|
|
|
|
setIsloading(false);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
getData();
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
//正在提交状态
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
|
|
2024-05-29 16:39:34 +08:00
|
|
|
|
//是否正在拖动图片,用于禁用ScrollView的滚动
|
|
|
|
|
const [dragging, setDragging] = useState(false);
|
|
|
|
|
|
2024-04-18 22:58:59 +08:00
|
|
|
|
//loading时展示加载中
|
|
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<ActivityIndicator style={tailwind("mt-32")} size="large" color="white" />
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<KeyboardAvoidingView
|
|
|
|
|
behavior={Platform.OS == "ios" ? "padding" : "height"}
|
|
|
|
|
keyboardVerticalOffset={insets.bottom + 60}
|
|
|
|
|
style={{
|
|
|
|
|
paddingLeft: insets.left,
|
|
|
|
|
paddingRight: insets.right,
|
|
|
|
|
...tailwind("flex-1"),
|
|
|
|
|
}}
|
|
|
|
|
>
|
2024-05-29 16:39:34 +08:00
|
|
|
|
<ScrollView scrollEnabled={!dragging} style={tailwind("px-4 py-4")}>
|
2024-04-18 22:58:59 +08:00
|
|
|
|
<Formik
|
|
|
|
|
initialValues={{}}
|
|
|
|
|
enableReinitialize
|
|
|
|
|
onSubmit={async () => {
|
|
|
|
|
//相册不得低于2张
|
|
|
|
|
if (oldPhotos.length + photos.length < 2) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
type: "error",
|
|
|
|
|
text1: "相册至少需要上传2张照片哦!",
|
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//相册不得超过9张
|
|
|
|
|
if (oldPhotos.length + photos.length > 9) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
type: "error",
|
|
|
|
|
text1: "相册最多只能上传9张照片哦!",
|
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
const account = await get("account");
|
|
|
|
|
const cover = displayImage[0].notChanged
|
|
|
|
|
? displayImage[0].id
|
|
|
|
|
: await multiUpload(displayImage);
|
|
|
|
|
const shorts = displayVideo[0].notChanged
|
|
|
|
|
? displayVideo[0].id
|
|
|
|
|
: await multiUpload(displayVideo);
|
|
|
|
|
const newPhotosIds = await multiUpload(photos);
|
|
|
|
|
const oldPhotosIds = oldPhotos.map((item) => item.id);
|
|
|
|
|
const album = {
|
|
|
|
|
image_ids: [...oldPhotosIds, ...newPhotosIds?.image_ids],
|
|
|
|
|
};
|
|
|
|
|
if (
|
|
|
|
|
!cover.image_ids.length ||
|
|
|
|
|
!shorts.video_ids.length ||
|
|
|
|
|
!album.image_ids.length
|
|
|
|
|
) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
type: "error",
|
|
|
|
|
text1: "上传失败,请联系客服进行上传",
|
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//获取环境变量
|
|
|
|
|
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
|
|
|
|
|
|
|
|
|
//上传表单
|
|
|
|
|
const base = await baseRequest();
|
|
|
|
|
const signature = await generateSignature({
|
|
|
|
|
mid: account?.mid,
|
|
|
|
|
cover: cover,
|
|
|
|
|
shorts: shorts,
|
|
|
|
|
album: album,
|
|
|
|
|
...base,
|
|
|
|
|
});
|
|
|
|
|
try {
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`${apiUrl}/api/streamer/update?signature=${signature}`,
|
|
|
|
|
{
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: {
|
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
mid: account?.mid,
|
|
|
|
|
cover: cover,
|
|
|
|
|
shorts: shorts,
|
|
|
|
|
album: album,
|
|
|
|
|
...base,
|
|
|
|
|
}),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
const streamerData = await response.json();
|
|
|
|
|
if (streamerData.ret === -1) {
|
|
|
|
|
Toast.show({
|
|
|
|
|
type: "error",
|
|
|
|
|
text1: streamerData.msg,
|
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//提交成功后弹窗提示并返回上级
|
|
|
|
|
Toast.show({
|
2024-09-27 16:23:36 +08:00
|
|
|
|
type: "info",
|
|
|
|
|
text1: "提交成功,等耐心等待审核",
|
2024-04-18 22:58:59 +08:00
|
|
|
|
topOffset: 60,
|
|
|
|
|
});
|
|
|
|
|
navigation.goBack();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error);
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{({ handleSubmit }) => (
|
|
|
|
|
<>
|
|
|
|
|
<Text style={tailwind("text-sm text-[#F53030] font-medium")}>
|
|
|
|
|
将展示在“推荐”、“主页”、“空间”,请认真完善
|
|
|
|
|
</Text>
|
|
|
|
|
<View style={tailwind("my-2 bg-[#FFFFFF1A] p-2 rounded-2xl")}>
|
|
|
|
|
<View style={tailwind("flex-row justify-between items-center")}>
|
|
|
|
|
<Text style={tailwind("text-base text-white font-medium")}>
|
|
|
|
|
<Text style={tailwind("text-[#F53030]")}>*</Text>
|
|
|
|
|
封面图
|
|
|
|
|
</Text>
|
|
|
|
|
<TouchableOpacity
|
2024-09-27 16:04:56 +08:00
|
|
|
|
onPress={() => pickDisPlayImage()}
|
2024-04-18 22:58:59 +08:00
|
|
|
|
style={tailwind("flex-row items-center")}
|
|
|
|
|
>
|
|
|
|
|
{displayImage.length !== 0 ? (
|
|
|
|
|
<Image
|
|
|
|
|
style={tailwind("w-12 h-12 rounded-lg")}
|
|
|
|
|
source={displayImage[0].uri}
|
|
|
|
|
placeholder={blurhash}
|
|
|
|
|
contentFit="cover"
|
|
|
|
|
transition={1000}
|
|
|
|
|
cachePolicy="disk"
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<Text
|
|
|
|
|
style={tailwind("text-xs text-[#FFFFFF80] font-medium")}
|
|
|
|
|
>
|
|
|
|
|
请尽量选择横屏照片
|
|
|
|
|
</Text>
|
|
|
|
|
)}
|
|
|
|
|
<Icon
|
|
|
|
|
name="chevron-forward-outline"
|
|
|
|
|
type="ionicon"
|
|
|
|
|
color="white"
|
|
|
|
|
/>
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
</View>
|
|
|
|
|
<Divider style={tailwind("my-2")} />
|
|
|
|
|
<View style={tailwind("flex-row justify-between items-center")}>
|
|
|
|
|
<Text style={tailwind("text-base text-white font-medium")}>
|
|
|
|
|
<Text style={tailwind("text-[#F53030]")}>*</Text>
|
|
|
|
|
展示视频
|
|
|
|
|
</Text>
|
|
|
|
|
<TouchableOpacity
|
2024-09-27 16:04:56 +08:00
|
|
|
|
onPress={() => pickDisPlayVideo()}
|
2024-04-18 22:58:59 +08:00
|
|
|
|
style={tailwind("flex-row items-center")}
|
|
|
|
|
>
|
|
|
|
|
{displayVideo.length !== 0 ? (
|
|
|
|
|
<Image
|
|
|
|
|
style={tailwind("w-12 h-16 rounded-lg")}
|
2024-09-27 16:04:56 +08:00
|
|
|
|
source={displayVideo[0].cover}
|
2024-04-18 22:58:59 +08:00
|
|
|
|
placeholder={blurhash}
|
|
|
|
|
contentFit="cover"
|
|
|
|
|
transition={1000}
|
|
|
|
|
cachePolicy="disk"
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<Text
|
|
|
|
|
style={tailwind("text-xs text-[#FFFFFF80] font-medium")}
|
|
|
|
|
>
|
|
|
|
|
请选择60秒内短视频
|
|
|
|
|
</Text>
|
|
|
|
|
)}
|
|
|
|
|
<Icon
|
|
|
|
|
name="chevron-forward-outline"
|
|
|
|
|
type="ionicon"
|
|
|
|
|
color="white"
|
|
|
|
|
/>
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
</View>
|
|
|
|
|
<Divider style={tailwind("my-2")} />
|
|
|
|
|
<View>
|
|
|
|
|
<View
|
|
|
|
|
style={tailwind("flex-row justify-between items-center")}
|
|
|
|
|
>
|
|
|
|
|
<Text style={tailwind("text-base text-white font-medium")}>
|
|
|
|
|
<Text style={tailwind("text-[#F53030]")}>*</Text>
|
|
|
|
|
相册
|
|
|
|
|
</Text>
|
|
|
|
|
<Text
|
|
|
|
|
style={tailwind("text-xs text-[#FFFFFF80] font-medium")}
|
|
|
|
|
>
|
|
|
|
|
请上传2~9张照片
|
|
|
|
|
</Text>
|
|
|
|
|
</View>
|
2024-05-29 16:39:34 +08:00
|
|
|
|
<MediaGrid
|
|
|
|
|
setDragging={setDragging}
|
|
|
|
|
assets={oldPhotos}
|
|
|
|
|
setAssets={setOldPhotos}
|
|
|
|
|
/>
|
2024-04-18 22:58:59 +08:00
|
|
|
|
<MediaPicker
|
2024-05-29 16:39:34 +08:00
|
|
|
|
setDragging={setDragging}
|
2024-04-18 22:58:59 +08:00
|
|
|
|
maxCount={9}
|
|
|
|
|
type="image"
|
|
|
|
|
setAssets={setPhotos}
|
|
|
|
|
/>
|
|
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
<Button
|
|
|
|
|
color="#FF669E"
|
|
|
|
|
radius="999"
|
|
|
|
|
size="md"
|
|
|
|
|
disabled={isSubmitting}
|
|
|
|
|
disabledStyle={tailwind("bg-[#FFFFFF80]")}
|
|
|
|
|
disabledTitleStyle={tailwind("text-white")}
|
|
|
|
|
onPress={(e) => {
|
|
|
|
|
handleSubmit(e);
|
|
|
|
|
}}
|
|
|
|
|
titleStyle={tailwind("text-base")}
|
|
|
|
|
containerStyle={{
|
|
|
|
|
marginBottom: insets.bottom + 60,
|
|
|
|
|
...tailwind("mt-4"),
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{isSubmitting && (
|
|
|
|
|
<ActivityIndicator size="small" color="white" />
|
|
|
|
|
)}
|
|
|
|
|
{isSubmitting ? "正在提交..." : "确认修改"}
|
|
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</Formik>
|
|
|
|
|
</ScrollView>
|
|
|
|
|
</KeyboardAvoidingView>
|
|
|
|
|
);
|
|
|
|
|
}
|