240 lines
7.1 KiB
JavaScript
240 lines
7.1 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";
|
|
|
|
//imageUrls [{ url: string }]
|
|
//index int
|
|
//lockedStartIndex int
|
|
//onPressUnlockBtn () => void
|
|
|
|
export function ImageViewer({
|
|
isShow,
|
|
onClose,
|
|
onChange,
|
|
imageUrls,
|
|
index,
|
|
lockedStartIndex,
|
|
onPressUnlockBtn,
|
|
}) {
|
|
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 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) => {
|
|
const isVip = await checkRole();
|
|
if (!isVip) {
|
|
setIsVipModalVisible(true);
|
|
return;
|
|
}
|
|
if (isSaving) return;
|
|
setIsSaving(true);
|
|
await saveImage(imageUrls[index].url);
|
|
setIsSaving(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) => (
|
|
<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"
|
|
/>
|
|
)}
|
|
</TouchableOpacity>
|
|
)}
|
|
onSave={(url) => {
|
|
saveImage(url);
|
|
}}
|
|
saveToLocalByLongPress
|
|
menus={MenusComponent}
|
|
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>
|
|
);
|
|
}
|