about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-11-02 12:09:57 -0700
committerGitHub <noreply@github.com>2023-11-02 12:09:57 -0700
commit0f4bfcb05d4d902209126cca216eac31d49c8f80 (patch)
tree51de199207ed0d029f76aaf1125058bda1fc40d7
parent0e8723c3bb9566542f009994484b30c3da72ede7 (diff)
downloadvoidsky-0f4bfcb05d4d902209126cca216eac31d49c8f80.tar.zst
Replace draglist due to upstream errors (#1795)
* Replace draggable flatlist with simple sort buttons

* Remove react-native-draggable-flatlist dep

* Fix hitslops

* Update lockfile

* Remove bad flex:1
-rw-r--r--package.json1
-rw-r--r--src/state/models/ui/saved-feeds.ts10
-rw-r--r--src/view/screens/SavedFeeds.tsx285
-rw-r--r--yarn.lock9
4 files changed, 133 insertions, 172 deletions
diff --git a/package.json b/package.json
index 01528bf08..24ddbeb18 100644
--- a/package.json
+++ b/package.json
@@ -128,7 +128,6 @@
     "react-dom": "^18.2.0",
     "react-native": "0.72.5",
     "react-native-appstate-hook": "^1.0.6",
-    "react-native-draggable-flatlist": "^4.0.1",
     "react-native-drawer-layout": "^3.2.0",
     "react-native-fs": "^2.20.0",
     "react-native-gesture-handler": "^2.12.1",
diff --git a/src/state/models/ui/saved-feeds.ts b/src/state/models/ui/saved-feeds.ts
index 881684ee6..667bc03a3 100644
--- a/src/state/models/ui/saved-feeds.ts
+++ b/src/state/models/ui/saved-feeds.ts
@@ -95,19 +95,15 @@ export class SavedFeedsModel {
       return
     }
     if (direction === 'up' && index !== 0) {
-      const temp = pinned[index]
-      pinned[index] = pinned[index - 1]
-      pinned[index - 1] = temp
+      ;[pinned[index], pinned[index - 1]] = [pinned[index - 1], pinned[index]]
     } else if (direction === 'down' && index < pinned.length - 1) {
-      const temp = pinned[index]
-      pinned[index] = pinned[index + 1]
-      pinned[index + 1] = temp
+      ;[pinned[index], pinned[index + 1]] = [pinned[index + 1], pinned[index]]
     }
+    this._updatePinSortOrder(pinned.concat(this.unpinned.map(f => f.uri)))
     await this.rootStore.preferences.setSavedFeeds(
       this.rootStore.preferences.savedFeeds,
       pinned,
     )
-    this._updatePinSortOrder()
     track('CustomFeed:Reorder', {
       name: item.displayName,
       uri: item.uri,
diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx
index 8f8cdc6c9..0f6278288 100644
--- a/src/view/screens/SavedFeeds.tsx
+++ b/src/view/screens/SavedFeeds.tsx
@@ -1,6 +1,5 @@
 import React, {useCallback, useMemo} from 'react'
 import {
-  RefreshControl,
   StyleSheet,
   View,
   ActivityIndicator,
@@ -18,23 +17,30 @@ import {SavedFeedsModel} from 'state/models/ui/saved-feeds'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {ViewHeader} from 'view/com/util/ViewHeader'
-import {CenteredView} from 'view/com/util/Views'
+import {ScrollView, CenteredView} from 'view/com/util/Views'
 import {Text} from 'view/com/util/text/Text'
-import {isWeb} from 'platform/detection'
 import {s, colors} from 'lib/styles'
-import DraggableFlatList, {
-  ShadowDecorator,
-  ScaleDecorator,
-} from 'react-native-draggable-flatlist'
 import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
 import {FeedSourceModel} from 'state/models/content/feed-source'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import * as Toast from 'view/com/util/Toast'
 import {Haptics} from 'lib/haptics'
-import {Link, TextLink} from 'view/com/util/Link'
+import {TextLink} from 'view/com/util/Link'
 
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
+const HITSLOP_TOP = {
+  top: 20,
+  left: 20,
+  bottom: 5,
+  right: 20,
+}
+const HITSLOP_BOTTOM = {
+  top: 5,
+  left: 20,
+  bottom: 20,
+  right: 20,
+}
 
+type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
 export const SavedFeeds = withAuthRequired(
   observer(function SavedFeedsImpl({}: Props) {
     const pal = usePalette('default')
@@ -55,37 +61,76 @@ export const SavedFeeds = withAuthRequired(
       }, [screen, store, savedFeeds]),
     )
 
-    const renderListEmptyComponent = useCallback(() => {
-      return (
-        <View
-          style={[
-            pal.border,
-            isMobile && s.flex1,
-            pal.viewLight,
-            styles.empty,
-          ]}>
-          <Text type="lg" style={[pal.text]}>
-            You don't have any saved feeds.
-          </Text>
-        </View>
-      )
-    }, [pal, isMobile])
-
-    const renderListFooterComponent = useCallback(() => {
-      return (
-        <>
-          <View style={[styles.footerLinks, pal.border]}>
-            <Link style={styles.footerLink} href="/feeds">
-              <FontAwesomeIcon
-                icon="search"
-                size={18}
-                color={pal.colors.icon}
-              />
-              <Text type="lg-medium" style={pal.textLight}>
-                Discover new feeds
-              </Text>
-            </Link>
+    return (
+      <CenteredView
+        style={[
+          s.hContentRegion,
+          pal.border,
+          isTabletOrDesktop && styles.desktopContainer,
+        ]}>
+        <ViewHeader title="Edit My Feeds" showOnDesktop showBorder />
+        <ScrollView style={s.flex1}>
+          <View style={[pal.text, pal.border, styles.title]}>
+            <Text type="title" style={pal.text}>
+              Pinned Feeds
+            </Text>
           </View>
+          {savedFeeds.hasLoaded ? (
+            !savedFeeds.pinned.length ? (
+              <View
+                style={[
+                  pal.border,
+                  isMobile && s.flex1,
+                  pal.viewLight,
+                  styles.empty,
+                ]}>
+                <Text type="lg" style={[pal.text]}>
+                  You don't have any pinned feeds.
+                </Text>
+              </View>
+            ) : (
+              savedFeeds.pinned.map(feed => (
+                <ListItem
+                  key={feed._reactKey}
+                  savedFeeds={savedFeeds}
+                  item={feed}
+                />
+              ))
+            )
+          ) : (
+            <ActivityIndicator style={{marginTop: 20}} />
+          )}
+          <View style={[pal.text, pal.border, styles.title]}>
+            <Text type="title" style={pal.text}>
+              Saved Feeds
+            </Text>
+          </View>
+          {savedFeeds.hasLoaded ? (
+            !savedFeeds.unpinned.length ? (
+              <View
+                style={[
+                  pal.border,
+                  isMobile && s.flex1,
+                  pal.viewLight,
+                  styles.empty,
+                ]}>
+                <Text type="lg" style={[pal.text]}>
+                  You don't have any saved feeds.
+                </Text>
+              </View>
+            ) : (
+              savedFeeds.unpinned.map(feed => (
+                <ListItem
+                  key={feed._reactKey}
+                  savedFeeds={savedFeeds}
+                  item={feed}
+                />
+              ))
+            )
+          ) : (
+            <ActivityIndicator style={{marginTop: 20}} />
+          )}
+
           <View style={styles.footerText}>
             <Text type="sm" style={pal.textLight}>
               Feeds are custom algorithms that users build with a little coding
@@ -99,60 +144,8 @@ export const SavedFeeds = withAuthRequired(
               for more information.
             </Text>
           </View>
-          {savedFeeds.isLoading && <ActivityIndicator />}
-        </>
-      )
-    }, [pal, savedFeeds.isLoading])
-
-    const onRefresh = useCallback(() => savedFeeds.refresh(), [savedFeeds])
-
-    const onDragEnd = useCallback(
-      async ({data}: {data: FeedSourceModel[]}) => {
-        try {
-          await savedFeeds.reorderPinnedFeeds(data)
-        } catch (e) {
-          Toast.show('There was an issue contacting the server')
-          store.log.error('Failed to save pinned feed order', {e})
-        }
-      },
-      [savedFeeds, store],
-    )
-
-    return (
-      <CenteredView
-        style={[
-          s.hContentRegion,
-          pal.border,
-          isTabletOrDesktop && styles.desktopContainer,
-        ]}>
-        <ViewHeader title="Edit My Feeds" showOnDesktop showBorder />
-        <DraggableFlatList
-          containerStyle={[isTabletOrDesktop ? s.hContentRegion : s.flex1]}
-          data={savedFeeds.pinned.concat(savedFeeds.unpinned)}
-          keyExtractor={item => item.uri}
-          refreshing={savedFeeds.isRefreshing}
-          refreshControl={
-            <RefreshControl
-              refreshing={savedFeeds.isRefreshing}
-              onRefresh={onRefresh}
-              tintColor={pal.colors.text}
-              titleColor={pal.colors.text}
-            />
-          }
-          renderItem={({item, drag}) => (
-            <ListItem savedFeeds={savedFeeds} item={item} drag={drag} />
-          )}
-          getItemLayout={(data, index) => ({
-            length: 77,
-            offset: 77 * index,
-            index,
-          })}
-          initialNumToRender={10}
-          ListFooterComponent={renderListFooterComponent}
-          ListEmptyComponent={renderListEmptyComponent}
-          extraData={savedFeeds.isLoading}
-          onDragEnd={onDragEnd}
-        />
+          <View style={{height: 100}} />
+        </ScrollView>
       </CenteredView>
     )
   }),
@@ -161,11 +154,9 @@ export const SavedFeeds = withAuthRequired(
 const ListItem = observer(function ListItemImpl({
   savedFeeds,
   item,
-  drag,
 }: {
   savedFeeds: SavedFeedsModel
   item: FeedSourceModel
-  drag: () => void
 }) {
   const pal = usePalette('default')
   const store = useStores()
@@ -196,59 +187,46 @@ const ListItem = observer(function ListItemImpl({
   )
 
   return (
-    <ScaleDecorator>
-      <ShadowDecorator>
-        <Pressable
-          accessibilityRole="button"
-          onLongPress={isPinned ? drag : undefined}
-          delayLongPress={200}
-          style={[styles.itemContainer, pal.border]}>
-          {isPinned && isWeb ? (
-            <View style={styles.webArrowButtonsContainer}>
-              <TouchableOpacity accessibilityRole="button" onPress={onPressUp}>
-                <FontAwesomeIcon
-                  icon="arrow-up"
-                  size={12}
-                  style={[pal.text, styles.webArrowUpButton]}
-                />
-              </TouchableOpacity>
-              <TouchableOpacity
-                accessibilityRole="button"
-                onPress={onPressDown}>
-                <FontAwesomeIcon
-                  icon="arrow-down"
-                  size={12}
-                  style={[pal.text]}
-                />
-              </TouchableOpacity>
-            </View>
-          ) : isPinned ? (
-            <FontAwesomeIcon
-              icon="bars"
-              size={20}
-              color={pal.colors.text}
-              style={s.ml20}
-            />
-          ) : null}
-          <FeedSourceCard
-            key={item.uri}
-            item={item}
-            showSaveBtn
-            style={styles.noBorder}
-          />
+    <Pressable
+      accessibilityRole="button"
+      style={[styles.itemContainer, pal.border]}>
+      {isPinned ? (
+        <View style={styles.webArrowButtonsContainer}>
           <TouchableOpacity
             accessibilityRole="button"
-            hitSlop={10}
-            onPress={onTogglePinned}>
+            onPress={onPressUp}
+            hitSlop={HITSLOP_TOP}>
             <FontAwesomeIcon
-              icon="thumb-tack"
-              size={20}
-              color={isPinned ? colors.blue3 : pal.colors.icon}
+              icon="arrow-up"
+              size={12}
+              style={[pal.text, styles.webArrowUpButton]}
             />
           </TouchableOpacity>
-        </Pressable>
-      </ShadowDecorator>
-    </ScaleDecorator>
+          <TouchableOpacity
+            accessibilityRole="button"
+            onPress={onPressDown}
+            hitSlop={HITSLOP_BOTTOM}>
+            <FontAwesomeIcon icon="arrow-down" size={12} style={[pal.text]} />
+          </TouchableOpacity>
+        </View>
+      ) : null}
+      <FeedSourceCard
+        key={item.uri}
+        item={item}
+        showSaveBtn
+        style={styles.noBorder}
+      />
+      <TouchableOpacity
+        accessibilityRole="button"
+        hitSlop={10}
+        onPress={onTogglePinned}>
+        <FontAwesomeIcon
+          icon="thumb-tack"
+          size={20}
+          color={isPinned ? colors.blue3 : pal.colors.icon}
+        />
+      </TouchableOpacity>
+    </Pressable>
   )
 })
 
@@ -262,12 +240,17 @@ const styles = StyleSheet.create({
   empty: {
     paddingHorizontal: 20,
     paddingVertical: 20,
-    borderRadius: 16,
-    marginHorizontal: 24,
+    borderRadius: 8,
+    marginHorizontal: 10,
     marginTop: 10,
   },
+  title: {
+    paddingHorizontal: 14,
+    paddingTop: 20,
+    paddingBottom: 10,
+    borderBottomWidth: 1,
+  },
   itemContainer: {
-    flex: 1,
     flexDirection: 'row',
     alignItems: 'center',
     borderBottomWidth: 1,
@@ -289,14 +272,4 @@ const styles = StyleSheet.create({
     paddingTop: 22,
     paddingBottom: 100,
   },
-  footerLinks: {
-    borderBottomWidth: 1,
-    borderTopWidth: 0,
-  },
-  footerLink: {
-    flexDirection: 'row',
-    paddingHorizontal: 26,
-    paddingVertical: 18,
-    gap: 18,
-  },
 })
diff --git a/yarn.lock b/yarn.lock
index 1611786f5..b42475ac0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1483,7 +1483,7 @@
     "@babel/plugin-transform-react-jsx-development" "^7.22.5"
     "@babel/plugin-transform-react-pure-annotations" "^7.22.5"
 
-"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.16.0", "@babel/preset-typescript@^7.16.7", "@babel/preset-typescript@^7.17.12":
+"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.16.0", "@babel/preset-typescript@^7.16.7":
   version "7.22.5"
   resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz#16367d8b01d640e9a507577ed4ee54e0101e51c8"
   integrity sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ==
@@ -15801,13 +15801,6 @@ react-native-dotenv@^3.3.1:
   dependencies:
     dotenv "^16.3.1"
 
-react-native-draggable-flatlist@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/react-native-draggable-flatlist/-/react-native-draggable-flatlist-4.0.1.tgz#2f027d387ba4b8f3eb0907340e32cb85e6460df2"
-  integrity sha512-ZO1QUTNx64KZfXGXeXcBfql67l38X7kBcJ3rxUVZzPHt5r035GnGzIC0F8rqSXp6zgnwgUYMfB6zQc5PKmPL9Q==
-  dependencies:
-    "@babel/preset-typescript" "^7.17.12"
-
 react-native-drawer-layout@^3.2.0:
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-3.2.1.tgz#eb626216181965e72de6d9377ca619fab40226f2"