about summary refs log tree commit diff
diff options
context:
space:
mode:
authordan <dan.abramov@gmail.com>2025-01-10 00:32:08 +0000
committerGitHub <noreply@github.com>2025-01-10 00:32:08 +0000
commit02dbcc134ef9f9870c4f6eab2da93773b8310d67 (patch)
treec69ac4c1a43f350a2eb01dd78dfec20d00bb9224
parent72dc508cb7f678df50ebb41db9adbcf826ed6975 (diff)
downloadvoidsky-02dbcc134ef9f9870c4f6eab2da93773b8310d67.tar.zst
Fix trending swipe gesture (#7417)
-rw-r--r--src/components/interstitials/Trending.tsx164
-rw-r--r--src/view/shell/TrendingGestureContext.tsx7
-rw-r--r--src/view/shell/index.tsx13
3 files changed, 105 insertions, 79 deletions
diff --git a/src/components/interstitials/Trending.tsx b/src/components/interstitials/Trending.tsx
index 9a5feb2b6..3e0308e43 100644
--- a/src/components/interstitials/Trending.tsx
+++ b/src/components/interstitials/Trending.tsx
@@ -1,6 +1,6 @@
-import React from 'react'
-import {View} from 'react-native'
-import {ScrollView} from 'react-native-gesture-handler'
+import React, {useContext} from 'react'
+import {ScrollView, View} from 'react-native'
+import {GestureDetector} from 'react-native-gesture-handler'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
@@ -12,6 +12,7 @@ import {
 import {useTrendingTopics} from '#/state/queries/trending/useTrendingTopics'
 import {useTrendingConfig} from '#/state/trending-config'
 import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
+import {TrendingGestureContext} from '#/view/shell/TrendingGestureContext'
 import {atoms as a, useGutters, useTheme} from '#/alf'
 import {Button, ButtonIcon} from '#/components/Button'
 import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
@@ -40,83 +41,92 @@ export function Inner() {
     setTrendingDisabled(true)
   }, [setTrendingDisabled])
 
+  // This is coordinated to take precedence over the drawer pan gesture.
+  const trendingScrollGesture = useContext(TrendingGestureContext)
+
   return error || noTopics ? null : (
     <View style={[t.atoms.border_contrast_low, a.border_t]}>
-      <ScrollView
-        horizontal
-        showsHorizontalScrollIndicator={false}
-        decelerationRate="fast">
-        <View style={[gutters, a.flex_row, a.align_center, a.gap_lg]}>
-          <View style={{paddingLeft: 4, paddingRight: 2}}>
-            <Graph size="sm" />
-          </View>
-          {isLoading ? (
-            <View style={[a.py_lg, a.flex_row, a.gap_lg, a.align_center]}>
-              <LoadingPlaceholder
-                width={80}
-                height={undefined}
-                style={{alignSelf: 'stretch'}}
-              />
-              <LoadingPlaceholder
-                width={50}
-                height={undefined}
-                style={{alignSelf: 'stretch'}}
-              />
-              <LoadingPlaceholder
-                width={120}
-                height={undefined}
-                style={{alignSelf: 'stretch'}}
-              />
-              <LoadingPlaceholder
-                width={30}
-                height={undefined}
-                style={{alignSelf: 'stretch'}}
-              />
-              <LoadingPlaceholder
-                width={180}
-                height={undefined}
-                style={{alignSelf: 'stretch'}}
-              />
-              <Text
-                style={[t.atoms.text_contrast_medium, a.text_sm, a.font_bold]}>
-                {' '}
-              </Text>
+      <GestureDetector gesture={trendingScrollGesture}>
+        <ScrollView
+          horizontal
+          showsHorizontalScrollIndicator={false}
+          decelerationRate="fast">
+          <View style={[gutters, a.flex_row, a.align_center, a.gap_lg]}>
+            <View style={{paddingLeft: 4, paddingRight: 2}}>
+              <Graph size="sm" />
             </View>
-          ) : !trending?.topics ? null : (
-            <>
-              {trending.topics.map(topic => (
-                <TrendingTopicLink
-                  key={topic.link}
-                  topic={topic}
-                  onPress={() => {
-                    logEvent('trendingTopic:click', {context: 'interstitial'})
-                  }}>
-                  <View style={[a.py_lg]}>
-                    <Text
-                      style={[
-                        t.atoms.text,
-                        a.text_sm,
-                        a.font_bold,
-                        {opacity: 0.7}, // NOTE: we use opacity 0.7 instead of a color to match the color of the home pager tab bar
-                      ]}>
-                      {topic.topic}
-                    </Text>
-                  </View>
-                </TrendingTopicLink>
-              ))}
-              <Button
-                label={_(msg`Hide trending topics`)}
-                size="tiny"
-                variant="ghost"
-                color="secondary"
-                shape="round"
-                onPress={() => trendingPrompt.open()}>
-                <ButtonIcon icon={X} />
-              </Button>
-            </>
-          )}
-        </View>
-      </ScrollView>
+            {isLoading ? (
+              <View style={[a.py_lg, a.flex_row, a.gap_lg, a.align_center]}>
+                <LoadingPlaceholder
+                  width={80}
+                  height={undefined}
+                  style={{alignSelf: 'stretch'}}
+                />
+                <LoadingPlaceholder
+                  width={50}
+                  height={undefined}
+                  style={{alignSelf: 'stretch'}}
+                />
+                <LoadingPlaceholder
+                  width={120}
+                  height={undefined}
+                  style={{alignSelf: 'stretch'}}
+                />
+                <LoadingPlaceholder
+                  width={30}
+                  height={undefined}
+                  style={{alignSelf: 'stretch'}}
+                />
+                <LoadingPlaceholder
+                  width={180}
+                  height={undefined}
+                  style={{alignSelf: 'stretch'}}
+                />
+                <Text
+                  style={[
+                    t.atoms.text_contrast_medium,
+                    a.text_sm,
+                    a.font_bold,
+                  ]}>
+                  {' '}
+                </Text>
+              </View>
+            ) : !trending?.topics ? null : (
+              <>
+                {trending.topics.map(topic => (
+                  <TrendingTopicLink
+                    key={topic.link}
+                    topic={topic}
+                    onPress={() => {
+                      logEvent('trendingTopic:click', {context: 'interstitial'})
+                    }}>
+                    <View style={[a.py_lg]}>
+                      <Text
+                        style={[
+                          t.atoms.text,
+                          a.text_sm,
+                          a.font_bold,
+                          {opacity: 0.7}, // NOTE: we use opacity 0.7 instead of a color to match the color of the home pager tab bar
+                        ]}>
+                        {topic.topic}
+                      </Text>
+                    </View>
+                  </TrendingTopicLink>
+                ))}
+                <Button
+                  label={_(msg`Hide trending topics`)}
+                  size="tiny"
+                  variant="ghost"
+                  color="secondary"
+                  shape="round"
+                  onPress={() => trendingPrompt.open()}>
+                  <ButtonIcon icon={X} />
+                </Button>
+              </>
+            )}
+          </View>
+        </ScrollView>
+      </GestureDetector>
 
       <Prompt.Basic
         control={trendingPrompt}
diff --git a/src/view/shell/TrendingGestureContext.tsx b/src/view/shell/TrendingGestureContext.tsx
new file mode 100644
index 000000000..8f21f444b
--- /dev/null
+++ b/src/view/shell/TrendingGestureContext.tsx
@@ -0,0 +1,7 @@
+import {createContext} from 'react'
+import {Gesture} from 'react-native-gesture-handler'
+
+// Not really used but serves as a fallback for types.
+const noopGesture = Gesture.Native()
+
+export const TrendingGestureContext = createContext(noopGesture)
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx
index a5e97610d..80e63c6bc 100644
--- a/src/view/shell/index.tsx
+++ b/src/view/shell/index.tsx
@@ -1,6 +1,7 @@
-import {useCallback, useEffect} from 'react'
+import {useCallback, useEffect, useState} from 'react'
 import {BackHandler, useWindowDimensions, View} from 'react-native'
 import {Drawer} from 'react-native-drawer-layout'
+import {Gesture} from 'react-native-gesture-handler'
 import {useSafeAreaInsets} from 'react-native-safe-area-context'
 import {StatusBar} from 'expo-status-bar'
 import {useNavigation, useNavigationState} from '@react-navigation/native'
@@ -33,6 +34,7 @@ import {BottomSheetOutlet} from '../../../modules/bottom-sheet'
 import {updateActiveViewAsync} from '../../../modules/expo-bluesky-swiss-army/src/VisibilityView'
 import {Composer} from './Composer'
 import {DrawerContent} from './Drawer'
+import {TrendingGestureContext} from './TrendingGestureContext'
 
 function ShellInner() {
   const t = useTheme()
@@ -92,6 +94,7 @@ function ShellInner() {
   }, [dedupe, navigation])
 
   const swipeEnabled = !canGoBack && hasSession && !isDrawerSwipeDisabled
+  const [trendingScrollGesture] = useState(() => Gesture.Native())
   return (
     <>
       <View style={[a.h_full]}>
@@ -101,6 +104,10 @@ function ShellInner() {
             renderDrawerContent={renderDrawerContent}
             drawerStyle={{width: Math.min(400, winDim.width * 0.8)}}
             configureGestureHandler={handler => {
+              handler = handler.requireExternalGestureToFail(
+                trendingScrollGesture,
+              )
+
               if (swipeEnabled) {
                 if (isDrawerOpen) {
                   return handler.activeOffsetX([-1, 1])
@@ -138,7 +145,9 @@ function ShellInner() {
                 dim: 'rgba(10, 13, 16, 0.8)',
               }),
             }}>
-            <TabsNavigator />
+            <TrendingGestureContext.Provider value={trendingScrollGesture}>
+              <TabsNavigator />
+            </TrendingGestureContext.Provider>
           </Drawer>
         </ErrorBoundary>
       </View>