262 lines
7.7 KiB
JavaScript
262 lines
7.7 KiB
JavaScript
import {
|
||
View,
|
||
Text,
|
||
Modal,
|
||
TouchableOpacity,
|
||
ActivityIndicator,
|
||
Platform,
|
||
} from "react-native";
|
||
import React, { useState, useCallback, useEffect } from "react";
|
||
import { ImageViewer as OriginImageViewer } from "react-native-image-zoom-viewer";
|
||
import { Icon } from "@rneui/themed";
|
||
import { useTailwind } from "tailwind-rn";
|
||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||
import saveImage from "../../utils/saveImage";
|
||
import Toast from "react-native-toast-message";
|
||
import { get } from "../../utils/storeInfo";
|
||
import { useNavigation } from "@react-navigation/native";
|
||
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 , id: int }] 网络图片需要查看原图时才传id,其他情况不用
|
||
//index int
|
||
//lockedStartIndex int
|
||
//onPressUnlockBtn () => void
|
||
|
||
export function ImageViewer({
|
||
isShow,
|
||
onClose,
|
||
onChange,
|
||
imageUrls,
|
||
index,
|
||
lockedStartIndex,
|
||
onPressUnlockBtn,
|
||
setImageViewerProps,
|
||
}) {
|
||
const tailwind = useTailwind();
|
||
const insets = useSafeAreaInsets();
|
||
|
||
const navigation = useNavigation();
|
||
|
||
const [isVisible, setIsVisible] = useState(false);
|
||
useEffect(() => {
|
||
setIsVisible(isShow);
|
||
}, [isShow]);
|
||
|
||
const closeImageViewer = () => {
|
||
setIsVisible(false);
|
||
onClose && onClose();
|
||
};
|
||
|
||
const checkRole = useCallback(async () => {
|
||
const account = await get("account");
|
||
const role = account.role;
|
||
const isVip = account.is_a_member;
|
||
if (role !== 0 || isVip === 1) return true;
|
||
return false;
|
||
}, []);
|
||
|
||
const [isVipModalVisible, setIsVipModalVisible] = useState(false);
|
||
const [isSaving, setIsSaving] = useState(false);
|
||
const hanldSaveImage = async (index) => {
|
||
const isVip = await checkRole();
|
||
if (!isVip) {
|
||
setIsVipModalVisible(true);
|
||
return;
|
||
}
|
||
if (isSaving) return;
|
||
setIsSaving(true);
|
||
await saveImage(imageUrls[index].url);
|
||
setIsSaving(false);
|
||
};
|
||
|
||
//查看原图
|
||
const [isLoading, setIsLoading] = useState(false);
|
||
const handleCheckOriginalImage = async (index) => {
|
||
const isVip = await checkRole();
|
||
if (!isVip) {
|
||
setIsVipModalVisible(true);
|
||
return;
|
||
}
|
||
setIsLoading(true);
|
||
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);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<Modal visible={isVisible} statusBarTranslucent transparent={true}>
|
||
<OriginImageViewer
|
||
imageUrls={imageUrls}
|
||
index={index}
|
||
onClick={closeImageViewer}
|
||
onSwipeDown={closeImageViewer}
|
||
onChange={onChange ? (index) => onChange(index) : () => null}
|
||
enableSwipeDown
|
||
backgroundColor="#07050A"
|
||
renderImage={(props) => {
|
||
if (index >= lockedStartIndex) {
|
||
return (
|
||
<View>
|
||
<Image
|
||
{...props}
|
||
blurRadius={Platform.OS === "ios" ? 100 : 10}
|
||
/>
|
||
<View
|
||
style={tailwind(
|
||
"absolute flex justify-center items-center top-0 left-0 bg-[#00000080] w-full h-full"
|
||
)}
|
||
>
|
||
<Button
|
||
onPress={() => {
|
||
closeImageViewer();
|
||
onPressUnlockBtn();
|
||
}}
|
||
ViewComponent={LinearGradient}
|
||
radius="999"
|
||
size="md"
|
||
linearGradientProps={{
|
||
colors: ["#FF668B", "#FF66F0"],
|
||
start: { x: 0, y: 0.5 },
|
||
end: { x: 1, y: 0.5 },
|
||
}}
|
||
titleStyle={tailwind("text-base font-medium")}
|
||
containerStyle={tailwind("w-3/4 px-4")}
|
||
>
|
||
立即解锁
|
||
</Button>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
return <Image {...props} />;
|
||
}}
|
||
renderFooter={(index) => (
|
||
<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"
|
||
),
|
||
}}
|
||
>
|
||
{isLoading && <ActivityIndicator size="small" />}
|
||
{!isLoading && (
|
||
<Icon
|
||
type="ionicon"
|
||
name="image-outline"
|
||
size={20}
|
||
color="white"
|
||
/>
|
||
)}
|
||
<Text
|
||
style={tailwind("text-xs text-[#FFFFFF80] font-medium mt-1")}
|
||
>
|
||
原图
|
||
</Text>
|
||
</TouchableOpacity>
|
||
)}
|
||
</View>
|
||
)}
|
||
onSave={(url) => {
|
||
saveImage(url);
|
||
}}
|
||
saveToLocalByLongPress={false}
|
||
loadingRender={() => <ActivityIndicator size="large" />}
|
||
/>
|
||
<Toast />
|
||
<MyModal
|
||
visible={isVipModalVisible}
|
||
setVisible={setIsVipModalVisible}
|
||
title="是否开通会员?"
|
||
content="会员可无限制保存图片、查看原图,一次开通永久有效。"
|
||
cancel={() => {
|
||
setIsVipModalVisible(false);
|
||
}}
|
||
confirm={() => {
|
||
setIsVipModalVisible(false);
|
||
closeImageViewer();
|
||
navigation.navigate("WebWithoutHeader", {
|
||
uri: process.env.EXPO_PUBLIC_WEB_URL + "/vip",
|
||
});
|
||
}}
|
||
/>
|
||
</Modal>
|
||
);
|
||
}
|