File size: 3,768 Bytes
9a92a42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import React, { useState, useEffect, useRef } from 'react';
import { View, Text, StyleSheet, Image, Animated, Easing } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import { Ionicons } from '@expo/vector-icons';

const AnimatedMapPin = ({ training }) => {
  const [showPopup, setShowPopup] = useState(false);
  const [currentImageIndex, setCurrentImageIndex] = useState(0);
  
  const scaleAnim = useRef(new Animated.Value(0)).current; // For popup appear/disappear
  const opacityAnim = useRef(new Animated.Value(0)).current; // For image fade in/out

  const hasImages = training.photos && training.photos.length > 0;

  useEffect(() => {
    if (!hasImages) return;

    const mainLoop = () => {
      // 1. Appear
      setShowPopup(true);
      Animated.spring(scaleAnim, {
        toValue: 1,
        friction: 5,
        useNativeDriver: true,
      }).start(() => {
        // 2. Start image slideshow
        runSlideshow();
      });
    };

    const runSlideshow = () => {
      // Fade in the first image
      fadeImage(true, () => {
        // After fade-in, wait, then start cycling
        setTimeout(() => cycleImages(1), 2000);
      });
    };

    const cycleImages = (nextIndex) => {
      // Fade out current image
      fadeImage(false, () => {
        if (nextIndex >= training.photos.length) {
          // Slideshow finished, hide the popup
          hidePopup();
        } else {
          // Show next image
          setCurrentImageIndex(nextIndex);
          fadeImage(true, () => {
            // Wait, then cycle to the next one
            setTimeout(() => cycleImages(nextIndex + 1), 2000);
          });
        }
      });
    };

    const fadeImage = (fadeIn, onComplete) => {
      Animated.timing(opacityAnim, {
        toValue: fadeIn ? 1 : 0,
        duration: 800, // Smooth fade duration
        easing: Easing.ease,
        useNativeDriver: true,
      }).start(onComplete);
    };

    const hidePopup = () => {
      Animated.timing(scaleAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }).start(() => {
        setShowPopup(false);
        setCurrentImageIndex(0); // Reset for next loop
        // 3. Disappear for 1 second, then restart loop
        setTimeout(mainLoop, 1000);
      });
    };

    // Start the main loop
    mainLoop();

  }, [training, hasImages]);

  if (!training.location) return null;

  return (
    <Marker
      coordinate={{
        latitude: training.location.latitude,
        longitude: training.location.longitude,
      }}
      anchor={{ x: 0.5, y: 0.5 }}
    >
      <View style={styles.markerContainer}>
        {showPopup && hasImages && (
          <Animated.View style={[styles.popup, { transform: [{ scale: scaleAnim }] }]}>
            <Animated.Image
              source={{ uri: training.photos[currentImageIndex] }}
              style={[styles.popupImage, { opacity: opacityAnim }]}
              resizeMode="cover"
            />
          </Animated.View>
        )}
        <View style={styles.pin}>
          <Ionicons name="location" size={40} color="#FF5A5F" />
        </View>
      </View>
    </Marker>
  );
};

const styles = StyleSheet.create({
  markerContainer: {
    alignItems: 'center',
    justifyContent: 'center',
  },
  pin: {
    // The pin itself
  },
  popup: {
    position: 'absolute',
    bottom: 35, // Position above the pin
    width: 80,
    height: 80,
    backgroundColor: 'white',
    borderRadius: 10,
    padding: 4,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.3,
    shadowRadius: 3,
    elevation: 5,
  },
  popupImage: {
    width: '100%',
    height: '100%',
    borderRadius: 6,
  },
});

export default AnimatedMapPin;