/ components / EnhancedBackButton.tsx
EnhancedBackButton.tsx
  1  import React, { useState } from 'react';
  2  import { View, StyleSheet, useColorScheme, Pressable } from 'react-native';
  3  import { Ionicons } from '@expo/vector-icons';
  4  import { Colors, ColorScheme } from '@/constants/Colors';
  5  import { useNavigationHistory } from '@/hooks/useNavigationHistory';
  6  import NavigationHistoryPanel from './NavigationHistoryPanel';
  7  
  8  interface EnhancedBackButtonProps {
  9    size?: number;
 10    color?: string;
 11    style?: any;
 12    showHistoryOnLongPress?: boolean;
 13    customOnPress?: () => void;
 14    disabled?: boolean;
 15  }
 16  
 17  const EnhancedBackButton: React.FC<EnhancedBackButtonProps> = ({
 18    size = 24,
 19    color,
 20    style,
 21    showHistoryOnLongPress = true,
 22    customOnPress,
 23    disabled = false,
 24  }) => {
 25    const colorScheme = useColorScheme() as ColorScheme;
 26    const { handleBackPress, canGoBack, currentDepth } = useNavigationHistory();
 27    const [showHistoryPanel, setShowHistoryPanel] = useState(false);
 28    const [isPressed, setIsPressed] = useState(false);
 29  
 30    const colors = Colors[colorScheme];
 31    const buttonColor = color || colors.text;
 32    const isDisabled = disabled || !canGoBack;
 33  
 34    const handlePress = async () => {
 35      if (isDisabled) return;
 36  
 37      if (customOnPress) {
 38        customOnPress();
 39      } else {
 40        await handleBackPress('tap');
 41      }
 42    };
 43  
 44    const handleLongPress = () => {
 45      if (isDisabled || !showHistoryOnLongPress) return;
 46      setShowHistoryPanel(true);
 47    };
 48  
 49    const getBackgroundColor = () => {
 50      if (isDisabled) return 'transparent';
 51      if (isPressed) return colors.primary + '20';
 52      return 'transparent';
 53    };
 54  
 55    return (
 56      <>
 57        <Pressable
 58          style={[
 59            styles.container,
 60            {
 61              backgroundColor: getBackgroundColor(),
 62              opacity: isDisabled ? 0.3 : 1,
 63            },
 64            style,
 65          ]}
 66          onPress={handlePress}
 67          onLongPress={handleLongPress}
 68          onPressIn={() => setIsPressed(true)}
 69          onPressOut={() => setIsPressed(false)}
 70          disabled={isDisabled}
 71          delayLongPress={500}
 72        >
 73          <View style={styles.iconContainer}>
 74            <Ionicons name="arrow-back" size={size} color={buttonColor} />
 75            {currentDepth > 1 && (
 76              <View
 77                style={[
 78                  styles.depthIndicator,
 79                  { backgroundColor: colors.primary },
 80                ]}
 81              >
 82                <Ionicons
 83                  name="ellipsis-horizontal"
 84                  size={size * 0.5}
 85                  color={colors.background}
 86                />
 87              </View>
 88            )}
 89          </View>
 90        </Pressable>
 91  
 92        <NavigationHistoryPanel
 93          visible={showHistoryPanel}
 94          onClose={() => setShowHistoryPanel(false)}
 95        />
 96      </>
 97    );
 98  };
 99  
100  interface FloatingBackButtonProps extends EnhancedBackButtonProps {
101    position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
102    offset?: { x: number; y: number };
103  }
104  
105  export const FloatingBackButton: React.FC<FloatingBackButtonProps> = ({
106    position = 'top-left',
107    offset = { x: 20, y: 60 },
108    size = 28,
109    ...props
110  }) => {
111    const colorScheme = useColorScheme() as ColorScheme;
112    const colors = Colors[colorScheme];
113  
114    const getPositionStyle = () => {
115      const baseStyle = {
116        position: 'absolute' as const,
117        width: 48,
118        height: 48,
119        borderRadius: 24,
120        backgroundColor: colors.card,
121        shadowColor: '#000',
122        shadowOffset: { width: 0, height: 2 },
123        shadowOpacity: 0.25,
124        shadowRadius: 3.84,
125        elevation: 5,
126        justifyContent: 'center' as const,
127        alignItems: 'center' as const,
128      };
129  
130      switch (position) {
131        case 'top-left':
132          return { ...baseStyle, top: offset.y, left: offset.x };
133        case 'top-right':
134          return { ...baseStyle, top: offset.y, right: offset.x };
135        case 'bottom-left':
136          return { ...baseStyle, bottom: offset.y, left: offset.x };
137        case 'bottom-right':
138          return { ...baseStyle, bottom: offset.y, right: offset.x };
139        default:
140          return { ...baseStyle, top: offset.y, left: offset.x };
141      }
142    };
143  
144    return (
145      <EnhancedBackButton {...props} size={size} style={getPositionStyle()} />
146    );
147  };
148  
149  const styles = StyleSheet.create({
150    container: {
151      padding: 8,
152      borderRadius: 20,
153      justifyContent: 'center',
154      alignItems: 'center',
155      minWidth: 40,
156      minHeight: 40,
157    },
158    iconContainer: {
159      position: 'relative',
160      justifyContent: 'center',
161      alignItems: 'center',
162    },
163    depthIndicator: {
164      position: 'absolute',
165      top: -4,
166      right: -4,
167      width: 16,
168      height: 16,
169      borderRadius: 8,
170      justifyContent: 'center',
171      alignItems: 'center',
172    },
173  });
174  
175  export default EnhancedBackButton;