增加查看原图功能;增加检查铁粉进度功能
This commit is contained in:
parent
e44b611998
commit
f5487d23b5
|
@ -19,8 +19,10 @@ import MyModal from "../MyModal";
|
|||
import { Image } from "expo-image";
|
||||
import { Button } from "@rneui/themed";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { generateSignature } from "../../utils/crypto";
|
||||
import baseRequest from "../../utils/baseRequest";
|
||||
|
||||
//imageUrls [{ url: string }]
|
||||
//imageUrls [{ url: string , id: int }] 网络图片需要查看原图时才传id,其他情况不用
|
||||
//index int
|
||||
//lockedStartIndex int
|
||||
//onPressUnlockBtn () => void
|
||||
|
@ -33,6 +35,7 @@ export function ImageViewer({
|
|||
index,
|
||||
lockedStartIndex,
|
||||
onPressUnlockBtn,
|
||||
setImageViewerProps,
|
||||
}) {
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
@ -57,76 +60,6 @@ export function ImageViewer({
|
|||
return false;
|
||||
}, []);
|
||||
|
||||
const MenusComponent = useCallback(
|
||||
({ cancel, saveToLocal }) => (
|
||||
<Modal
|
||||
visible={true}
|
||||
transparent={true}
|
||||
statusBarTranslucent
|
||||
animationType="fade"
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={cancel}
|
||||
activeOpacity={1}
|
||||
style={tailwind("flex flex-1 bg-[#00000080]")}
|
||||
>
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
style={{
|
||||
paddingBottom: insets.bottom,
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
...tailwind(
|
||||
"absolute bottom-0 left-0 h-32 w-full bg-[#13121F] rounded-t-2xl"
|
||||
),
|
||||
}}
|
||||
>
|
||||
<View style={tailwind("flex flex-1 flex-row items-center px-4")}>
|
||||
<TouchableOpacity
|
||||
onPress={async () => {
|
||||
const isVip = await checkRole();
|
||||
if (isVip) {
|
||||
saveToLocal();
|
||||
return;
|
||||
}
|
||||
closeImageViewer();
|
||||
navigation.navigate("WebWithoutHeader", {
|
||||
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
|
||||
});
|
||||
}}
|
||||
style={tailwind("flex flex-col items-center px-4")}
|
||||
>
|
||||
<Icon type="ionicon" name="image" size={30} color="white" />
|
||||
<Text
|
||||
style={tailwind("text-sm text-[#FFFFFF80] font-medium mt-1")}
|
||||
>
|
||||
保存(会员特权)
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={cancel}
|
||||
style={tailwind("flex flex-col items-center px-4")}
|
||||
>
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="close-circle"
|
||||
size={30}
|
||||
color="white"
|
||||
/>
|
||||
<Text
|
||||
style={tailwind("text-sm text-[#FFFFFF80] font-medium mt-1")}
|
||||
>
|
||||
取消
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const [isVipModalVisible, setIsVipModalVisible] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const hanldSaveImage = async (index) => {
|
||||
|
@ -141,6 +74,58 @@ export function ImageViewer({
|
|||
setIsSaving(false);
|
||||
};
|
||||
|
||||
//查看原图
|
||||
const handleCheckOriginalImage = async (index) => {
|
||||
const isVip = await checkRole();
|
||||
if (!isVip) {
|
||||
setIsVipModalVisible(true);
|
||||
return;
|
||||
}
|
||||
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
||||
try {
|
||||
const base = await baseRequest();
|
||||
const body = {
|
||||
image_id: imageUrls[index].id,
|
||||
...base,
|
||||
};
|
||||
const signature = await generateSignature(body);
|
||||
const _response = await fetch(
|
||||
`${apiUrl}/api/previews/original_image?signature=${signature}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
}
|
||||
);
|
||||
const _data = await _response.json();
|
||||
if (_data.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: _data.msg,
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setImageViewerProps((prev) => {
|
||||
let newImageViewerProps = prev;
|
||||
newImageViewerProps.imageUrls[index] = {
|
||||
id: imageUrls[index].id,
|
||||
url: _data?.data?.urls[0],
|
||||
};
|
||||
return { ...newImageViewerProps };
|
||||
});
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "已切换至原图",
|
||||
topOffset: 60,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal visible={isVisible} statusBarTranslucent transparent={true}>
|
||||
<OriginImageViewer
|
||||
|
@ -189,32 +174,62 @@ export function ImageViewer({
|
|||
return <Image {...props} />;
|
||||
}}
|
||||
renderFooter={(index) => (
|
||||
<TouchableOpacity
|
||||
onPress={() => hanldSaveImage(index)}
|
||||
style={{
|
||||
marginLeft: 20,
|
||||
marginBottom: insets.bottom,
|
||||
...tailwind(
|
||||
"flex justify-center items-center w-12 h-12 bg-[#FFFFFF1A] rounded-full"
|
||||
),
|
||||
}}
|
||||
>
|
||||
{isSaving && <ActivityIndicator size="small" />}
|
||||
{!isSaving && (
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="save-outline"
|
||||
size={20}
|
||||
color="white"
|
||||
/>
|
||||
<View style={tailwind("flex flex-row items-center")}>
|
||||
<TouchableOpacity
|
||||
onPress={() => hanldSaveImage(index)}
|
||||
style={{
|
||||
marginLeft: 20,
|
||||
marginBottom: insets.bottom,
|
||||
...tailwind(
|
||||
"flex justify-center items-center w-14 h-14 bg-[#FFFFFF1A] rounded-full"
|
||||
),
|
||||
}}
|
||||
>
|
||||
{isSaving && <ActivityIndicator size="small" />}
|
||||
{!isSaving && (
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="save-outline"
|
||||
size={20}
|
||||
color="white"
|
||||
/>
|
||||
)}
|
||||
<Text
|
||||
style={tailwind("text-xs text-[#FFFFFF80] font-medium mt-1")}
|
||||
>
|
||||
保存
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
{imageUrls[index]?.id && (
|
||||
<TouchableOpacity
|
||||
onPress={() => handleCheckOriginalImage(index)}
|
||||
style={{
|
||||
marginLeft: 20,
|
||||
marginBottom: insets.bottom,
|
||||
...tailwind(
|
||||
"flex justify-center items-center w-14 h-14 bg-[#FFFFFF1A] rounded-full"
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Icon
|
||||
type="ionicon"
|
||||
name="image-outline"
|
||||
size={20}
|
||||
color="white"
|
||||
/>
|
||||
<Text
|
||||
style={tailwind("text-xs text-[#FFFFFF80] font-medium mt-1")}
|
||||
>
|
||||
原图
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
onSave={(url) => {
|
||||
saveImage(url);
|
||||
}}
|
||||
saveToLocalByLongPress
|
||||
menus={MenusComponent}
|
||||
saveToLocalByLongPress={false}
|
||||
loadingRender={() => <ActivityIndicator size="large" />}
|
||||
/>
|
||||
<Toast />
|
||||
|
@ -222,7 +237,7 @@ export function ImageViewer({
|
|||
visible={isVipModalVisible}
|
||||
setVisible={setIsVipModalVisible}
|
||||
title="是否开通会员?"
|
||||
content="会员可无限制保存图片/视频,一次开通永久有效。"
|
||||
content="会员可无限制保存图片、查看原图,一次开通永久有效。"
|
||||
cancel={() => {
|
||||
setIsVipModalVisible(false);
|
||||
}}
|
||||
|
|
|
@ -257,9 +257,8 @@ export default function Post({ data }) {
|
|||
|
||||
//媒体为图片时展示内容的组件
|
||||
function ImageDisplay({ media }) {
|
||||
const navigation = useNavigation();
|
||||
const tailwind = useTailwind();
|
||||
const images = media.map((item) => ({ url: item.urls[0] }));
|
||||
const images = media.map((item) => ({ url: item.urls[0], id: item.id }));
|
||||
|
||||
const { showImageViewer } = useImageViewer();
|
||||
|
||||
|
|
|
@ -608,7 +608,7 @@ function ImageDisplay({
|
|||
|
||||
const { showImageViewer } = useImageViewer();
|
||||
const images = displayMedia.map((item) => {
|
||||
return { url: item?.urls[0] };
|
||||
return { url: item?.urls[0], id: item?.id };
|
||||
});
|
||||
|
||||
const [isCollapsed, setIsCollapsed] = useState(true);
|
||||
|
|
|
@ -28,6 +28,7 @@ export const ImageViewerProvider = ({ children }) => {
|
|||
{...imageViewerProps}
|
||||
onClose={closeImageViewer}
|
||||
onChange={changeImageViewerIndex}
|
||||
setImageViewerProps={setImageViewerProps}
|
||||
/>
|
||||
)}
|
||||
</ImageViewerContext.Provider>
|
||||
|
|
|
@ -87,9 +87,8 @@ export default function SpaceIntroduce({ navigation, route }) {
|
|||
const images = data?.streamer_ext?.album?.images
|
||||
?.slice(0, 5)
|
||||
?.map((image) => {
|
||||
return image?.urls[0];
|
||||
return { url: image?.urls[0], id: image?.id };
|
||||
});
|
||||
const imagesForImageViewer = images?.map((url) => ({ url }));
|
||||
|
||||
//当空间价格为0时,直接加入空间
|
||||
const handleJoinFreeSpace = async () => {
|
||||
|
@ -288,7 +287,7 @@ export default function SpaceIntroduce({ navigation, route }) {
|
|||
activeOpacity={1}
|
||||
onPress={() => {
|
||||
showImageViewer({
|
||||
imageUrls: imagesForImageViewer,
|
||||
imageUrls: images,
|
||||
index: index,
|
||||
});
|
||||
}}
|
||||
|
|
|
@ -245,8 +245,10 @@ export default function StreamerProfile({ navigation, route }) {
|
|||
|
||||
const { showImageViewer } = useImageViewer();
|
||||
|
||||
const images = data?.album?.images?.map((image) => image?.urls[0]);
|
||||
const imagesForImageViewer = images?.map((url) => ({ url }));
|
||||
const images = data?.album?.images?.map((image) => ({
|
||||
url: image?.urls[0],
|
||||
id: image?.id,
|
||||
}));
|
||||
return (
|
||||
<>
|
||||
<Swiper
|
||||
|
@ -297,7 +299,7 @@ export default function StreamerProfile({ navigation, route }) {
|
|||
<TouchableWithoutFeedback
|
||||
onPress={() => {
|
||||
showImageViewer({
|
||||
imageUrls: imagesForImageViewer,
|
||||
imageUrls: images,
|
||||
index: index - 1,
|
||||
});
|
||||
}}
|
||||
|
|
|
@ -215,6 +215,42 @@ export default function StreamerSpace({ navigation, route }) {
|
|||
//bottom sheet组件相关
|
||||
const snapPoints = useMemo(() => ["73%", "100%"], []);
|
||||
|
||||
//刷新铁粉身份(解决主播降价导致的进度满100但未成为铁粉)
|
||||
const handleFansIdentityRefresh = async () => {
|
||||
const apiUrl = process.env.EXPO_PUBLIC_API_URL;
|
||||
try {
|
||||
const base = await baseRequest();
|
||||
const body = {
|
||||
zid: data?.id,
|
||||
...base,
|
||||
};
|
||||
const signature = await generateSignature(body);
|
||||
const _response = await fetch(
|
||||
`${apiUrl}/api/zone_moment/fans_identity_refresh?signature=${signature}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
}
|
||||
);
|
||||
const _data = await _response.json();
|
||||
if (_data.ret === -1) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: _data.msg,
|
||||
topOffset: 60,
|
||||
});
|
||||
return;
|
||||
}
|
||||
await getData();
|
||||
setIsIronFanModalVisible(false);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
//成为铁粉Modal组件
|
||||
const [isIronFanModalVisible, setIsIronFanModalVisible] = useState(false);
|
||||
const ironFanProgress = useMemo(
|
||||
|
@ -283,6 +319,15 @@ export default function StreamerSpace({ navigation, route }) {
|
|||
>
|
||||
查看铁粉专享内容
|
||||
</Button>
|
||||
<Text
|
||||
onPress={handleFansIdentityRefresh}
|
||||
style={{
|
||||
textDecorationLine: "underline",
|
||||
...tailwind("text-sm font-medium text-[#FF669E] mt-2"),
|
||||
}}
|
||||
>
|
||||
进度已满但还未成为铁粉?
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
|
Loading…
Reference in New Issue