Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions src/components/AIPlayerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ const AIPlayerView: React.FC<AIPlayerViewProps> = ({
{[...Array(Math.min(10, player.hand.length))].map((_, i) => (
<View
key={`${position}-card-${i}`}
style={[styles.botCardSmall, getCardStyle(i)]}
style={[styles.botCardWrapper, getCardStyle(i)]}
>
<CardBack />
<CardBack width={36} height={50} />
</View>
))}
</View>
Expand Down Expand Up @@ -170,16 +170,10 @@ const styles = StyleSheet.create({
flexDirection: "column",
alignItems: "center",
},
botCardSmall: {
botCardWrapper: {
width: 36,
height: 50,
backgroundColor: "#4169E1",
borderRadius: 3,
borderWidth: 1,
borderColor: "white",
zIndex: 5,
justifyContent: "center",
alignItems: "center",
position: "absolute",
},
});
Expand Down
32 changes: 21 additions & 11 deletions src/components/AnimatedCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ export const AnimatedCard: React.FC<CardProps> = ({

// Selection animation - improved with higher pop-up for better visibility
useEffect(() => {
let timerId: ReturnType<typeof setTimeout>;
if (selected) {
// Use a tiny delay to ensure all cards start animating at the same time
// This helps when multiple cards are selected simultaneously via auto-selection
setTimeout(() => {
timerId = setTimeout(() => {
translateY.value = withTiming(-20 * cardScale, {
duration: 120, // Slightly longer duration for smoother animation
easing: Easing.out(Easing.cubic),
Expand All @@ -109,7 +110,7 @@ export const AnimatedCard: React.FC<CardProps> = ({
}, 0); // Use setTimeout with 0ms to synchronize animations
} else {
// Quick deselection with consistent timing
setTimeout(() => {
timerId = setTimeout(() => {
translateY.value = withTiming(0, {
duration: 120,
easing: Easing.inOut(Easing.cubic),
Expand All @@ -121,13 +122,14 @@ export const AnimatedCard: React.FC<CardProps> = ({
opacity.value = 1;
}, 0);
}
return () => clearTimeout(timerId);
}, [selected, translateY, scale, opacity, cardScale]);

// Play animation - improved for cleaner, more refined appearance with better Bot3 support
useEffect(() => {
if (isPlayed) {
// Delay animations for sequential effect
setTimeout(() => {
const timerId = setTimeout(() => {
// Set rotation to 0 for a neat stack with improved easing
rotate.value = withTiming("0deg", {
duration: 200, // Reduced duration for smoother Bot3 animations
Expand All @@ -153,6 +155,7 @@ export const AnimatedCard: React.FC<CardProps> = ({
// Always set opacity to 1 immediately to prevent any transparency
opacity.value = 1;
}, delay);
return () => clearTimeout(timerId);
}
}, [isPlayed, delay, rotate, opacity, scale, onAnimationComplete]);

Expand Down Expand Up @@ -320,7 +323,11 @@ export const AnimatedCard: React.FC<CardProps> = ({

if (faceDown) {
return (
<Animated.View style={[styles.card, shadowStyle, style, animatedStyle]}>
<Animated.View
style={[styles.card, shadowStyle, style, animatedStyle]}
shouldRasterizeIOS={true}
renderToHardwareTextureAndroid={true}
>
<View style={styles.cardBack}>
{/* Card back with simplified 3x3 grid pattern */}
<View style={faceDownCardBackStyle}>
Expand Down Expand Up @@ -419,7 +426,11 @@ export const AnimatedCard: React.FC<CardProps> = ({

if (card.joker) {
return (
<Animated.View style={[shadowStyle, style, animatedStyle]}>
<Animated.View
style={[shadowStyle, style, animatedStyle]}
shouldRasterizeIOS={true}
renderToHardwareTextureAndroid={true}
>
<TouchableOpacity
style={[
styles.card,
Expand Down Expand Up @@ -486,7 +497,11 @@ export const AnimatedCard: React.FC<CardProps> = ({

// Render normal card with enhanced styling
return (
<Animated.View style={[shadowStyle, style, animatedStyle]}>
<Animated.View
style={[shadowStyle, style, animatedStyle]}
shouldRasterizeIOS={true}
renderToHardwareTextureAndroid={true}
>
<TouchableOpacity
style={[
styles.card,
Expand Down Expand Up @@ -561,9 +576,6 @@ const styles = StyleSheet.create({
elevation: 3,
// Performance optimizations
backfaceVisibility: "hidden",
// @ts-expect-error - These are valid React Native style properties
shouldRasterizeIOS: true, // iOS performance optimization
renderToHardwareTextureAndroid: true, // Android performance optimization
overflow: "hidden",
},
cardBack: {
Expand All @@ -575,8 +587,6 @@ const styles = StyleSheet.create({
overflow: "hidden",
// Performance optimizations for card back too
backfaceVisibility: "hidden",
shouldRasterizeIOS: true,
renderToHardwareTextureAndroid: true,
},
// Using state-based styling controlled by animated values instead of this static style
selectedCard: {
Expand Down
36 changes: 14 additions & 22 deletions src/components/CardPlayArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
const [totalAnimationsNeeded, setTotalAnimationsNeeded] = useState<number>(0);
const [animationCompleted, setAnimationCompleted] = useState<boolean>(false);

// Track changes to lastCompletedTrick
useEffect(() => {
// Removed debug logging
}, [lastCompletedTrick]);

// Handler for individual card animations completing - explicitly typed as a function
const handleCardAnimationComplete = (): void => {
// Increment the animation counter
Expand Down Expand Up @@ -85,7 +80,8 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
setTotalAnimationsNeeded(0);
setAnimationCompleted(false);
}
}, [currentTrick, animationCompleted]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentTrick]);

// Add sequence information to cards
type CardWithSequence = CardType & {
Expand Down Expand Up @@ -132,11 +128,13 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
// All animations complete - trigger callback

// Add a small delay to ensure all visual animations are complete
setTimeout(() => {
const timerId = setTimeout(() => {
if (typeof onAnimationComplete === "function") {
onAnimationComplete();
}
}, ANIMATION_COMPLETION_DELAY); // Delay to ensure cards are rendered properly

return () => clearTimeout(timerId);
}
}, [
completedAnimations,
Expand Down Expand Up @@ -200,7 +198,11 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
playerSequenceMap[play.playerId] = sequence;

play.cards.forEach((card, idx) => {
const cardWithSequence = Object.assign(card, {
const cardCopy = Object.create(
Object.getPrototypeOf(card),
Object.getOwnPropertyDescriptors(card),
);
const cardWithSequence: CardWithSequence = Object.assign(cardCopy, {
playSequence: sequence,
cardIndex: idx, // Index within this player's combo
});
Expand Down Expand Up @@ -248,9 +250,7 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
marginLeft: 15, // Smaller shift for tighter centering
}),
// Enhanced winner highlighting with card-matching radius
...(isWinning(
players.find((p) => p.id === PlayerId.Bot2)?.id as PlayerId,
) && styles.winningCard),
...(isWinning(PlayerId.Bot2) && styles.winningCard),
}}
/>
))}
Expand Down Expand Up @@ -287,10 +287,7 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
marginLeft: 15, // Smaller shift for tighter centering
}),
// Enhanced winner highlighting with card-matching radius
...(isWinning(
players.find((p) => p.id === PlayerId.Bot3)
?.id as PlayerId,
) && styles.winningCard),
...(isWinning(PlayerId.Bot3) && styles.winningCard),
}}
/>
))}
Expand Down Expand Up @@ -330,10 +327,7 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
marginLeft: 15, // Smaller shift for tighter centering
}),
// Enhanced winner highlighting with card-matching radius
...(isWinning(
players.find((p) => p.id === PlayerId.Bot1)
?.id as PlayerId,
) && styles.winningCard),
...(isWinning(PlayerId.Bot1) && styles.winningCard),
}}
/>
))}
Expand Down Expand Up @@ -369,9 +363,7 @@ const CardPlayArea: React.FC<CardPlayAreaProps> = ({
marginLeft: 15, // Smaller shift for tighter centering
}),
// Enhanced winner highlighting with card-matching radius
...(isWinning(
players.find((p) => p.isHuman)?.id as PlayerId,
) && styles.winningCard),
...(isWinning(PlayerId.Human) && styles.winningCard),
}}
/>
))}
Expand Down
14 changes: 11 additions & 3 deletions src/components/ExpandableTrumpDeclaration.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
Animated,
StyleSheet,
Expand Down Expand Up @@ -55,6 +55,14 @@ export function ExpandableTrumpDeclaration({
const [isExpanded, setIsExpanded] = useState(false);
const [animatedHeight] = useState(new Animated.Value(0));
const [isCollapsing, setIsCollapsing] = useState(false);
const collapseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

// Cleanup collapse timer on unmount
useEffect(() => {
return () => {
if (collapseTimerRef.current) clearTimeout(collapseTimerRef.current);
};
}, []);

// Get all the data we need
const dealingProgress = getDealingProgress(gameState);
Expand Down Expand Up @@ -115,7 +123,7 @@ export function ExpandableTrumpDeclaration({
}).start(() => {
onContinue();
// Keep collapsing flag longer to prevent re-expansion
setTimeout(() => {
collapseTimerRef.current = setTimeout(() => {
setIsCollapsing(false);
}, 500);
});
Expand All @@ -135,7 +143,7 @@ export function ExpandableTrumpDeclaration({
}).start(() => {
onDeclaration(declaration);
// Keep collapsing flag longer to prevent re-expansion
setTimeout(() => {
collapseTimerRef.current = setTimeout(() => {
setIsCollapsing(false);
}, 500);
});
Expand Down
Loading