diff --git a/package.json b/package.json index 01528bf08b..24ddbeb182 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 881684ee6a..667bc03a35 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 8f8cdc6c9d..0f62782880 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 +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 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 ( - - - You don't have any saved feeds. - - - ) - }, [pal, isMobile]) - - const renderListFooterComponent = useCallback(() => { - return ( - <> - - - - - Discover new feeds - - + return ( + + + + + + Pinned Feeds + + {savedFeeds.hasLoaded ? ( + !savedFeeds.pinned.length ? ( + + + You don't have any pinned feeds. + + + ) : ( + savedFeeds.pinned.map(feed => ( + + )) + ) + ) : ( + + )} + + + Saved Feeds + + + {savedFeeds.hasLoaded ? ( + !savedFeeds.unpinned.length ? ( + + + You don't have any saved feeds. + + + ) : ( + savedFeeds.unpinned.map(feed => ( + + )) + ) + ) : ( + + )} + Feeds are custom algorithms that users build with a little coding @@ -99,60 +144,8 @@ export const SavedFeeds = withAuthRequired( for more information. - {savedFeeds.isLoading && } - - ) - }, [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 ( - - - item.uri} - refreshing={savedFeeds.isRefreshing} - refreshControl={ - - } - renderItem={({item, drag}) => ( - - )} - getItemLayout={(data, index) => ({ - length: 77, - offset: 77 * index, - index, - })} - initialNumToRender={10} - ListFooterComponent={renderListFooterComponent} - ListEmptyComponent={renderListEmptyComponent} - extraData={savedFeeds.isLoading} - onDragEnd={onDragEnd} - /> + + ) }), @@ -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 ( - - - - {isPinned && isWeb ? ( - - - - - - - - - ) : isPinned ? ( - - ) : null} - + + {isPinned ? ( + + onPress={onPressUp} + hitSlop={HITSLOP_TOP}> - - - + + + + + ) : null} + + + + + ) }) @@ -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 1611786f57..b42475ac06 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"