Remove redundant feed-settings page

zio/stable
Paul Frazee 2023-05-17 22:04:01 -05:00
parent 177df36330
commit 998879d6d6
8 changed files with 97 additions and 293 deletions

View File

@ -55,9 +55,8 @@ import {CopyrightPolicyScreen} from './view/screens/CopyrightPolicy'
import {AppPasswords} from 'view/screens/AppPasswords'
import {ModerationMutedAccounts} from 'view/screens/ModerationMutedAccounts'
import {ModerationBlockedAccounts} from 'view/screens/ModerationBlockedAccounts'
import {SavedFeeds} from 'view/screens/SavedFeeds'
import {getRoutingInstrumentation} from 'lib/sentry'
import {SavedFeeds} from './view/screens/SavedFeeds'
import {PinnedFeeds} from 'view/screens/PinnedFeeds'
import {bskyTitle} from 'lib/strings/headings'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@ -189,7 +188,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
options={{title: title('App Passwords')}}
/>
<Stack.Screen name="SavedFeeds" component={SavedFeeds} />
<Stack.Screen name="PinnedFeeds" component={PinnedFeeds} />
</>
)
}

View File

@ -27,7 +27,6 @@ export type CommonNavigatorParams = {
CopyrightPolicy: undefined
AppPasswords: undefined
SavedFeeds: undefined
PinnedFeeds: undefined
}
export type BottomTabNavigatorParams = CommonNavigatorParams & {

View File

@ -21,7 +21,6 @@ export const router = new Router({
Log: '/sys/log',
AppPasswords: '/settings/app-passwords',
SavedFeeds: '/settings/saved-feeds',
PinnedFeeds: '/settings/pinned-feeds',
Support: '/support',
PrivacyPolicy: '/support/privacy',
TermsOfService: '/support/tos',

View File

@ -50,7 +50,7 @@ export const SavedFeeds = observer(
return (
<Link
style={[styles.footerLink, pal.border]}
href="/settings/pinned-feeds">
href="/settings/saved-feeds">
<FontAwesomeIcon icon="cog" size={18} color={pal.colors.icon} />
<Text type="lg-medium" style={pal.textLight}>
Settings

View File

@ -60,14 +60,17 @@ import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib'
import {faPenToSquare} from '@fortawesome/free-solid-svg-icons/faPenToSquare'
import {faPlus} from '@fortawesome/free-solid-svg-icons/faPlus'
import {faQuoteLeft} from '@fortawesome/free-solid-svg-icons/faQuoteLeft'
import {faReply} from '@fortawesome/free-solid-svg-icons/faReply'
import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet'
import {faRss} from '@fortawesome/free-solid-svg-icons/faRss'
import {faSatelliteDish} from '@fortawesome/free-solid-svg-icons/faSatelliteDish'
import {faShare} from '@fortawesome/free-solid-svg-icons/faShare'
import {faShareFromSquare} from '@fortawesome/free-solid-svg-icons/faShareFromSquare'
import {faShield} from '@fortawesome/free-solid-svg-icons/faShield'
import {faSquarePlus} from '@fortawesome/free-regular-svg-icons/faSquarePlus'
import {faSignal} from '@fortawesome/free-solid-svg-icons/faSignal'
import {faReply} from '@fortawesome/free-solid-svg-icons/faReply'
import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet'
import {faRss} from '@fortawesome/free-solid-svg-icons/faRss'
import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket'
import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan'
import {faUser} from '@fortawesome/free-regular-svg-icons/faUser'
import {faUsers} from '@fortawesome/free-solid-svg-icons/faUsers'
import {faUserCheck} from '@fortawesome/free-solid-svg-icons/faUserCheck'
@ -75,8 +78,6 @@ import {faUserSlash} from '@fortawesome/free-solid-svg-icons/faUserSlash'
import {faUserPlus} from '@fortawesome/free-solid-svg-icons/faUserPlus'
import {faUserXmark} from '@fortawesome/free-solid-svg-icons/faUserXmark'
import {faUsersSlash} from '@fortawesome/free-solid-svg-icons/faUsersSlash'
import {faTicket} from '@fortawesome/free-solid-svg-icons/faTicket'
import {faTrashCan} from '@fortawesome/free-regular-svg-icons/faTrashCan'
import {faX} from '@fortawesome/free-solid-svg-icons/faX'
import {faXmark} from '@fortawesome/free-solid-svg-icons/faXmark'
import {faPlay} from '@fortawesome/free-solid-svg-icons/faPlay'
@ -148,6 +149,7 @@ export function setup() {
faReply,
faRetweet,
faRss,
faSatelliteDish,
faShare,
faShareFromSquare,
faShield,

View File

@ -1,179 +0,0 @@
import React, {useCallback, useMemo} from 'react'
import {
RefreshControl,
StyleSheet,
View,
ActivityIndicator,
Pressable,
TouchableOpacity,
} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {useAnalytics} from 'lib/analytics'
import {usePalette} from 'lib/hooks/usePalette'
import {CommonNavigatorParams} from 'lib/routes/types'
import {observer} from 'mobx-react-lite'
import {useStores} from 'state/index'
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, isWeb} from 'platform/detection'
import {s} from 'lib/styles'
import DraggableFlatList, {
ShadowDecorator,
ScaleDecorator,
} from 'react-native-draggable-flatlist'
import {SavedFeedItem} from 'view/com/feeds/SavedFeedItem'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {CustomFeedModel} from 'state/models/feeds/custom-feed'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PinnedFeeds'>
export const PinnedFeeds = withAuthRequired(
observer(({}: Props) => {
// hooks for global items
const pal = usePalette('default')
const rootStore = useStores()
const {screen} = useAnalytics()
// hooks for local
const savedFeeds = useMemo(() => rootStore.me.savedFeeds, [rootStore])
useFocusEffect(
useCallback(() => {
screen('SavedFeeds')
rootStore.shell.setMinimalShellMode(false)
savedFeeds.refresh()
}, [screen, rootStore, savedFeeds]),
)
const _ListEmptyComponent = () => {
return (
<View
style={[
pal.border,
!isDesktopWeb && s.flex1,
pal.viewLight,
styles.empty,
]}>
<Text type="lg" style={[pal.text]}>
You don't have any pinned feeds. To pin a feed, go back to the Saved
Feeds screen and click the pin icon!
</Text>
</View>
)
}
const _ListFooterComponent = () => {
return (
<View style={styles.footer}>
{savedFeeds.isLoading && <ActivityIndicator />}
</View>
)
}
return (
<CenteredView style={[s.flex1]}>
<ViewHeader title="Edit My Feeds" showOnDesktop />
<DraggableFlatList
containerStyle={[!isDesktopWeb && s.flex1]}
data={[...savedFeeds.pinned, ...savedFeeds.unpinned]} // make a copy so this FlatList re-renders when pinned changes
keyExtractor={item => item.data.uri}
refreshing={savedFeeds.isRefreshing}
refreshControl={
<RefreshControl
refreshing={savedFeeds.isRefreshing}
onRefresh={() => savedFeeds.refresh()}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
renderItem={({item, drag}) => <ListItem item={item} drag={drag} />}
initialNumToRender={10}
ListFooterComponent={_ListFooterComponent}
ListEmptyComponent={_ListEmptyComponent}
extraData={savedFeeds.isLoading}
onDragEnd={({data}) => savedFeeds.reorderPinnedFeeds(data)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
</CenteredView>
)
}),
)
const ListItem = observer(
({item, drag}: {item: CustomFeedModel; drag: () => void}) => {
const pal = usePalette('default')
const rootStore = useStores()
const savedFeeds = useMemo(() => rootStore.me.savedFeeds, [rootStore])
const isPinned = savedFeeds.isPinned(item)
return (
<ScaleDecorator>
<ShadowDecorator>
<Pressable
accessibilityRole="button"
onLongPress={isPinned ? drag : undefined}
style={[styles.itemContainer, pal.border]}>
{isPinned && isWeb ? (
<View style={styles.webArrowButtonsContainer}>
<TouchableOpacity
accessibilityRole="button"
onPress={() => {
savedFeeds.movePinnedItem(item, 'up')
}}>
<FontAwesomeIcon
icon="arrow-up"
size={20}
style={[s.mr10, pal.text, styles.webArrowUpButton]}
/>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="button"
onPress={() => {
savedFeeds.movePinnedItem(item, 'down')
}}>
<FontAwesomeIcon
icon="arrow-down"
size={20}
style={[s.mr10, pal.text]}
/>
</TouchableOpacity>
</View>
) : isPinned ? (
<FontAwesomeIcon
icon="bars"
size={20}
color={pal.colors.text}
style={s.ml20}
/>
) : null}
<SavedFeedItem item={item} savedFeeds={savedFeeds} showSaveBtn />
</Pressable>
</ShadowDecorator>
</ScaleDecorator>
)
},
)
const styles = StyleSheet.create({
footer: {
paddingVertical: 20,
},
empty: {
paddingHorizontal: 20,
paddingVertical: 20,
borderRadius: 16,
marginHorizontal: 24,
marginTop: 10,
},
itemContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
borderTopWidth: 1,
},
webArrowButtonsContainer: {
flexDirection: 'column',
justifyContent: 'space-around',
},
webArrowUpButton: {marginBottom: 10},
})

View File

@ -4,9 +4,8 @@ import {
StyleSheet,
View,
ActivityIndicator,
FlatList,
Pressable,
TouchableOpacity,
ScrollView,
} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
@ -21,16 +20,18 @@ import {CenteredView} from 'view/com/util/Views'
import {Text} from 'view/com/util/text/Text'
import {isDesktopWeb, isWeb} from 'platform/detection'
import {s} from 'lib/styles'
import {SavedFeedsModel} from 'state/models/ui/saved-feeds'
import {Link} from 'view/com/util/Link'
import {UserAvatar} from 'view/com/util/UserAvatar'
import DraggableFlatList, {
ShadowDecorator,
ScaleDecorator,
} from 'react-native-draggable-flatlist'
import {SavedFeedItem} from 'view/com/feeds/SavedFeedItem'
import {AtUri} from '@atproto/api'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {CustomFeedModel} from 'state/models/feeds/custom-feed'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
export const SavedFeeds = withAuthRequired(
observer(({navigation}: Props) => {
observer(({}: Props) => {
// hooks for global items
const pal = usePalette('default')
const rootStore = useStores()
@ -55,8 +56,8 @@ export const SavedFeeds = withAuthRequired(
styles.empty,
]}>
<Text type="lg" style={[pal.text]}>
You don't have any saved feeds. To save a feed, click the save
button when a custom feed or algorithm shows up.
You don't have any pinned feeds. To pin a feed, go back to the Saved
Feeds screen and click the pin icon!
</Text>
</View>
)
@ -71,10 +72,10 @@ export const SavedFeeds = withAuthRequired(
return (
<CenteredView style={[s.flex1]}>
<ViewHeader title="Saved Feeds" showOnDesktop />
<FlatList
style={[!isDesktopWeb && s.flex1]}
data={savedFeeds.feeds}
<ViewHeader title="Edit My Feeds" showOnDesktop />
<DraggableFlatList
containerStyle={[!isDesktopWeb && s.flex1]}
data={[...savedFeeds.pinned, ...savedFeeds.unpinned]} // make a copy so this FlatList re-renders when pinned changes
keyExtractor={item => item.data.uri}
refreshing={savedFeeds.isRefreshing}
refreshControl={
@ -85,19 +86,12 @@ export const SavedFeeds = withAuthRequired(
titleColor={pal.colors.text}
/>
}
renderItem={({item}) => (
<SavedFeedItem item={item} savedFeeds={savedFeeds} />
)}
renderItem={({item, drag}) => <ListItem item={item} drag={drag} />}
initialNumToRender={10}
ListHeaderComponent={() => (
<ListHeaderComponent
savedFeeds={savedFeeds}
navigation={navigation}
/>
)}
ListFooterComponent={_ListFooterComponent}
ListEmptyComponent={_ListEmptyComponent}
extraData={savedFeeds.isLoading}
onDragEnd={({data}) => savedFeeds.reorderPinnedFeeds(data)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
@ -106,64 +100,56 @@ export const SavedFeeds = withAuthRequired(
}),
)
const ListHeaderComponent = observer(
({
savedFeeds,
navigation,
}: {
savedFeeds: SavedFeedsModel
navigation: Props['navigation']
}) => {
const ListItem = observer(
({item, drag}: {item: CustomFeedModel; drag: () => void}) => {
const pal = usePalette('default')
const rootStore = useStores()
const savedFeeds = useMemo(() => rootStore.me.savedFeeds, [rootStore])
const isPinned = savedFeeds.isPinned(item)
return (
<View style={styles.headerContainer}>
{savedFeeds.pinned.length > 0 ? (
<View style={styles.pinnedContainer}>
<View style={styles.pinnedHeader}>
<Text type="lg-bold" style={[pal.text]}>
Pinned Feeds
</Text>
<Link href="/settings/pinned-feeds">
<Text style={[styles.editPinned, pal.text]}>Edit</Text>
</Link>
</View>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={isWeb}>
{savedFeeds.pinned.map(item => {
return (
<TouchableOpacity
key={item.data.uri}
accessibilityRole="button"
onPress={() => {
navigation.navigate('ProfileCustomFeed', {
name: item.data.creator.did,
rkey: new AtUri(item.data.uri).rkey,
})
}}
style={styles.pinnedItem}>
<UserAvatar
type="algo"
avatar={item.data.avatar}
size={80}
/>
<Text
type="sm-medium"
numberOfLines={1}
style={[pal.text, styles.pinnedItemName]}>
{item.data.displayName ??
`${item.data.creator.displayName}'s feed`}
</Text>
</TouchableOpacity>
)
})}
</ScrollView>
</View>
) : null}
<Text type="lg-bold">All Saved Feeds</Text>
</View>
<ScaleDecorator>
<ShadowDecorator>
<Pressable
accessibilityRole="button"
onLongPress={isPinned ? drag : undefined}
style={[styles.itemContainer, pal.border]}>
{isPinned && isWeb ? (
<View style={styles.webArrowButtonsContainer}>
<TouchableOpacity
accessibilityRole="button"
onPress={() => {
savedFeeds.movePinnedItem(item, 'up')
}}>
<FontAwesomeIcon
icon="arrow-up"
size={20}
style={[s.mr10, pal.text, styles.webArrowUpButton]}
/>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="button"
onPress={() => {
savedFeeds.movePinnedItem(item, 'down')
}}>
<FontAwesomeIcon
icon="arrow-down"
size={20}
style={[s.mr10, pal.text]}
/>
</TouchableOpacity>
</View>
) : isPinned ? (
<FontAwesomeIcon
icon="bars"
size={20}
color={pal.colors.text}
style={s.ml20}
/>
) : null}
<SavedFeedItem item={item} savedFeeds={savedFeeds} showSaveBtn />
</Pressable>
</ShadowDecorator>
</ScaleDecorator>
)
},
)
@ -179,15 +165,15 @@ const styles = StyleSheet.create({
marginHorizontal: 24,
marginTop: 10,
},
headerContainer: {paddingHorizontal: 18, paddingTop: 18},
pinnedContainer: {marginBottom: 18, gap: 18},
pinnedHeader: {flexDirection: 'row', justifyContent: 'space-between'},
pinnedItem: {
itemContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
marginRight: 18,
maxWidth: 100,
borderTopWidth: 1,
},
pinnedItemName: {marginTop: 8, textAlign: 'center'},
editPinned: {textDecorationLine: 'underline'},
webArrowButtonsContainer: {
flexDirection: 'column',
justifyContent: 'space-around',
},
webArrowUpButton: {marginBottom: 10},
})

View File

@ -284,23 +284,6 @@ export const SettingsScreen = withAuthRequired(
<View style={styles.spacer20} />
<Link
testID="bookmarkedAlgosBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
accessibilityHint="Custom Algorithms"
accessibilityLabel="Opens screen with all bookmarked custom algorithms"
href="/settings/saved-feeds">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="rss"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Custom Algorithms
</Text>
</Link>
<Text type="xl-bold" style={[pal.text, styles.heading]}>
Advanced
</Text>
@ -318,6 +301,22 @@ export const SettingsScreen = withAuthRequired(
App passwords
</Text>
</Link>
<Link
testID="savedFeedsBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}
accessibilityHint="Saved Feeds"
accessibilityLabel="Opens screen with all saved feeds"
href="/settings/saved-feeds">
<View style={[styles.iconContainer, pal.btn]}>
<FontAwesomeIcon
icon="satellite-dish"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
<Text type="lg" style={pal.text}>
Saved Feeds
</Text>
</Link>
<TouchableOpacity
testID="contentLanguagesBtn"
style={[styles.linkCard, pal.view, isSwitching && styles.dimmed]}