Merge remote-tracking branch 'origin/main' into anln
This commit is contained in:
commit
5acfed8ed6
8
app.json
8
app.json
|
@ -2,7 +2,7 @@
|
|||
"expo": {
|
||||
"name": "铁粉空间",
|
||||
"slug": "ironfans",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"splash": {
|
||||
|
@ -57,6 +57,12 @@
|
|||
"isAccessMediaLocationEnabled": true
|
||||
}
|
||||
],
|
||||
[
|
||||
"expo-image-picker",
|
||||
{
|
||||
"photosPermission": "当您授权允许访问相册后,您能够在APP中浏览相册中的图片,以便您选择合适的图片进行上传,用于头像或其他位置"
|
||||
}
|
||||
],
|
||||
[
|
||||
"@sentry/react-native/expo",
|
||||
{
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { View, TouchableOpacity, Image } from "react-native";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { Icon } from "@rneui/themed";
|
||||
import MediaPickerModal from "../MediaPickerModal";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { DraggableGrid } from "react-native-draggable-grid";
|
||||
import { useImageViewer } from "../../context/ImageViewProvider";
|
||||
import VideoModal from "../VideoModal";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import * as VideoThumbnails from "expo-video-thumbnails";
|
||||
|
||||
/*
|
||||
props格式:
|
||||
|
@ -19,11 +20,10 @@ props格式:
|
|||
export default function MediaPicker({
|
||||
setDragging = () => null,
|
||||
maxCount,
|
||||
type,
|
||||
type = "image",
|
||||
setAssets,
|
||||
}) {
|
||||
const tailwind = useTailwind();
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [newAssets, setNewAssets] = useState([]);
|
||||
const [_assets, set_Assets] = useState([]);
|
||||
|
||||
|
@ -32,6 +32,44 @@ export default function MediaPicker({
|
|||
const [showVideo, setShowVideo] = useState(false);
|
||||
const [videoUrl, setVideoUrl] = useState("");
|
||||
|
||||
//为视频生成封面
|
||||
const generateThumbnail = useCallback(async (uri) => {
|
||||
try {
|
||||
const videoCover = await VideoThumbnails.getThumbnailAsync(uri);
|
||||
return videoCover;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}, []);
|
||||
|
||||
//选择媒体
|
||||
const pickMedia = async () => {
|
||||
let mediaType;
|
||||
if (type === "image") {
|
||||
mediaType = ImagePicker.MediaTypeOptions.Images;
|
||||
} else if (type === "video") {
|
||||
mediaType = ImagePicker.MediaTypeOptions.Videos;
|
||||
} else {
|
||||
mediaType = ImagePicker.MediaTypeOptions.All;
|
||||
}
|
||||
let result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: mediaType,
|
||||
allowsMultipleSelection: true,
|
||||
selectionLimit: maxCount - _assets.length,
|
||||
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;
|
||||
}
|
||||
}
|
||||
setNewAssets(result.assets);
|
||||
}
|
||||
};
|
||||
|
||||
//当newAssets改变的时候添加新数据到assets
|
||||
useEffect(() => {
|
||||
const temAssets = newAssets.map((item) => ({
|
||||
|
@ -49,7 +87,7 @@ export default function MediaPicker({
|
|||
onPress={() => {
|
||||
//数量检查
|
||||
maxCount - _assets.length !== 0
|
||||
? setModalVisible(!modalVisible)
|
||||
? pickMedia()
|
||||
: Toast.show({
|
||||
type: "error",
|
||||
text1: `已达到最大选择数量`,
|
||||
|
@ -90,8 +128,11 @@ export default function MediaPicker({
|
|||
}}
|
||||
key={item.key}
|
||||
>
|
||||
<Image src={item.old_uri} style={tailwind("w-full h-full rounded")} />
|
||||
<View style={tailwind("absolute top-2 right-2")}>
|
||||
<Image
|
||||
src={item.cover ? item.cover : item.uri}
|
||||
style={tailwind("w-full h-full rounded")}
|
||||
/>
|
||||
<View style={{ zIndex: 999, ...tailwind("absolute top-2 right-2") }}>
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="close"
|
||||
|
@ -101,7 +142,7 @@ export default function MediaPicker({
|
|||
style={tailwind("bg-black rounded-full opacity-70")}
|
||||
/>
|
||||
</View>
|
||||
{item.duration !== 0 && (
|
||||
{item.duration > 0 && (
|
||||
<View
|
||||
style={tailwind(
|
||||
"absolute flex w-full h-full items-center justify-center"
|
||||
|
@ -133,9 +174,9 @@ export default function MediaPicker({
|
|||
setDragging(false);
|
||||
}}
|
||||
onItemPress={(item) => {
|
||||
if (item.duration === 0) {
|
||||
if (!item.duration) {
|
||||
showImageViewer({
|
||||
imageUrls: [{ url: item.old_uri }],
|
||||
imageUrls: [{ url: item.uri }],
|
||||
index: 0,
|
||||
});
|
||||
return;
|
||||
|
@ -145,13 +186,6 @@ export default function MediaPicker({
|
|||
}}
|
||||
/>
|
||||
<Picker />
|
||||
<MediaPickerModal
|
||||
visible={modalVisible}
|
||||
setVisible={setModalVisible}
|
||||
type={type}
|
||||
maxCount={maxCount - _assets.length}
|
||||
setAssets={setNewAssets}
|
||||
/>
|
||||
<VideoModal
|
||||
visible={showVideo}
|
||||
setVisible={setShowVideo}
|
||||
|
|
|
@ -1,351 +0,0 @@
|
|||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
Image,
|
||||
Modal,
|
||||
Platform,
|
||||
} from "react-native";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { ImagePicker } from "expo-image-multiple-picker";
|
||||
import { Icon, Badge } from "@rneui/themed";
|
||||
import * as MediaLibrary from "expo-media-library";
|
||||
import * as Linking from "expo-linking";
|
||||
import MyModal from "../MyModal";
|
||||
|
||||
/*
|
||||
props格式:
|
||||
visible 控制modal可见性
|
||||
setVisible 控制modal可见性
|
||||
type 选择的媒体类型 "image"|"video"|"mix"
|
||||
maxCount 最大选择数量
|
||||
setAssets 向父组件返回媒体
|
||||
*/
|
||||
|
||||
export default function MediaPickerModal({
|
||||
visible,
|
||||
setVisible,
|
||||
type,
|
||||
maxCount,
|
||||
setAssets,
|
||||
}) {
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [album, setAlbum] = useState({ title: "全部" });
|
||||
|
||||
//前往打开权限弹窗
|
||||
const [requestModalVisible, setRequestModalVisible] = useState(false);
|
||||
//前往打开权限弹窗
|
||||
const [overlayVisible, setOverlayVisible] = useState(false);
|
||||
//保存当前权限状态
|
||||
const [permissionStatus, setPermissionStatus] = useState();
|
||||
|
||||
//检查并获取权限
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
async function checkMediaLibraryPermissions() {
|
||||
//权限检查、获取
|
||||
// 第一步:检查是否已有权限
|
||||
const { status } = await MediaLibrary.getPermissionsAsync();
|
||||
if (status === "granted") {
|
||||
// 如果已有权限,直接执行操作
|
||||
setPermissionStatus("granted");
|
||||
return;
|
||||
}
|
||||
if (status === "undetermined") {
|
||||
setRequestModalVisible(true);
|
||||
return;
|
||||
}
|
||||
if (status === "denied") {
|
||||
requestMediaLibraryPermissions();
|
||||
}
|
||||
}
|
||||
checkMediaLibraryPermissions();
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
async function requestMediaLibraryPermissions() {
|
||||
const permission = await MediaLibrary.requestPermissionsAsync();
|
||||
if (permission.status === "denied") {
|
||||
// 用户拒绝了权限请求,打开应用设置页面
|
||||
setPermissionStatus("denied");
|
||||
setVisible(false);
|
||||
setOverlayVisible(true);
|
||||
return;
|
||||
}
|
||||
if (permission.status === "granted") {
|
||||
// 用户同意了权限请求,执行操作
|
||||
setPermissionStatus("granted");
|
||||
}
|
||||
}
|
||||
|
||||
//将ios中assets的路径从ph://改为file://
|
||||
const changeToLocalUri = async (assets) => {
|
||||
const editedAssets = await Promise.all(
|
||||
assets.map(async (item) => {
|
||||
const info = await MediaLibrary.getAssetInfoAsync(item.id);
|
||||
const uri = info.localUri;
|
||||
if (Platform.OS === "ios") {
|
||||
return { ...item, old_uri: item.uri, uri };
|
||||
}
|
||||
return { ...item, old_uri: item.uri };
|
||||
})
|
||||
);
|
||||
return editedAssets;
|
||||
};
|
||||
|
||||
//让视频秒数格式化
|
||||
function formatDuration(duration) {
|
||||
let minutes = Math.floor(duration / 60);
|
||||
let seconds = Math.round(duration % 60);
|
||||
if (seconds < 10) {
|
||||
seconds = "0" + seconds;
|
||||
}
|
||||
return `${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
//header组件
|
||||
const ImagePickerHeader = (props) => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingTop: insets.top,
|
||||
height: 100,
|
||||
...tailwind(
|
||||
"px-4 bg-[#07050A] flex-row justify-between items-center"
|
||||
),
|
||||
}}
|
||||
>
|
||||
{props.view == "album" && (
|
||||
<>
|
||||
<View style={tailwind("w-10")}></View>
|
||||
<Text
|
||||
style={tailwind("text-lg text-center text-white font-medium")}
|
||||
>
|
||||
选择相册
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FF669E",
|
||||
...tailwind("text-lg font-semibold ml-1"),
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</>
|
||||
)}
|
||||
{props.view == "gallery" && (
|
||||
<>
|
||||
<TouchableOpacity onPress={props.goToAlbum}>
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="chevron-back"
|
||||
color="white"
|
||||
size={32}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<Text
|
||||
style={tailwind(
|
||||
"text-lg text-center text-white font-medium w-1/2"
|
||||
)}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{props.album.title}
|
||||
</Text>
|
||||
|
||||
{props.imagesPicked > 0 ? (
|
||||
<TouchableOpacity
|
||||
onPress={props.save}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
<Badge
|
||||
value={props.imagesPicked}
|
||||
badgeStyle={{
|
||||
backgroundColor: "#FF669E",
|
||||
borderColor: "#FF669E",
|
||||
}}
|
||||
textStyle={tailwind("text-white font-medium")}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FF669E",
|
||||
...tailwind("text-lg font-semibold ml-1"),
|
||||
}}
|
||||
>
|
||||
完成
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#FF669E",
|
||||
...tailwind("text-lg font-semibold ml-1"),
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
//check组件
|
||||
const ImagePickerCheck = () => {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundColor: "rgba(0,0,0,0.6)",
|
||||
}}
|
||||
>
|
||||
<Icon type="ionicon" name="checkmark" color="white" size={32} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
//album组件
|
||||
const ImagePickerAlbum = (props) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => props.goToGallery(props.album)}
|
||||
style={{ flex: 1, height: 200 }}
|
||||
>
|
||||
<Image
|
||||
source={{ uri: props.thumb.uri }}
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
blurRadius={10}
|
||||
></Image>
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "rgba(0,0,0,0.2)",
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<View style={{ padding: 5, flexDirection: "row" }}>
|
||||
<Icon type="ionicon" name="folder-open" color="white" size={16} />
|
||||
<Text
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: 16,
|
||||
marginLeft: 5,
|
||||
}}
|
||||
>
|
||||
{props.album.title}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
//video组件
|
||||
const ImagePickerVideo = (props) => {
|
||||
return (
|
||||
<View style={tailwind("flex-1 justify-end")}>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex-row justify-between items-center bg-black px-2"
|
||||
)}
|
||||
>
|
||||
<Icon type="ionicon" name="videocam" color="white" size={16} />
|
||||
<Text numberOfLines={1} style={tailwind("text-xs text-white")}>
|
||||
{formatDuration(props.duration)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
visible={visible && permissionStatus == "granted"}
|
||||
transparent={true}
|
||||
statusBarTranslucent
|
||||
animationType="slide"
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
...tailwind("bg-[#13121F] flex-1"),
|
||||
}}
|
||||
>
|
||||
<ImagePicker
|
||||
theme={{
|
||||
header: ImagePickerHeader,
|
||||
check: ImagePickerCheck,
|
||||
album: ImagePickerAlbum,
|
||||
video: ImagePickerVideo,
|
||||
}}
|
||||
onSave={async (assets) => {
|
||||
setVisible(false);
|
||||
const editedAssets = await changeToLocalUri(assets);
|
||||
setAssets(editedAssets);
|
||||
}}
|
||||
onCancel={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
galleryColumns={3}
|
||||
albumColumns={2}
|
||||
multiple
|
||||
onSelectAlbum={(album) => setAlbum(album)}
|
||||
selectedAlbum={album}
|
||||
limit={maxCount}
|
||||
video={type === "video" || type === "mix"}
|
||||
image={type === "image" || type === "mix"}
|
||||
/>
|
||||
</View>
|
||||
</Modal>
|
||||
<MyModal
|
||||
visible={requestModalVisible}
|
||||
setVisible={setRequestModalVisible}
|
||||
title="权限申请"
|
||||
content="该功能需要开启存储权限,用于选择上传媒体文件"
|
||||
confirmText="继续"
|
||||
custom={() => {
|
||||
setRequestModalVisible(false);
|
||||
requestMediaLibraryPermissions();
|
||||
}}
|
||||
customText="继续"
|
||||
/>
|
||||
<MyModal
|
||||
visible={overlayVisible}
|
||||
setVisible={setOverlayVisible}
|
||||
title="未获得相册权限"
|
||||
content="请先前往设置打开相关权限后重试"
|
||||
confirmText="去设置"
|
||||
cancel={() => {
|
||||
setOverlayVisible(false);
|
||||
}}
|
||||
confirm={() => {
|
||||
Linking.openSettings();
|
||||
setOverlayVisible(false);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
"expo-file-system": "~17.0.1",
|
||||
"expo-image": "~1.12.15",
|
||||
"expo-image-manipulator": "~12.0.5",
|
||||
"expo-image-multiple-picker": "^4.8.3",
|
||||
"expo-image-picker": "~15.0.7",
|
||||
"expo-intent-launcher": "~11.0.1",
|
||||
"expo-linear-gradient": "~13.0.2",
|
||||
"expo-linking": "~6.3.1",
|
||||
|
|
|
@ -251,8 +251,8 @@ export default function EditSpacePost({ navigation, route }) {
|
|||
}
|
||||
//提交成功后显示Toast并返回上一页
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "编辑成功",
|
||||
type: "info",
|
||||
text1: "提交成功,等耐心等待审核",
|
||||
topOffset: 60,
|
||||
});
|
||||
navigation.goBack();
|
||||
|
|
|
@ -7,13 +7,12 @@ import {
|
|||
Platform,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
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 MediaPickerModal from "../../components/MediaPickerModal";
|
||||
import MediaPicker from "../../components/MediaPicker";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { get } from "../../utils/storeInfo";
|
||||
|
@ -21,6 +20,8 @@ import { multiUpload } from "../../utils/upload";
|
|||
import baseRequest from "../../utils/baseRequest";
|
||||
import { generateSignature } from "../../utils/crypto";
|
||||
import MediaGrid from "../../components/MediaGrid";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import * as VideoThumbnails from "expo-video-thumbnails";
|
||||
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
|
@ -28,16 +29,52 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
//保存封面图以及控制上传封面图Modal出现
|
||||
const [displayImagePickerModalVisible, setDisplayImagePickerModalVisible] =
|
||||
useState(false);
|
||||
//保存封面图
|
||||
const [displayImage, setDisplayImage] = useState([]);
|
||||
|
||||
//保存展示视频以及控制上传展示视频Modal出现
|
||||
const [displayVideoPickerModalVisible, setDisplayVideoPickerModalVisible] =
|
||||
useState(false);
|
||||
//选择封面图
|
||||
const pickDisPlayImage = async () => {
|
||||
let result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (!result.canceled) {
|
||||
setDisplayImage(result.assets);
|
||||
}
|
||||
};
|
||||
|
||||
//保存展示视频
|
||||
const [displayVideo, setDisplayVideo] = useState([]);
|
||||
|
||||
//为视频生成封面
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
//保存新添加的相册图片
|
||||
const [photos, setPhotos] = useState([]);
|
||||
//展示旧相册图片组件
|
||||
|
@ -89,7 +126,7 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
{
|
||||
notChanged: true,
|
||||
id: { video_ids: streamerData.data.streamer.shorts.video_ids },
|
||||
old_uri:
|
||||
cover:
|
||||
streamerData?.data?.streamer?.shorts?.videos[0]?.cover_urls[0],
|
||||
},
|
||||
]);
|
||||
|
@ -215,8 +252,8 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
}
|
||||
//提交成功后弹窗提示并返回上级
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "更改成功",
|
||||
type: "info",
|
||||
text1: "提交成功,等耐心等待审核",
|
||||
topOffset: 60,
|
||||
});
|
||||
navigation.goBack();
|
||||
|
@ -239,7 +276,7 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
封面图
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setDisplayImagePickerModalVisible(true)}
|
||||
onPress={() => pickDisPlayImage()}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
{displayImage.length !== 0 ? (
|
||||
|
@ -264,13 +301,6 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
color="white"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<MediaPickerModal
|
||||
visible={displayImagePickerModalVisible}
|
||||
setVisible={setDisplayImagePickerModalVisible}
|
||||
type="image"
|
||||
maxCount={1}
|
||||
setAssets={setDisplayImage}
|
||||
/>
|
||||
</View>
|
||||
<Divider style={tailwind("my-2")} />
|
||||
<View style={tailwind("flex-row justify-between items-center")}>
|
||||
|
@ -279,13 +309,13 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
展示视频
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setDisplayVideoPickerModalVisible(true)}
|
||||
onPress={() => pickDisPlayVideo()}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
{displayVideo.length !== 0 ? (
|
||||
<Image
|
||||
style={tailwind("w-12 h-16 rounded-lg")}
|
||||
source={displayVideo[0].old_uri}
|
||||
source={displayVideo[0].cover}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
|
@ -304,13 +334,6 @@ export default function EditStreamerMedia({ navigation, route }) {
|
|||
color="white"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<MediaPickerModal
|
||||
visible={displayVideoPickerModalVisible}
|
||||
setVisible={setDisplayVideoPickerModalVisible}
|
||||
type="video"
|
||||
maxCount={1}
|
||||
setAssets={setDisplayVideo}
|
||||
/>
|
||||
</View>
|
||||
<Divider style={tailwind("my-2")} />
|
||||
<View>
|
||||
|
|
|
@ -343,8 +343,8 @@ export default function EditStreamerProfile({ navigation, route }) {
|
|||
}
|
||||
//提交成功后弹窗提示并返回上级
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "更改成功",
|
||||
type: "info",
|
||||
text1: "提交成功,等耐心等待审核",
|
||||
topOffset: 60,
|
||||
});
|
||||
navigation.goBack();
|
||||
|
|
|
@ -4,13 +4,13 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|||
import { useTailwind } from "tailwind-rn";
|
||||
import { Image } from "expo-image";
|
||||
import { Divider, Icon } from "@rneui/themed";
|
||||
import MediaPickerModal from "../../../components/MediaPickerModal";
|
||||
import { get, save } from "../../../utils/storeInfo";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { uploadImage } from "../../../utils/upload";
|
||||
import baseRequest from "../../../utils/baseRequest";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { generateSignature } from "../../../utils/crypto";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
|
@ -20,7 +20,19 @@ export default function SelectUserProfileItem({ navigation, route }) {
|
|||
|
||||
//选取头像
|
||||
const [head, setHead] = useState([]);
|
||||
const [mediaPickerModalVisible, setMediaPickerModalVisible] = useState(false);
|
||||
|
||||
const pickImage = async () => {
|
||||
let result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
allowsEditing: true,
|
||||
aspect: [1, 1],
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (!result.canceled) {
|
||||
setHead(result.assets);
|
||||
}
|
||||
};
|
||||
|
||||
//获取页面数据
|
||||
const [data, setData] = useState({});
|
||||
|
@ -124,18 +136,11 @@ export default function SelectUserProfileItem({ navigation, route }) {
|
|||
...tailwind("flex-1"),
|
||||
}}
|
||||
>
|
||||
<MediaPickerModal
|
||||
visible={mediaPickerModalVisible}
|
||||
setVisible={setMediaPickerModalVisible}
|
||||
type="image"
|
||||
maxCount={1}
|
||||
setAssets={setHead}
|
||||
/>
|
||||
<View style={tailwind("px-4")}>
|
||||
<View style={tailwind("flex-row justify-between items-center mt-2")}>
|
||||
<Text style={tailwind("text-base text-white font-medium")}>头像</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setMediaPickerModalVisible(!mediaPickerModalVisible)}
|
||||
onPress={pickImage}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
<Image
|
||||
|
|
|
@ -12,7 +12,7 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|||
import Toast from "react-native-toast-message";
|
||||
import baseRequest from "../../../utils/baseRequest";
|
||||
import { generateSignature } from "../../../utils/crypto";
|
||||
import { Button, Divider, CheckBox, Switch, Icon } from "@rneui/themed";
|
||||
import { Button, Icon } from "@rneui/themed";
|
||||
import MyDivider from "../../../components/MyDivider";
|
||||
|
||||
export default function SpaceIntroSetting({ navigation, route }) {
|
||||
|
@ -69,8 +69,8 @@ export default function SpaceIntroSetting({ navigation, route }) {
|
|||
return;
|
||||
}
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "修改成功,请重进空间刷新查看",
|
||||
type: "info",
|
||||
text1: "提交成功,等耐心等待审核",
|
||||
topOffset: 60,
|
||||
});
|
||||
navigation.goBack();
|
||||
|
|
|
@ -15,7 +15,6 @@ import { Divider, Icon, Button, CheckBox } from "@rneui/themed";
|
|||
import { Image } from "expo-image";
|
||||
import { Formik } from "formik";
|
||||
import Picker from "../../../components/Picker";
|
||||
import MediaPickerModal from "../../../components/MediaPickerModal";
|
||||
import MediaPicker from "../../../components/MediaPicker";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { get } from "../../../utils/storeInfo";
|
||||
|
@ -23,6 +22,8 @@ import { multiUpload } from "../../../utils/upload";
|
|||
import baseRequest from "../../../utils/baseRequest";
|
||||
import { generateSignature } from "../../../utils/crypto";
|
||||
import MediaGrid from "../../../components/MediaGrid";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import * as VideoThumbnails from "expo-video-thumbnails";
|
||||
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
|
@ -31,14 +32,51 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
const insets = useSafeAreaInsets();
|
||||
|
||||
//保存封面图以及控制上传封面图Modal出现
|
||||
const [displayImagePickerModalVisible, setDisplayImagePickerModalVisible] =
|
||||
useState(false);
|
||||
const [displayImage, setDisplayImage] = useState([]);
|
||||
|
||||
//保存展示视频以及控制上传展示视频Modal出现
|
||||
const [displayVideoPickerModalVisible, setDisplayVideoPickerModalVisible] =
|
||||
useState(false);
|
||||
//选择封面图
|
||||
const pickDisPlayImage = async () => {
|
||||
let result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
if (!result.canceled) {
|
||||
setDisplayImage(result.assets);
|
||||
}
|
||||
};
|
||||
|
||||
//保存展示视频
|
||||
const [displayVideo, setDisplayVideo] = useState([]);
|
||||
|
||||
//为视频生成封面
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
const [wechatInputShow, setWechatInputShow] = useState(1);
|
||||
|
||||
//保存新添加的相册图片
|
||||
|
@ -234,7 +272,7 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
{
|
||||
notChanged: true,
|
||||
id: { video_ids: _data.data.list[0].shorts?.video_ids },
|
||||
old_uri: _data.data.list[0].shorts?.videos[0]?.cover_urls[0],
|
||||
cover: _data.data.list[0].shorts?.videos[0]?.cover_urls[0],
|
||||
},
|
||||
]);
|
||||
setOldPhotos(_data.data.list[0].album.images);
|
||||
|
@ -503,7 +541,7 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
//提交成功后toast提示并返回“我的”页面
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "提交成功",
|
||||
text1: "提交成功,请耐心等待审核",
|
||||
topOffset: 60,
|
||||
});
|
||||
navigation.goBack();
|
||||
|
@ -748,7 +786,7 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
封面图
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setDisplayImagePickerModalVisible(true)}
|
||||
onPress={() => pickDisPlayImage()}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
{displayImage.length !== 0 ? (
|
||||
|
@ -773,13 +811,6 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
color="white"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<MediaPickerModal
|
||||
visible={displayImagePickerModalVisible}
|
||||
setVisible={setDisplayImagePickerModalVisible}
|
||||
type="image"
|
||||
maxCount={1}
|
||||
setAssets={setDisplayImage}
|
||||
/>
|
||||
</View>
|
||||
<Divider style={tailwind("my-2")} />
|
||||
<View style={tailwind("flex-row justify-between items-center")}>
|
||||
|
@ -788,13 +819,13 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
展示视频
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setDisplayVideoPickerModalVisible(true)}
|
||||
onPress={() => pickDisPlayVideo()}
|
||||
style={tailwind("flex-row items-center")}
|
||||
>
|
||||
{displayVideo.length !== 0 ? (
|
||||
<Image
|
||||
style={tailwind("w-12 h-16 rounded-lg")}
|
||||
source={displayVideo[0].old_uri}
|
||||
source={displayVideo[0].cover}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
|
@ -813,13 +844,6 @@ export default function CompleteStreamerInformation({ navigation, route }) {
|
|||
color="white"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<MediaPickerModal
|
||||
visible={displayVideoPickerModalVisible}
|
||||
setVisible={setDisplayVideoPickerModalVisible}
|
||||
type="video"
|
||||
maxCount={1}
|
||||
setAssets={setDisplayVideo}
|
||||
/>
|
||||
</View>
|
||||
<Divider style={tailwind("my-2")} />
|
||||
<View>
|
||||
|
|
|
@ -217,7 +217,7 @@ export async function uploadVideo(asset) {
|
|||
src_id: auth.directory + "/" + auth.filename,
|
||||
cover_id: videoCoverId,
|
||||
md5: md5,
|
||||
dur: asset?.duration,
|
||||
dur: asset?.duration / 1000,
|
||||
fmt: fileType,
|
||||
};
|
||||
const base = await baseRequest();
|
||||
|
@ -275,7 +275,7 @@ export async function uploadVideo(asset) {
|
|||
export async function multiUpload(assets) {
|
||||
let ids = { image_ids: [], video_ids: [] };
|
||||
const tasks = assets.map(async (asset, index) => {
|
||||
if (asset.duration === 0) {
|
||||
if (!asset.duration) {
|
||||
const id = await uploadImage(asset);
|
||||
ids.image_ids[index] = id;
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue