|
1 | | -import { NavigationContainer } from '@react-navigation/native'; |
2 | | -import { ReanimatedTrueSheetProvider } from '@lodev09/react-native-true-sheet/reanimated'; |
3 | | -import { MapProvider } from '@lugg/maps'; |
4 | | -const GOOGLE_MAPS_API_KEY = process.env.GOOGLE_MAPS_API_KEY ?? ''; |
| 1 | +import { useEffect, useRef, useState, useCallback } from 'react'; |
| 2 | +import { Alert, Pressable, StyleSheet, Text, TextInput, View } from 'react-native'; |
| 3 | +import { TrueSheet, TrueSheetProvider } from '@lodev09/react-native-true-sheet'; |
| 4 | +import { SafeAreaProvider, useSafeAreaInsets } from 'react-native-safe-area-context'; |
5 | 5 |
|
6 | | -import { RootNavigator } from './navigators'; |
| 6 | +const DARK = '#1c1c1e'; |
| 7 | +const DARK_BLUE = '#2c2c3e'; |
| 8 | +const SPACING = 16; |
| 9 | +const GAP = 12; |
| 10 | + |
| 11 | +const FooterRepro = () => { |
| 12 | + const sheetRef = useRef<TrueSheet>(null); |
| 13 | + const insets = useSafeAreaInsets(); |
| 14 | + const [footerTaps, setFooterTaps] = useState(0); |
| 15 | + const [contentTaps, setContentTaps] = useState(0); |
| 16 | + const footerTapsRef = useRef(0); |
| 17 | + |
| 18 | + const handleFooterTap = useCallback(() => { |
| 19 | + footerTapsRef.current += 1; |
| 20 | + const count = footerTapsRef.current; |
| 21 | + setFooterTaps(count); |
| 22 | + Alert.alert('Footer Tap', `Count: ${count}`); |
| 23 | + }, []); |
| 24 | + |
| 25 | + useEffect(() => { |
| 26 | + const timer = setTimeout(() => sheetRef.current?.present(), 500); |
| 27 | + return () => clearTimeout(timer); |
| 28 | + }, []); |
| 29 | + |
| 30 | + return ( |
| 31 | + <View style={[styles.container, { paddingTop: insets.top + 16 }]}> |
| 32 | + <Text style={styles.title}>Footer Touch Repro</Text> |
| 33 | + <Text style={styles.subtitle}> |
| 34 | + {'Tap each button 10 times. The counter should reach 10.\n\n' + |
| 35 | + 'BUG: On physical iOS devices, every 2nd footer tap is ' + |
| 36 | + 'silently swallowed. The content button (control) works every time.'} |
| 37 | + </Text> |
| 38 | + <Pressable |
| 39 | + style={[styles.button, { backgroundColor: '#007AFF', marginBottom: 16 }]} |
| 40 | + onPress={() => sheetRef.current?.present()} |
| 41 | + > |
| 42 | + <Text style={styles.buttonText}>Present Sheet</Text> |
| 43 | + </Pressable> |
| 44 | + |
| 45 | + <TrueSheet |
| 46 | + ref={sheetRef} |
| 47 | + detents={['auto', 0.5, 1]} |
| 48 | + backgroundColor={DARK} |
| 49 | + style={styles.sheetContent} |
| 50 | + footer={ |
| 51 | + <View style={styles.footer}> |
| 52 | + <Pressable |
| 53 | + style={[ |
| 54 | + styles.button, |
| 55 | + footerTaps >= 10 |
| 56 | + ? { backgroundColor: '#2d7d2d' } |
| 57 | + : footerTaps > 0 && footerTaps < 10 |
| 58 | + ? { backgroundColor: '#cc3333' } |
| 59 | + : undefined, |
| 60 | + ]} |
| 61 | + onPress={handleFooterTap} |
| 62 | + > |
| 63 | + <Text style={styles.buttonText}> |
| 64 | + FOOTER: {footerTaps}/10 {footerTaps >= 10 ? ' PASS' : ''} |
| 65 | + </Text> |
| 66 | + </Pressable> |
| 67 | + <TextInput |
| 68 | + style={styles.input} |
| 69 | + placeholder="Tap to focus (keyboard test)" |
| 70 | + placeholderTextColor="#999" |
| 71 | + returnKeyType="done" |
| 72 | + /> |
| 73 | + </View> |
| 74 | + } |
| 75 | + > |
| 76 | + <Pressable |
| 77 | + style={[ |
| 78 | + styles.demoBlock, |
| 79 | + contentTaps >= 10 |
| 80 | + ? { backgroundColor: '#2d7d2d' } |
| 81 | + : contentTaps > 0 && contentTaps < 10 |
| 82 | + ? { backgroundColor: '#cc3333' } |
| 83 | + : undefined, |
| 84 | + ]} |
| 85 | + onPress={() => setContentTaps((n) => n + 1)} |
| 86 | + > |
| 87 | + <Text style={styles.demoText}> |
| 88 | + CONTENT: {contentTaps}/10 {contentTaps >= 10 ? ' PASS' : ''} |
| 89 | + </Text> |
| 90 | + <Text style={[styles.demoText, { fontSize: 12, marginTop: 4, opacity: 0.6 }]}> |
| 91 | + (control — this should always work) |
| 92 | + </Text> |
| 93 | + </Pressable> |
| 94 | + <View style={styles.demoBlock}> |
| 95 | + <Text style={styles.demoText}>Sheet content block 2</Text> |
| 96 | + </View> |
| 97 | + <View style={styles.demoBlock}> |
| 98 | + <Text style={styles.demoText}>Sheet content block 3</Text> |
| 99 | + </View> |
| 100 | + </TrueSheet> |
| 101 | + </View> |
| 102 | + ); |
| 103 | +}; |
7 | 104 |
|
8 | 105 | const App = () => { |
9 | 106 | return ( |
10 | | - <MapProvider apiKey={GOOGLE_MAPS_API_KEY}> |
11 | | - <ReanimatedTrueSheetProvider> |
12 | | - <NavigationContainer> |
13 | | - <RootNavigator /> |
14 | | - </NavigationContainer> |
15 | | - </ReanimatedTrueSheetProvider> |
16 | | - </MapProvider> |
| 107 | + <SafeAreaProvider> |
| 108 | + <TrueSheetProvider> |
| 109 | + <FooterRepro /> |
| 110 | + </TrueSheetProvider> |
| 111 | + </SafeAreaProvider> |
17 | 112 | ); |
18 | 113 | }; |
19 | 114 |
|
20 | 115 | export default App; |
| 116 | + |
| 117 | +const styles = StyleSheet.create({ |
| 118 | + container: { |
| 119 | + flex: 1, |
| 120 | + backgroundColor: '#f5f5f5', |
| 121 | + alignItems: 'center', |
| 122 | + padding: SPACING, |
| 123 | + }, |
| 124 | + title: { |
| 125 | + fontSize: 22, |
| 126 | + fontWeight: 'bold', |
| 127 | + marginBottom: 8, |
| 128 | + }, |
| 129 | + subtitle: { |
| 130 | + fontSize: 14, |
| 131 | + color: '#666', |
| 132 | + textAlign: 'center', |
| 133 | + marginBottom: 24, |
| 134 | + paddingHorizontal: 20, |
| 135 | + }, |
| 136 | + sheetContent: { |
| 137 | + paddingHorizontal: SPACING, |
| 138 | + paddingTop: SPACING, |
| 139 | + paddingBottom: 80 + SPACING, |
| 140 | + gap: GAP, |
| 141 | + }, |
| 142 | + footer: { |
| 143 | + padding: SPACING, |
| 144 | + gap: GAP, |
| 145 | + }, |
| 146 | + demoBlock: { |
| 147 | + backgroundColor: DARK_BLUE, |
| 148 | + borderRadius: 12, |
| 149 | + padding: 24, |
| 150 | + alignItems: 'center', |
| 151 | + }, |
| 152 | + demoText: { |
| 153 | + color: '#fff', |
| 154 | + fontSize: 16, |
| 155 | + }, |
| 156 | + button: { |
| 157 | + backgroundColor: DARK_BLUE, |
| 158 | + height: 48, |
| 159 | + borderRadius: 24, |
| 160 | + alignItems: 'center', |
| 161 | + justifyContent: 'center', |
| 162 | + paddingHorizontal: SPACING, |
| 163 | + }, |
| 164 | + buttonText: { |
| 165 | + color: '#fff', |
| 166 | + fontSize: 16, |
| 167 | + }, |
| 168 | + input: { |
| 169 | + backgroundColor: 'rgba(0, 0, 0, 0.5)', |
| 170 | + paddingHorizontal: SPACING, |
| 171 | + height: 48, |
| 172 | + borderRadius: 24, |
| 173 | + fontSize: 16, |
| 174 | + color: '#fff', |
| 175 | + }, |
| 176 | +}); |
0 commit comments