about summary refs log tree commit diff
path: root/src/lib/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hooks')
-rw-r--r--src/lib/hooks/useCustomFeed.ts27
-rw-r--r--src/lib/hooks/useDraggableScrollView.ts84
-rw-r--r--src/lib/hooks/useNavigationTabState.ts4
-rw-r--r--src/lib/hooks/useOnMainScroll.ts61
4 files changed, 160 insertions, 16 deletions
diff --git a/src/lib/hooks/useCustomFeed.ts b/src/lib/hooks/useCustomFeed.ts
new file mode 100644
index 000000000..d7a27050d
--- /dev/null
+++ b/src/lib/hooks/useCustomFeed.ts
@@ -0,0 +1,27 @@
+import {useEffect, useState} from 'react'
+import {useStores} from 'state/index'
+import {CustomFeedModel} from 'state/models/feeds/custom-feed'
+
+export function useCustomFeed(uri: string): CustomFeedModel | undefined {
+  const store = useStores()
+  const [item, setItem] = useState<CustomFeedModel | undefined>()
+  useEffect(() => {
+    async function fetchView() {
+      const res = await store.agent.app.bsky.feed.getFeedGenerator({
+        feed: uri,
+      })
+      const view = res.data.view
+      return view
+    }
+    async function buildFeedItem() {
+      const view = await fetchView()
+      if (view) {
+        const temp = new CustomFeedModel(store, view)
+        setItem(temp)
+      }
+    }
+    buildFeedItem()
+  }, [store, uri])
+
+  return item
+}
diff --git a/src/lib/hooks/useDraggableScrollView.ts b/src/lib/hooks/useDraggableScrollView.ts
new file mode 100644
index 000000000..b0f7465d7
--- /dev/null
+++ b/src/lib/hooks/useDraggableScrollView.ts
@@ -0,0 +1,84 @@
+import {useEffect, useRef, useMemo, ForwardedRef} from 'react'
+import {Platform, findNodeHandle} from 'react-native'
+import type {ScrollView} from 'react-native'
+import {mergeRefs} from 'lib/merge-refs'
+
+type Props<Scrollable extends ScrollView = ScrollView> = {
+  cursor?: string
+  outerRef?: ForwardedRef<Scrollable>
+}
+
+export function useDraggableScroll<Scrollable extends ScrollView = ScrollView>({
+  outerRef,
+  cursor = 'grab',
+}: Props<Scrollable> = {}) {
+  const ref = useRef<Scrollable>(null)
+
+  useEffect(() => {
+    if (Platform.OS !== 'web' || !ref.current) {
+      return
+    }
+    const slider = findNodeHandle(ref.current) as unknown as HTMLDivElement
+    if (!slider) {
+      return
+    }
+    let isDragging = false
+    let isMouseDown = false
+    let startX = 0
+    let scrollLeft = 0
+
+    const mouseDown = (e: MouseEvent) => {
+      isMouseDown = true
+      startX = e.pageX - slider.offsetLeft
+      scrollLeft = slider.scrollLeft
+
+      slider.style.cursor = cursor
+    }
+
+    const mouseUp = () => {
+      if (isDragging) {
+        slider.addEventListener('click', e => e.stopPropagation(), {once: true})
+      }
+
+      isMouseDown = false
+      isDragging = false
+      slider.style.cursor = 'default'
+    }
+
+    const mouseMove = (e: MouseEvent) => {
+      if (!isMouseDown) {
+        return
+      }
+
+      // Require n pixels momement before start of drag (3 in this case )
+      const x = e.pageX - slider.offsetLeft
+      if (Math.abs(x - startX) < 3) {
+        return
+      }
+
+      isDragging = true
+      e.preventDefault()
+      const walk = x - startX
+      slider.scrollLeft = scrollLeft - walk
+    }
+
+    slider.addEventListener('mousedown', mouseDown)
+    window.addEventListener('mouseup', mouseUp)
+    window.addEventListener('mousemove', mouseMove)
+
+    return () => {
+      slider.removeEventListener('mousedown', mouseDown)
+      window.removeEventListener('mouseup', mouseUp)
+      window.removeEventListener('mousemove', mouseMove)
+    }
+  }, [cursor])
+
+  const refs = useMemo(
+    () => mergeRefs(outerRef ? [ref, outerRef] : [ref]),
+    [ref, outerRef],
+  )
+
+  return {
+    refs,
+  }
+}
diff --git a/src/lib/hooks/useNavigationTabState.ts b/src/lib/hooks/useNavigationTabState.ts
index fb3662152..3a05fe524 100644
--- a/src/lib/hooks/useNavigationTabState.ts
+++ b/src/lib/hooks/useNavigationTabState.ts
@@ -6,14 +6,16 @@ export function useNavigationTabState() {
     const res = {
       isAtHome: getTabState(state, 'Home') !== TabState.Outside,
       isAtSearch: getTabState(state, 'Search') !== TabState.Outside,
+      isAtFeeds: getTabState(state, 'Feeds') !== TabState.Outside,
       isAtNotifications:
         getTabState(state, 'Notifications') !== TabState.Outside,
       isAtMyProfile: getTabState(state, 'MyProfile') !== TabState.Outside,
     }
     if (
       !res.isAtHome &&
-      !res.isAtNotifications &&
       !res.isAtSearch &&
+      !res.isAtFeeds &&
+      !res.isAtNotifications &&
       !res.isAtMyProfile
     ) {
       // HACK for some reason useNavigationState will give us pre-hydration results
diff --git a/src/lib/hooks/useOnMainScroll.ts b/src/lib/hooks/useOnMainScroll.ts
index 41b35dd4f..12e42aca5 100644
--- a/src/lib/hooks/useOnMainScroll.ts
+++ b/src/lib/hooks/useOnMainScroll.ts
@@ -1,25 +1,56 @@
-import {useState} from 'react'
+import {useState, useCallback, useRef} from 'react'
 import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native'
 import {RootStoreModel} from 'state/index'
+import {s} from 'lib/styles'
+import {isDesktopWeb} from 'platform/detection'
+
+const DY_LIMIT = isDesktopWeb ? 30 : 10
 
 export type OnScrollCb = (
   event: NativeSyntheticEvent<NativeScrollEvent>,
 ) => void
+export type ResetCb = () => void
+
+export function useOnMainScroll(
+  store: RootStoreModel,
+): [OnScrollCb, boolean, ResetCb] {
+  let lastY = useRef(0)
+  let [isScrolledDown, setIsScrolledDown] = useState(false)
+  return [
+    useCallback(
+      (event: NativeSyntheticEvent<NativeScrollEvent>) => {
+        const y = event.nativeEvent.contentOffset.y
+        const dy = y - (lastY.current || 0)
+        lastY.current = y
 
-export function useOnMainScroll(store: RootStoreModel) {
-  let [lastY, setLastY] = useState(0)
-  let isMinimal = store.shell.minimalShellMode
-  return function onMainScroll(event: NativeSyntheticEvent<NativeScrollEvent>) {
-    const y = event.nativeEvent.contentOffset.y
-    const dy = y - (lastY || 0)
-    setLastY(y)
+        if (!store.shell.minimalShellMode && y > 10 && dy > DY_LIMIT) {
+          store.shell.setMinimalShellMode(true)
+        } else if (
+          store.shell.minimalShellMode &&
+          (y <= 10 || dy < DY_LIMIT * -1)
+        ) {
+          store.shell.setMinimalShellMode(false)
+        }
 
-    if (!isMinimal && y > 10 && dy > 10) {
-      store.shell.setMinimalShellMode(true)
-      isMinimal = true
-    } else if (isMinimal && (y <= 10 || dy < -10)) {
+        if (
+          !isScrolledDown &&
+          event.nativeEvent.contentOffset.y > s.window.height
+        ) {
+          setIsScrolledDown(true)
+        } else if (
+          isScrolledDown &&
+          event.nativeEvent.contentOffset.y < s.window.height
+        ) {
+          setIsScrolledDown(false)
+        }
+      },
+      [store, isScrolledDown],
+    ),
+    isScrolledDown,
+    useCallback(() => {
+      setIsScrolledDown(false)
       store.shell.setMinimalShellMode(false)
-      isMinimal = false
-    }
-  }
+      lastY.current = 1e8 // NOTE we set this very high so that the onScroll logic works right -prf
+    }, [store, setIsScrolledDown]),
+  ]
 }