|
1 | 1 | import * as React from 'react'; |
2 | 2 | import { ActivityIndicator, Keyboard, LayoutChangeEvent, Modal as RNModal, Platform, Pressable, ScrollView, Text, TextInput, View } from 'react-native'; |
3 | 3 | import { Ionicons } from '@expo/vector-icons'; |
| 4 | +import { BlurView } from 'expo-blur'; |
4 | 5 | import { useSafeAreaInsets } from 'react-native-safe-area-context'; |
5 | 6 | import { StyleSheet, useUnistyles } from 'react-native-unistyles'; |
6 | 7 | import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'; |
@@ -90,20 +91,23 @@ const MOBILE_ACTION_ROW_GEOMETRY = resolveMobileComposerActionRowGeometry(); |
90 | 91 | const MOBILE_ICON_ACTION_GEOMETRY = resolveMobileComposerActionGeometry('icon'); |
91 | 92 | const MOBILE_PRIMARY_ACTION_GEOMETRY = resolveMobileComposerActionGeometry('primary'); |
92 | 93 | const MOBILE_COLLAPSED_COMPOSER_GEOMETRY = resolveMobileCollapsedComposerGeometry(); |
| 94 | +const MOBILE_HOME_DOCK_TOP_PADDING = 8; |
93 | 95 |
|
94 | 96 | const styles = StyleSheet.create((theme) => ({ |
95 | 97 | keyboardFollower: { |
96 | 98 | width: '100%', |
97 | 99 | }, |
98 | | - // Reaches above the dock so the scrim's ramp lands on content rather than |
99 | | - // on the composer itself. |
| 100 | + // Keep the content clear until the composer's midpoint. From there the |
| 101 | + // bottom scrim begins feathering over content that scrolls beneath it; |
| 102 | + // above that point the composer shadow provides the only separation. |
100 | 103 | bottomBackdrop: { |
101 | 104 | ...StyleSheet.absoluteFillObject, |
102 | | - top: -26, |
| 105 | + top: MOBILE_HOME_DOCK_TOP_PADDING |
| 106 | + + MOBILE_COLLAPSED_COMPOSER_GEOMETRY.shellHeight / 2, |
103 | 107 | }, |
104 | 108 | safeArea: { |
105 | 109 | paddingHorizontal: 16, |
106 | | - paddingTop: 8, |
| 110 | + paddingTop: MOBILE_HOME_DOCK_TOP_PADDING, |
107 | 111 | }, |
108 | 112 | // The focused composer replaces the resting one rather than covering it: |
109 | 113 | // the modal sits a safe-area inset higher, so leaving this on screen showed |
@@ -296,7 +300,7 @@ const styles = StyleSheet.create((theme) => ({ |
296 | 300 | right: 0, |
297 | 301 | bottom: 0, |
298 | 302 | }, |
299 | | - focusBackdrop: { |
| 303 | + focusBackdropDim: { |
300 | 304 | backgroundColor: theme.dark ? 'rgba(0, 0, 0, 0.88)' : 'rgba(255, 255, 255, 0.88)', |
301 | 305 | }, |
302 | 306 | focusDock: { |
@@ -1586,8 +1590,20 @@ export const HomeDock = React.memo(({ |
1586 | 1590 | <View style={styles.modalRoot}> |
1587 | 1591 | <Animated.View |
1588 | 1592 | pointerEvents="box-none" |
1589 | | - style={[styles.modalBackdrop, styles.focusBackdrop, focusBackdropStyle]} |
| 1593 | + style={[styles.modalBackdrop, focusBackdropStyle]} |
1590 | 1594 | > |
| 1595 | + <BlurView |
| 1596 | + blurMethod={Platform.OS === 'android' ? 'dimezisBlurViewSdk31Plus' : undefined} |
| 1597 | + blurReductionFactor={2} |
| 1598 | + intensity={8} |
| 1599 | + pointerEvents="none" |
| 1600 | + tint={theme.dark ? 'systemUltraThinMaterialDark' : 'systemUltraThinMaterialLight'} |
| 1601 | + style={styles.modalBackdrop} |
| 1602 | + /> |
| 1603 | + <View |
| 1604 | + pointerEvents="none" |
| 1605 | + style={[styles.modalBackdrop, styles.focusBackdropDim]} |
| 1606 | + /> |
1591 | 1607 | <Pressable |
1592 | 1608 | style={styles.modalBackdrop} |
1593 | 1609 | onPress={handleFocusBackdropPress} |
|
0 commit comments