|
@@ -1,3 +1,4 @@
|
|
|
|
|
+import { AVPlaybackStatus, ResizeMode, Video } from 'expo-av';
|
|
|
import { Image } from 'expo-image';
|
|
import { Image } from 'expo-image';
|
|
|
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
|
import {
|
|
import {
|
|
@@ -59,6 +60,45 @@ const LotteryImages = {
|
|
|
lotteryBg: `${imgUrlSupermart}/supermart/box/sequence/sequence0.jpg`,
|
|
lotteryBg: `${imgUrlSupermart}/supermart/box/sequence/sequence0.jpg`,
|
|
|
cardBack: `${imgUrl}/box/back1.png`,
|
|
cardBack: `${imgUrl}/box/back1.png`,
|
|
|
halo: `${imgUrlSupermart}/supermart/box/halo.gif`,
|
|
halo: `${imgUrlSupermart}/supermart/box/halo.gif`,
|
|
|
|
|
+ levelA_bg: `${imgUrlSupermart}/supermart/box/levelD.png`, // Using levelD as placeholder if specific not found, or specific bg
|
|
|
|
|
+ levelA_title: `${imgUrlSupermart}/supermart/box/detail/levelTextA.png`,
|
|
|
|
|
+ close: `${imgUrlSupermart}/supermart/box/qiji_close.png`,
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const DEFAULT_JACKPOT_VIDEO = 'https://cdn.acetoys.cn/kai_xin_ma_te/supermart/box/lottery/jackpot.mp4';
|
|
|
|
|
+
|
|
|
|
|
+const KingModal = ({ visible, data, onClose }: { visible: boolean; data: LotteryItem | null; onClose: () => void }) => {
|
|
|
|
|
+ if (!visible || !data) return null;
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Modal visible={visible} transparent animationType="fade" onRequestClose={onClose}>
|
|
|
|
|
+ <View style={styles.kingContainer}>
|
|
|
|
|
+ <View style={styles.kingMask}>
|
|
|
|
|
+ <TouchableOpacity style={StyleSheet.absoluteFill} onPress={onClose} />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View style={styles.kingWrapper}>
|
|
|
|
|
+ <Image
|
|
|
|
|
+ source={{ uri: LEVEL_MAP[data.level]?.resultBg || LEVEL_MAP.A.resultBg }}
|
|
|
|
|
+ style={styles.kingBg}
|
|
|
|
|
+ contentFit="fill"
|
|
|
|
|
+ />
|
|
|
|
|
+ <Animated.Image
|
|
|
|
|
+ source={{ uri: data.cover }}
|
|
|
|
|
+ style={styles.kingProduct}
|
|
|
|
|
+ resizeMode="contain"
|
|
|
|
|
+ />
|
|
|
|
|
+ <Image
|
|
|
|
|
+ source={{ uri: LotteryImages.levelA_title }}
|
|
|
|
|
+ style={styles.kingTitle}
|
|
|
|
|
+ contentFit="contain"
|
|
|
|
|
+ />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <TouchableOpacity style={styles.kingCloseBtn} onPress={onClose}>
|
|
|
|
|
+ <Image source={{ uri: LotteryImages.close }} style={styles.kingCloseIcon} />
|
|
|
|
|
+ </TouchableOpacity>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+ );
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
interface LotteryItem {
|
|
interface LotteryItem {
|
|
@@ -96,6 +136,11 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
|
|
|
const [isSkip, setIsSkip] = useState(true);
|
|
const [isSkip, setIsSkip] = useState(true);
|
|
|
const [tradeNo, setTradeNo] = useState('');
|
|
const [tradeNo, setTradeNo] = useState('');
|
|
|
|
|
|
|
|
|
|
+ const [kingVisible, setKingVisible] = useState(false);
|
|
|
|
|
+ const [kingData, setKingData] = useState<LotteryItem | null>(null);
|
|
|
|
|
+ const [videoVisible, setVideoVisible] = useState(false);
|
|
|
|
|
+ const [videoUrl, setVideoUrl] = useState('');
|
|
|
|
|
+
|
|
|
const flipAnims = useRef<Animated.Value[]>([]);
|
|
const flipAnims = useRef<Animated.Value[]>([]);
|
|
|
const dataLoadedRef = useRef(false);
|
|
const dataLoadedRef = useRef(false);
|
|
|
|
|
|
|
@@ -111,6 +156,10 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
|
|
|
setHaloShow(false);
|
|
setHaloShow(false);
|
|
|
setRebateAmount(0);
|
|
setRebateAmount(0);
|
|
|
setIsSkip(true);
|
|
setIsSkip(true);
|
|
|
|
|
+ setKingVisible(false);
|
|
|
|
|
+ setKingData(null);
|
|
|
|
|
+ setVideoVisible(false);
|
|
|
|
|
+ setVideoUrl('');
|
|
|
dataLoadedRef.current = false;
|
|
dataLoadedRef.current = false;
|
|
|
flipAnims.current = [];
|
|
flipAnims.current = [];
|
|
|
},
|
|
},
|
|
@@ -172,8 +221,39 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
|
|
|
setTableData(array);
|
|
setTableData(array);
|
|
|
setLoading(false);
|
|
setLoading(false);
|
|
|
|
|
|
|
|
- // 直接开始翻牌动画
|
|
|
|
|
- setTimeout(() => flipCards(array), 500);
|
|
|
|
|
|
|
+ setLoading(false);
|
|
|
|
|
+
|
|
|
|
|
+ // Determine playing video
|
|
|
|
|
+ let playVideoUrl = '';
|
|
|
|
|
+ if (res.video) {
|
|
|
|
|
+ playVideoUrl = res.video;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Check if any Level A item exists
|
|
|
|
|
+ const hasLevelA = array.some((item: LotteryItem) => item.level === 'A');
|
|
|
|
|
+ if (hasLevelA) {
|
|
|
|
|
+ playVideoUrl = DEFAULT_JACKPOT_VIDEO;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Check for Level A item for KingModal logic (which happens after video)
|
|
|
|
|
+ const levelAItem = array.find((item: LotteryItem) => item.level === 'A');
|
|
|
|
|
+
|
|
|
|
|
+ const startFlow = () => {
|
|
|
|
|
+ setVideoVisible(false);
|
|
|
|
|
+ if (levelAItem) {
|
|
|
|
|
+ setKingData(levelAItem);
|
|
|
|
|
+ setKingVisible(true);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setTimeout(() => flipCards(array), 500);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if (playVideoUrl) {
|
|
|
|
|
+ setVideoUrl(playVideoUrl);
|
|
|
|
|
+ setVideoVisible(true);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ startFlow();
|
|
|
|
|
+ }
|
|
|
} else if (attempts < maxAttempts) {
|
|
} else if (attempts < maxAttempts) {
|
|
|
attempts++;
|
|
attempts++;
|
|
|
timeoutId = setTimeout(fetchData, 400);
|
|
timeoutId = setTimeout(fetchData, 400);
|
|
@@ -377,6 +457,55 @@ export const LotteryResultModal = forwardRef<LotteryResultModalRef, LotteryResul
|
|
|
)}
|
|
)}
|
|
|
</ImageBackground>
|
|
</ImageBackground>
|
|
|
</View>
|
|
</View>
|
|
|
|
|
+ <KingModal
|
|
|
|
|
+ visible={kingVisible}
|
|
|
|
|
+ data={kingData}
|
|
|
|
|
+ onClose={() => {
|
|
|
|
|
+ setKingVisible(false);
|
|
|
|
|
+ setTimeout(() => flipCards(tableData), 300);
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ {videoVisible && videoUrl ? (
|
|
|
|
|
+ <View style={styles.videoContainer}>
|
|
|
|
|
+ <Video
|
|
|
|
|
+ source={{ uri: videoUrl }}
|
|
|
|
|
+ style={styles.video}
|
|
|
|
|
+ resizeMode={ResizeMode.COVER}
|
|
|
|
|
+ shouldPlay
|
|
|
|
|
+ isLooping={false}
|
|
|
|
|
+ onPlaybackStatusUpdate={(status: AVPlaybackStatus) => {
|
|
|
|
|
+ if (status.isLoaded && status.didJustFinish) {
|
|
|
|
|
+ // Video finished
|
|
|
|
|
+ setVideoVisible(false);
|
|
|
|
|
+ // Proceed to next step
|
|
|
|
|
+ const levelAItem = tableData.find((item: LotteryItem) => item.level === 'A');
|
|
|
|
|
+ if (levelAItem) {
|
|
|
|
|
+ setKingData(levelAItem);
|
|
|
|
|
+ setKingVisible(true);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setTimeout(() => flipCards(tableData), 300);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ <TouchableOpacity
|
|
|
|
|
+ style={styles.skipVideoBtn}
|
|
|
|
|
+ onPress={() => {
|
|
|
|
|
+ setVideoVisible(false);
|
|
|
|
|
+ // Proceed to next step
|
|
|
|
|
+ const levelAItem = tableData.find((item: LotteryItem) => item.level === 'A');
|
|
|
|
|
+ if (levelAItem) {
|
|
|
|
|
+ setKingData(levelAItem);
|
|
|
|
|
+ setKingVisible(true);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setTimeout(() => flipCards(tableData), 300);
|
|
|
|
|
+ }
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Text style={styles.skipText}>跳过</Text>
|
|
|
|
|
+ </TouchableOpacity>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ ) : null}
|
|
|
</Modal>
|
|
</Modal>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
@@ -508,4 +637,15 @@ const styles = StyleSheet.create({
|
|
|
borderRadius: 15
|
|
borderRadius: 15
|
|
|
},
|
|
},
|
|
|
skipText: { fontSize: 14, color: '#fff' },
|
|
skipText: { fontSize: 14, color: '#fff' },
|
|
|
|
|
+ kingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: 'transparent' },
|
|
|
|
|
+ kingMask: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.7)' },
|
|
|
|
|
+ kingWrapper: { width: 353 * 1.2, height: 545 * 1.2, alignItems: 'center', justifyContent: 'center' },
|
|
|
|
|
+ kingBg: { position: 'absolute', width: '100%', height: '100%' },
|
|
|
|
|
+ kingProduct: { width: 293 * 1.2, height: 370 * 1.2, marginTop: 33, borderRadius: 8 },
|
|
|
|
|
+ kingTitle: { position: 'absolute', bottom: 40, width: 230 * 1.2, height: 102 * 1.2 },
|
|
|
|
|
+ kingCloseBtn: { marginTop: 30 },
|
|
|
|
|
+ kingCloseIcon: { width: 60, height: 60 },
|
|
|
|
|
+ videoContainer: { ...StyleSheet.absoluteFillObject, zIndex: 10000, backgroundColor: 'black' },
|
|
|
|
|
+ video: { width: '100%', height: '100%' },
|
|
|
|
|
+ skipVideoBtn: { position: 'absolute', top: 60, right: 20, backgroundColor: 'rgba(0,0,0,0.5)', paddingHorizontal: 15, paddingVertical: 8, borderRadius: 20 },
|
|
|
});
|
|
});
|