增加查看原图功能;增加检查铁粉进度功能

This commit is contained in:
yezian 2024-12-20 20:40:46 +08:00
parent e44b611998
commit f5487d23b5
7 changed files with 163 additions and 102 deletions

View File

@ -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);
}}

View File

@ -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();

View File

@ -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);

View File

@ -28,6 +28,7 @@ export const ImageViewerProvider = ({ children }) => {
{...imageViewerProps}
onClose={closeImageViewer}
onChange={changeImageViewerIndex}
setImageViewerProps={setImageViewerProps}
/>
)}
</ImageViewerContext.Provider>

View File

@ -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,
});
}}

View File

@ -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,
});
}}

View File

@ -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>