// Import required hooks and components from React and React Native
import { useRef } from 'react';
import {
View,
Pressable,
Text,
Animated,
Easing,
StyleSheet,
} from 'react-native';
// Function to generate a random decimal between 0.00 and 1.00
const generateRandomDecimal = () => {
const randomNumber = Math.random();
return parseFloat(randomNumber.toFixed(2));
};
// Main component that implements the spinning bottle animation
const SpinBottle = () => {
// Animated value that controls the rotation
const spinValue = useRef(new Animated.Value(0)).current;
// Ref to prevent multiple spins at the same time
const isSpinning = useRef(false);
// Function to start the spin animation
const startSpinAnimation = () => {
if (!isSpinning.current) {
isSpinning.current = true;
spinValue.setValue(0); // Reset the spin value before starting
Animated.timing(spinValue, {
// Randomize spin by adding a decimal to 10 full rotations
toValue: 10 + generateRandomDecimal(),
duration: 2000, // Duration of animation in milliseconds
easing: Easing.bezier(0.16, 1, 0.3, 1), // Smooth acceleration/deceleration
useNativeDriver: false, // Not using native driver as rotation is in degrees
}).start(() => {
isSpinning.current = false; // Mark as not spinning when animation completes
// Optional: Add logic here after spinning ends
});
}
};
// Interpolating the animated value to degrees for rotation
const spin = spinValue.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'], // One full rotation
});
return (
<View style={styles.container}>
{/* Title Text */}
<Text style={styles.geekText}>Spin the bottle</Text>
{/* Animated bottle built using nested Views */}
<Animated.View style={[styles.bottle, { transform: [{ rotate: spin }] }]}>
<View style={styles.rectangle3}></View>
<View style={styles.rectangle2}></View>
<View style={styles.rectangle1}></View>
</Animated.View>
{/* Spin Button */}
<Pressable
style={({ pressed }) => [
styles.spinButton,
{
backgroundColor: pressed ? '#0F9D58' : '#14EF37', // Button press feedback
},
]}
onPress={startSpinAnimation}>
<Text style={styles.spinButtonText}>SPIN</Text>
</Pressable>
</View>
);
};
// App root component rendering the SpinBottle
export default function App() {
return <SpinBottle />;
}
// Styles for the components
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
},
geekText: {
marginBottom: '10%',
fontSize: 25,
color: '#228B22',
fontWeight: 'bold',
},
bottle: {
justifyContent: 'center',
alignItems: 'center',
},
rectangle3: {
width: 30,
height: 14,
backgroundColor: '#43E71A', // Top part of the bottle
},
rectangle2: {
width: 100,
height: 106,
backgroundColor: '#B4F6A3', // Neck of the bottle
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
overflow: 'hidden',
},
rectangle1: {
width: 100,
height: 157,
backgroundColor: '#A2F74D', // Body of the bottle
},
spinButton: {
alignItems: 'center',
marginTop: '20%',
borderRadius: 5,
paddingTop: 6,
paddingBottom: 6,
paddingLeft: 15,
paddingRight: 15,
},
spinButtonText: {
fontSize: 18,
color: 'white',
userSelect: 'none', // Prevents accidental text selection on desktop
},
});