about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/state/models/feeds/algo/saved.ts39
-rw-r--r--src/view/com/algos/AlgoItem.tsx4
-rw-r--r--src/view/com/pager/FeedsTabBar.web.tsx13
-rw-r--r--src/view/index.ts2
-rw-r--r--src/view/screens/CustomFeed.tsx2
-rw-r--r--src/view/screens/PinnedFeeds.tsx81
6 files changed, 116 insertions, 25 deletions
diff --git a/src/state/models/feeds/algo/saved.ts b/src/state/models/feeds/algo/saved.ts
index 97d75820d..cb2015ccb 100644
--- a/src/state/models/feeds/algo/saved.ts
+++ b/src/state/models/feeds/algo/saved.ts
@@ -1,4 +1,4 @@
-import {makeAutoObservable} from 'mobx'
+import {makeAutoObservable, runInAction} from 'mobx'
 import {AppBskyFeedGetSavedFeeds as GetSavedFeeds} from '@atproto/api'
 import {RootStoreModel} from '../../root-store'
 import {bundleAsync} from 'lib/async/bundle'
@@ -103,6 +103,43 @@ export class SavedFeedsModel {
     return this.pinned.find(f => f.data.uri === feed.data.uri) ? true : false
   }
 
+  movePinnedItem(item: AlgoItemModel, direction: 'up' | 'down') {
+    if (this.pinned.length < 2) {
+      throw new Error('Array must have at least 2 items')
+    }
+    const index = this.pinned.indexOf(item)
+    if (index === -1) {
+      throw new Error('Item not found in array')
+    }
+
+    const len = this.pinned.length
+
+    runInAction(() => {
+      if (direction === 'up') {
+        if (index === 0) {
+          // Remove the item from the first place and put it at the end
+          this.pinned.push(this.pinned.shift()!)
+        } else {
+          // Swap the item with the one before it
+          const temp = this.pinned[index]
+          this.pinned[index] = this.pinned[index - 1]
+          this.pinned[index - 1] = temp
+        }
+      } else if (direction === 'down') {
+        if (index === len - 1) {
+          // Remove the item from the last place and put it at the start
+          this.pinned.unshift(this.pinned.pop()!)
+        } else {
+          // Swap the item with the one after it
+          const temp = this.pinned[index]
+          this.pinned[index] = this.pinned[index + 1]
+          this.pinned[index + 1] = temp
+        }
+      }
+      // this.pinned = [...this.pinned]
+    })
+  }
+
   // public api
   // =
 
diff --git a/src/view/com/algos/AlgoItem.tsx b/src/view/com/algos/AlgoItem.tsx
index f2c36d7e9..56ee6d1d2 100644
--- a/src/view/com/algos/AlgoItem.tsx
+++ b/src/view/com/algos/AlgoItem.tsx
@@ -19,6 +19,7 @@ import {useStores} from 'state/index'
 import {HeartIconSolid} from 'lib/icons'
 import {pluralize} from 'lib/strings/helpers'
 import {AtUri} from '@atproto/api'
+import {isWeb} from 'platform/detection'
 
 const AlgoItem = observer(
   ({
@@ -37,8 +38,9 @@ const AlgoItem = observer(
     const navigation = useNavigation<NavigationProp>()
 
     // TODO: this is pretty hacky, but it works for now
+    // causes issues on web
     useFocusEffect(() => {
-      if (reloadOnFocus) {
+      if (reloadOnFocus && !isWeb) {
         item.reload()
       }
     })
diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx
index 0fc1b7310..a5e596143 100644
--- a/src/view/com/pager/FeedsTabBar.web.tsx
+++ b/src/view/com/pager/FeedsTabBar.web.tsx
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {useMemo} from 'react'
 import {Animated, StyleSheet} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import {TabBar} from 'view/com/pager/TabBar'
@@ -27,6 +27,14 @@ const FeedsTabBarDesktop = observer(
     props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
   ) => {
     const store = useStores()
+    const items = useMemo(
+      () => [
+        'Following',
+        "What's hot",
+        ...store.me.savedFeeds.listOfPinnedFeedNames,
+      ],
+      [store.me.savedFeeds.listOfPinnedFeedNames],
+    )
     const pal = usePalette('default')
     const interp = useAnimatedValue(0)
 
@@ -44,12 +52,13 @@ const FeedsTabBarDesktop = observer(
         {translateY: Animated.multiply(interp, -100)},
       ],
     }
+
     return (
       // @ts-ignore the type signature for transform wrong here, translateX and translateY need to be in separate objects -prf
       <Animated.View style={[pal.view, styles.tabBar, transform]}>
         <TabBar
           {...props}
-          items={['Following', "What's hot"]}
+          items={items}
           indicatorPosition="bottom"
           indicatorColor={pal.colors.link}
         />
diff --git a/src/view/index.ts b/src/view/index.ts
index 253735e81..9c8d023dd 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -8,6 +8,7 @@ import {faAngleUp} from '@fortawesome/free-solid-svg-icons/faAngleUp'
 import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft'
 import {faArrowRight} from '@fortawesome/free-solid-svg-icons/faArrowRight'
 import {faArrowUp} from '@fortawesome/free-solid-svg-icons/faArrowUp'
+import {faArrowDown} from '@fortawesome/free-solid-svg-icons/faArrowDown'
 import {faArrowRightFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowRightFromBracket'
 import {faArrowUpFromBracket} from '@fortawesome/free-solid-svg-icons/faArrowUpFromBracket'
 import {faArrowUpRightFromSquare} from '@fortawesome/free-solid-svg-icons/faArrowUpRightFromSquare'
@@ -87,6 +88,7 @@ export function setup() {
     faArrowLeft,
     faArrowRight,
     faArrowUp,
+    faArrowDown,
     faArrowRightFromBracket,
     faArrowUpFromBracket,
     faArrowUpRightFromSquare,
diff --git a/src/view/screens/CustomFeed.tsx b/src/view/screens/CustomFeed.tsx
index 5644c16e0..63cbfcca8 100644
--- a/src/view/screens/CustomFeed.tsx
+++ b/src/view/screens/CustomFeed.tsx
@@ -38,8 +38,6 @@ export const CustomFeed = withAuthRequired(
       return feed
     }, [rootStore, uri])
 
-    console.log(currentFeed?.data.creator)
-
     const _ListHeaderComponent = () => {
       return (
         <View style={[styles.headerContainer]}>
diff --git a/src/view/screens/PinnedFeeds.tsx b/src/view/screens/PinnedFeeds.tsx
index f87f8d284..ac901ba71 100644
--- a/src/view/screens/PinnedFeeds.tsx
+++ b/src/view/screens/PinnedFeeds.tsx
@@ -5,6 +5,7 @@ import {
   View,
   ActivityIndicator,
   Pressable,
+  TouchableOpacity,
 } from 'react-native'
 import {useFocusEffect} from '@react-navigation/native'
 import {NativeStackScreenProps} from '@react-navigation/native-stack'
@@ -17,7 +18,7 @@ import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {ViewHeader} from 'view/com/util/ViewHeader'
 import {CenteredView} from 'view/com/util/Views'
 import {Text} from 'view/com/util/text/Text'
-import {isDesktopWeb} from 'platform/detection'
+import {isDesktopWeb, isWeb} from 'platform/detection'
 import {s} from 'lib/styles'
 import DraggableFlatList, {
   ShadowDecorator,
@@ -25,6 +26,7 @@ import DraggableFlatList, {
 } from 'react-native-draggable-flatlist'
 import {SavedFeedItem} from 'view/com/algos/SavedFeedItem'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {AlgoItemModel} from 'state/models/feeds/algo/algo-item'
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'PinnedFeeds'>
 
@@ -73,7 +75,7 @@ export const PinnedFeeds = withAuthRequired(
         <ViewHeader title="Arrange Pinned Feeds" showOnDesktop />
         <DraggableFlatList
           containerStyle={[!isDesktopWeb && s.flex1]}
-          data={savedFeeds.pinned}
+          data={[...savedFeeds.pinned]} // make a copy so this FlatList re-renders when pinned changes
           keyExtractor={item => item.data.uri}
           refreshing={savedFeeds.isRefreshing}
           refreshControl={
@@ -84,23 +86,7 @@ export const PinnedFeeds = withAuthRequired(
               titleColor={pal.colors.text}
             />
           }
-          renderItem={({item, drag}) => (
-            <ScaleDecorator>
-              <ShadowDecorator>
-                <Pressable
-                  accessibilityRole="button"
-                  onLongPress={drag}
-                  style={styles.itemContainer}>
-                  <FontAwesomeIcon
-                    icon="bars"
-                    size={20}
-                    style={[styles.icon, pal.text]}
-                  />
-                  <SavedFeedItem item={item} savedFeeds={savedFeeds} />
-                </Pressable>
-              </ShadowDecorator>
-            </ScaleDecorator>
-          )}
+          renderItem={({item, drag}) => <PinnedItem item={item} drag={drag} />}
           initialNumToRender={10}
           ListFooterComponent={_ListFooterComponent}
           ListEmptyComponent={_ListEmptyComponent}
@@ -114,6 +100,58 @@ export const PinnedFeeds = withAuthRequired(
   }),
 )
 
+const PinnedItem = observer(
+  ({item, drag}: {item: AlgoItemModel; drag: () => void}) => {
+    const pal = usePalette('default')
+    const rootStore = useStores()
+    const savedFeeds = useMemo(() => rootStore.me.savedFeeds, [rootStore])
+    return (
+      <ScaleDecorator>
+        <ShadowDecorator>
+          <Pressable
+            accessibilityRole="button"
+            onLongPress={drag}
+            style={styles.itemContainer}>
+            {isWeb ? (
+              <View style={styles.webArrowButtonsContainer}>
+                <TouchableOpacity
+                  accessibilityRole="button"
+                  onPress={() => {
+                    savedFeeds.movePinnedItem(item, 'up')
+                  }}>
+                  <FontAwesomeIcon
+                    icon="arrow-up"
+                    size={20}
+                    style={[styles.icon, pal.text, styles.webArrowUpButton]}
+                  />
+                </TouchableOpacity>
+                <TouchableOpacity
+                  accessibilityRole="button"
+                  onPress={() => {
+                    savedFeeds.movePinnedItem(item, 'down')
+                  }}>
+                  <FontAwesomeIcon
+                    icon="arrow-down"
+                    size={20}
+                    style={[styles.icon, pal.text]}
+                  />
+                </TouchableOpacity>
+              </View>
+            ) : (
+              <FontAwesomeIcon
+                icon="bars"
+                size={20}
+                style={[styles.icon, pal.text]}
+              />
+            )}
+            <SavedFeedItem item={item} savedFeeds={savedFeeds} />
+          </Pressable>
+        </ShadowDecorator>
+      </ScaleDecorator>
+    )
+  },
+)
+
 const styles = StyleSheet.create({
   footer: {
     paddingVertical: 20,
@@ -135,4 +173,9 @@ const styles = StyleSheet.create({
     borderTopWidth: 0,
   },
   icon: {marginRight: 10},
+  webArrowButtonsContainer: {
+    flexDirection: 'column',
+    justifyContent: 'space-around',
+  },
+  webArrowUpButton: {marginBottom: 10},
 })