When I open the application on the web using the npx expo start --tunnel command, I can swipe and flip the cards, but it doesn't work in expo go. I can see the cards, but they don't move. It's like the touchscreen doesn't work at all.How can i fix?
package.json
{
"name": "word-cards",
"version": "1.0.0",
"main": "expo-router/entry",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"@expo/metro-runtime": "~3.2.3",
"@react-native-async-storage/async-storage": "1.23.1",
"axios": "^1.7.7",
"expo": "^51.0.0",
"expo-constants": "~16.0.1",
"expo-font": "^12.0.10",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.9",
"expo-splash-screen": "~0.27.4",
"expo-status-bar": "~1.12.1",
"npm-upgrade": "^3.1.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.5",
"react-native-deck-swiper": "^2.0.17",
"react-native-dotenv": "^3.4.11",
"react-native-flip-card": "^3.5.7",
"react-native-gesture-handler": "~2.16.1",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-swipe-gestures": "^1.0.5",
"react-native-web": "~0.19.10"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}
index.js
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { View, Text, StyleSheet, Dimensions, TouchableWithoutFeedback, Animated } from 'react-native';
import Swiper from 'react-native-deck-swiper';
import AsyncStorage from '@react-native-async-storage/async-storage';
const { width, height } = Dimensions.get('window');
const flashcards = [
{ id: 1, german: 'Ja', english: 'Yes' },
{ id: 2, german: 'Nein', english: 'No' },
{ id: 3, german: 'Bitte', english: 'Please' },
];
const shuffleArray = (array) => {
return array.sort(() => Math.random() - 0.5);
};
export default function App() {
const [currentIndex, setCurrentIndex] = useState(0);
const [cards, setCards] = useState(shuffleArray([...flashcards]));
const [label, setLabel] = useState('');
const [cardFrequency, setCardFrequency] = useState({});
const flipAnimation = useRef(new Animated.Value(0)).current;
const swiperRef = useRef(null);
useEffect(() => {
const loadCardData = async () => {
try {
const storedFrequency = await AsyncStorage.getItem('cardFrequency');
if (storedFrequency) {
setCardFrequency(JSON.parse(storedFrequency));
}
} catch (error) {
console.log("Error loading card data", error);
}
};
loadCardData();
}, []);
const flipCard = useCallback(() => {
Animated.spring(flipAnimation, {
toValue: flipAnimation._value === 0 ? 180 : 0,
friction: 8,
tension: 10,
useNativeDriver: true,
}).start();
}, [flipAnimation]);
const frontInterpolate = flipAnimation.interpolate({
inputRange: [0, 180],
outputRange: ['0deg', '180deg'],
});
const backInterpolate = flipAnimation.interpolate({
inputRange: [0, 180],
outputRange: ['180deg', '360deg'],
});
const frontAnimatedStyle = {
transform: [{ rotateY: frontInterpolate }],
};
const backAnimatedStyle = {
transform: [{ rotateY: backInterpolate }],
};
const updateCardOrder = () => {
const newCards = [...flashcards].sort((a, b) => {
const freqA = cardFrequency[a.id] || 1;
const freqB = cardFrequency[b.id] || 1;
return Math.random() * (1 / freqA) - Math.random() * (1 / freqB);
});
setCards(newCards);
};
const handleSwiping = useCallback((x) => {
if (x > 0) {
setLabel('TRUE');
} else if (x < 0) {
setLabel('FALSE');
} else {
setLabel('');
}
}, []);
const handleSwiped = useCallback((cardIndex) => {
const card = cards[cardIndex % cards.length];
const newFrequency = { ...cardFrequency };
if (label === 'TRUE') {
newFrequency[card.id] = (newFrequency[card.id] || 1) * 0.5;
} else if (label === 'FALSE') {
newFrequency[card.id] = (newFrequency[card.id] || 1) * 2;
}
setCardFrequency(newFrequency);
AsyncStorage.setItem('cardFrequency', JSON.stringify(newFrequency));
setCurrentIndex((prevIndex) => (prevIndex + 1) % flashcards.length);
setLabel('');
flipAnimation.setValue(0);
updateCardOrder();
}, [cardFrequency, cards, label, flipAnimation]);
const handleSwipedAll = useCallback(() => {
if (swiperRef.current) {
swiperRef.current.jumpToCardIndex(0);
}
setCurrentIndex(0);
flipAnimation.setValue(0);
setLabel('');
}, []);
return (
<View style={styles.container}>
<Swiper
ref={swiperRef}
cards={cards}
renderCard={(card) => (
<TouchableWithoutFeedback onPress={flipCard}>
<View style={styles.cardContainer}>
<Animated.View style={[styles.card, frontAnimatedStyle]}>
<Text style={styles.text}>{card.german}</Text>
</Animated.View>
<Animated.View style={[styles.card, styles.cardBack, backAnimatedStyle]}>
<Text style={styles.text}>{card.turkish}</Text>
</Animated.View>
{label !== '' && (
<View style={label === 'TRUE' ? styles.correctLabel : styles.wrongLabel}>
<Text style={styles.labelText}>{label}</Text>
</View>
)}
</View>
</TouchableWithoutFeedback>
)}
onSwiped={handleSwiped}
onSwiping={handleSwiping}
cardIndex={currentIndex}
backgroundColor={'#F5FCFF'}
stackSize={2}
showSecondCard={false}
animateCardOpacity
swipeBackCard
containerStyle={styles.swiperContainer}
cardVerticalMargin={80}
onSwipedAll={handleSwipedAll}
infinite
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
justifyContent: 'center',
alignItems: 'center',
},
swiperContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
cardContainer: {
width: width * 0.8,
height: height * 0.6,
},
card: {
width: '100%',
height: '100%',
borderRadius: 8,
borderWidth: 2,
borderColor: '#E8E8E8',
justifyContent: 'center',
backgroundColor: 'white',
backfaceVisibility: 'hidden',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
cardBack: {
position: 'absolute',
top: 0,
},
text: {
textAlign: 'center',
fontSize: 24,
fontWeight: 'bold',
},
correctLabel: {
position: 'absolute',
top: 20,
left: 20,
backgroundColor: 'green',
padding: 10,
borderRadius: 5,
},
wrongLabel: {
position: 'absolute',
top: 20,
right: 20,
backgroundColor: 'red',
padding: 10,
borderRadius: 5,
},
labelText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
});
Thinking that it might be a problem with my phone, I wanted to run it with Expo Snack, but I couldn't try it because I couldn't install the packages.