fix: improve gestures

This commit is contained in:
Fredrik Burmester
2026-01-03 23:51:27 +01:00
parent 245c9597c4
commit bfdc2c053b

View File

@@ -111,28 +111,28 @@ export const MiniPlayerBar: React.FC = () => {
// Swipe up - open modal (check position OR velocity) // Swipe up - open modal (check position OR velocity)
if (currentPosition < -16 || velocity < -VELOCITY_THRESHOLD) { if (currentPosition < -16 || velocity < -VELOCITY_THRESHOLD) {
// Slow return animation - won't jank with navigation
translateY.value = withTiming(0, {
duration: 600,
easing: Easing.out(Easing.cubic),
});
runOnJS(handlePress)(); runOnJS(handlePress)();
return;
} }
// Swipe down - stop playback and dismiss (check position OR velocity) // Swipe down - stop playback and dismiss (check position OR velocity)
else if (currentPosition > 16 || velocity > VELOCITY_THRESHOLD) { if (currentPosition > 16 || velocity > VELOCITY_THRESHOLD) {
// No need to reset - component will unmount
runOnJS(handleDismiss)(); runOnJS(handleDismiss)();
return;
} }
// Smooth return to original position (no bounce) // Only animate back if no action was triggered
translateY.value = withTiming(0, { translateY.value = withTiming(0, {
duration: 200, duration: 200,
easing: Easing.out(Easing.cubic), easing: Easing.out(Easing.cubic),
}); });
}); });
// Tap gesture for opening modal (preserves existing behavior)
const tapGesture = Gesture.Tap().onEnd(() => {
runOnJS(handlePress)();
});
// Combine gestures - pan takes priority over tap
const composedGesture = Gesture.Race(panGesture, tapGesture);
// Animated styles for the container // Animated styles for the container
const animatedContainerStyle = useAnimatedStyle(() => ({ const animatedContainerStyle = useAnimatedStyle(() => ({
transform: [{ translateY: translateY.value }], transform: [{ translateY: translateY.value }],
@@ -158,31 +158,38 @@ export const MiniPlayerBar: React.FC = () => {
const content = ( const content = (
<> <>
{/* Album art */} {/* Tappable area: Album art + Track info */}
<View style={styles.albumArt}> <TouchableOpacity
{imageUrl ? ( onPress={handlePress}
<Image activeOpacity={0.7}
source={{ uri: imageUrl }} style={styles.tappableArea}
style={styles.albumImage} >
contentFit='cover' {/* Album art */}
cachePolicy='memory-disk' <View style={styles.albumArt}>
/> {imageUrl ? (
) : ( <Image
<View style={styles.albumPlaceholder}> source={{ uri: imageUrl }}
<Ionicons name='musical-note' size={20} color='#888' /> style={styles.albumImage}
</View> contentFit='cover'
)} cachePolicy='memory-disk'
</View> />
) : (
<View style={styles.albumPlaceholder}>
<Ionicons name='musical-note' size={20} color='#888' />
</View>
)}
</View>
{/* Track info */} {/* Track info */}
<View style={styles.trackInfo}> <View style={styles.trackInfo}>
<Text numberOfLines={1} style={styles.trackTitle}> <Text numberOfLines={1} style={styles.trackTitle}>
{currentTrack.Name} {currentTrack.Name}
</Text> </Text>
<Text numberOfLines={1} style={styles.artistName}> <Text numberOfLines={1} style={styles.artistName}>
{currentTrack.Artists?.join(", ") || currentTrack.AlbumArtist} {currentTrack.Artists?.join(", ") || currentTrack.AlbumArtist}
</Text> </Text>
</View> </View>
</TouchableOpacity>
{/* Controls */} {/* Controls */}
<View style={styles.controls}> <View style={styles.controls}>
@@ -222,7 +229,7 @@ export const MiniPlayerBar: React.FC = () => {
); );
return ( return (
<GestureDetector gesture={composedGesture}> <GestureDetector gesture={panGesture}>
<Animated.View <Animated.View
style={[ style={[
styles.container, styles.container,
@@ -288,6 +295,11 @@ const styles = StyleSheet.create({
borderWidth: 0.5, borderWidth: 0.5,
borderColor: "rgba(255, 255, 255, 0.1)", borderColor: "rgba(255, 255, 255, 0.1)",
}, },
tappableArea: {
flex: 1,
flexDirection: "row",
alignItems: "center",
},
albumArt: { albumArt: {
width: 32, width: 32,
height: 32, height: 32,