diff options
Diffstat (limited to 'src/view/screens')
-rw-r--r-- | src/view/screens/PreferencesHomeFeed.tsx | 143 | ||||
-rw-r--r-- | src/view/screens/PreferencesThreads.tsx | 154 | ||||
-rw-r--r-- | src/view/screens/SavedFeeds.tsx | 317 | ||||
-rw-r--r-- | src/view/screens/Settings.tsx | 9 |
4 files changed, 385 insertions, 238 deletions
diff --git a/src/view/screens/PreferencesHomeFeed.tsx b/src/view/screens/PreferencesHomeFeed.tsx index da99dc16f..7b240ded0 100644 --- a/src/view/screens/PreferencesHomeFeed.tsx +++ b/src/view/screens/PreferencesHomeFeed.tsx @@ -4,7 +4,6 @@ import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Slider} from '@miblanchard/react-native-slider' import {Text} from '../com/util/text/Text' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -16,21 +15,31 @@ import {CenteredView} from 'view/com/util/Views' import debounce from 'lodash.debounce' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import { + usePreferencesQuery, + useSetFeedViewPreferencesMutation, +} from '#/state/queries/preferences' -function RepliesThresholdInput({enabled}: {enabled: boolean}) { - const store = useStores() +function RepliesThresholdInput({ + enabled, + initialValue, +}: { + enabled: boolean + initialValue: number +}) { const pal = usePalette('default') - const [value, setValue] = useState( - store.preferences.homeFeed.hideRepliesByLikeCount, - ) + const [value, setValue] = useState(initialValue) + const {mutate: setFeedViewPref} = useSetFeedViewPreferencesMutation() const save = React.useMemo( () => debounce( threshold => - store.preferences.setHomeFeedHideRepliesByLikeCount(threshold), + setFeedViewPref({ + hideRepliesByLikeCount: threshold, + }), 500, ), // debouce for 500ms - [store], + [setFeedViewPref], ) return ( @@ -67,9 +76,15 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ navigation, }: Props) { const pal = usePalette('default') - const store = useStores() const {_} = useLingui() const {isTabletOrDesktop} = useWebMediaQueries() + const {data: preferences} = usePreferencesQuery() + const {mutate: setFeedViewPref, variables} = + useSetFeedViewPreferencesMutation() + + const showReplies = !( + variables?.hideReplies ?? preferences?.feedViewPrefs?.hideReplies + ) return ( <CenteredView @@ -105,17 +120,20 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ <ToggleButton testID="toggleRepliesBtn" type="default-light" - label={store.preferences.homeFeed.hideReplies ? 'No' : 'Yes'} - isSelected={!store.preferences.homeFeed.hideReplies} - onPress={store.preferences.toggleHomeFeedHideReplies} + label={showReplies ? 'Yes' : 'No'} + isSelected={showReplies} + onPress={() => + setFeedViewPref({ + hideReplies: !( + variables?.hideReplies ?? + preferences?.feedViewPrefs?.hideReplies + ), + }) + } /> </View> <View - style={[ - pal.viewLight, - styles.card, - store.preferences.homeFeed.hideReplies && styles.dimmed, - ]}> + style={[pal.viewLight, styles.card, !showReplies && styles.dimmed]}> <Text type="title-sm" style={[pal.text, s.pb5]}> <Trans>Reply Filters</Trans> </Text> @@ -128,10 +146,19 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ <ToggleButton type="default-light" label="Followed users only" - isSelected={store.preferences.homeFeed.hideRepliesByUnfollowed} + isSelected={Boolean( + variables?.hideRepliesByUnfollowed ?? + preferences?.feedViewPrefs?.hideRepliesByUnfollowed, + )} onPress={ - !store.preferences.homeFeed.hideReplies - ? store.preferences.toggleHomeFeedHideRepliesByUnfollowed + showReplies + ? () => + setFeedViewPref({ + hideRepliesByUnfollowed: !( + variables?.hideRepliesByUnfollowed ?? + preferences?.feedViewPrefs?.hideRepliesByUnfollowed + ), + }) : undefined } style={[s.mb10]} @@ -142,9 +169,12 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ feed. </Trans> </Text> - <RepliesThresholdInput - enabled={!store.preferences.homeFeed.hideReplies} - /> + {preferences && ( + <RepliesThresholdInput + enabled={showReplies} + initialValue={preferences.feedViewPrefs.hideRepliesByLikeCount} + /> + )} </View> <View style={[pal.viewLight, styles.card]}> @@ -158,9 +188,26 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ </Text> <ToggleButton type="default-light" - label={store.preferences.homeFeed.hideReposts ? 'No' : 'Yes'} - isSelected={!store.preferences.homeFeed.hideReposts} - onPress={store.preferences.toggleHomeFeedHideReposts} + label={ + variables?.hideReposts ?? + preferences?.feedViewPrefs?.hideReposts + ? 'No' + : 'Yes' + } + isSelected={ + !( + variables?.hideReposts ?? + preferences?.feedViewPrefs?.hideReposts + ) + } + onPress={() => + setFeedViewPref({ + hideReposts: !( + variables?.hideReposts ?? + preferences?.feedViewPrefs?.hideReposts + ), + }) + } /> </View> @@ -176,9 +223,26 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ </Text> <ToggleButton type="default-light" - label={store.preferences.homeFeed.hideQuotePosts ? 'No' : 'Yes'} - isSelected={!store.preferences.homeFeed.hideQuotePosts} - onPress={store.preferences.toggleHomeFeedHideQuotePosts} + label={ + variables?.hideQuotePosts ?? + preferences?.feedViewPrefs?.hideQuotePosts + ? 'No' + : 'Yes' + } + isSelected={ + !( + variables?.hideQuotePosts ?? + preferences?.feedViewPrefs?.hideQuotePosts + ) + } + onPress={() => + setFeedViewPref({ + hideQuotePosts: !( + variables?.hideQuotePosts ?? + preferences?.feedViewPrefs?.hideQuotePosts + ), + }) + } /> </View> @@ -196,10 +260,25 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ <ToggleButton type="default-light" label={ - store.preferences.homeFeed.lab_mergeFeedEnabled ? 'Yes' : 'No' + variables?.lab_mergeFeedEnabled ?? + preferences?.feedViewPrefs?.lab_mergeFeedEnabled + ? 'Yes' + : 'No' + } + isSelected={ + !!( + variables?.lab_mergeFeedEnabled ?? + preferences?.feedViewPrefs?.lab_mergeFeedEnabled + ) + } + onPress={() => + setFeedViewPref({ + lab_mergeFeedEnabled: !( + variables?.lab_mergeFeedEnabled ?? + preferences?.feedViewPrefs?.lab_mergeFeedEnabled + ), + }) } - isSelected={!!store.preferences.homeFeed.lab_mergeFeedEnabled} - onPress={store.preferences.toggleHomeFeedMergeFeedEnabled} /> </View> </View> diff --git a/src/view/screens/PreferencesThreads.tsx b/src/view/screens/PreferencesThreads.tsx index 8a2db13ce..2386f6445 100644 --- a/src/view/screens/PreferencesThreads.tsx +++ b/src/view/screens/PreferencesThreads.tsx @@ -1,9 +1,14 @@ import React from 'react' -import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native' +import { + ActivityIndicator, + ScrollView, + StyleSheet, + TouchableOpacity, + View, +} from 'react-native' import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Text} from '../com/util/text/Text' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -14,15 +19,30 @@ import {ViewHeader} from 'view/com/util/ViewHeader' import {CenteredView} from 'view/com/util/Views' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import { + usePreferencesQuery, + useSetThreadViewPreferencesMutation, +} from '#/state/queries/preferences' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'> export const PreferencesThreads = observer(function PreferencesThreadsImpl({ navigation, }: Props) { const pal = usePalette('default') - const store = useStores() const {_} = useLingui() const {isTabletOrDesktop} = useWebMediaQueries() + const {data: preferences} = usePreferencesQuery() + const {mutate: setThreadViewPrefs, variables} = + useSetThreadViewPreferencesMutation() + + const prioritizeFollowedUsers = Boolean( + variables?.prioritizeFollowedUsers ?? + preferences?.threadViewPrefs?.prioritizeFollowedUsers, + ) + const treeViewEnabled = Boolean( + variables?.lab_treeViewEnabled ?? + preferences?.threadViewPrefs?.lab_treeViewEnabled, + ) return ( <CenteredView @@ -44,71 +64,79 @@ export const PreferencesThreads = observer(function PreferencesThreadsImpl({ </Text> </View> - <ScrollView> - <View style={styles.cardsContainer}> - <View style={[pal.viewLight, styles.card]}> - <Text type="title-sm" style={[pal.text, s.pb5]}> - <Trans>Sort Replies</Trans> - </Text> - <Text style={[pal.text, s.pb10]}> - <Trans>Sort replies to the same post by:</Trans> - </Text> - <View style={[pal.view, {borderRadius: 8, paddingVertical: 6}]}> - <RadioGroup + {preferences ? ( + <ScrollView> + <View style={styles.cardsContainer}> + <View style={[pal.viewLight, styles.card]}> + <Text type="title-sm" style={[pal.text, s.pb5]}> + <Trans>Sort Replies</Trans> + </Text> + <Text style={[pal.text, s.pb10]}> + <Trans>Sort replies to the same post by:</Trans> + </Text> + <View style={[pal.view, {borderRadius: 8, paddingVertical: 6}]}> + <RadioGroup + type="default-light" + items={[ + {key: 'oldest', label: 'Oldest replies first'}, + {key: 'newest', label: 'Newest replies first'}, + {key: 'most-likes', label: 'Most-liked replies first'}, + {key: 'random', label: 'Random (aka "Poster\'s Roulette")'}, + ]} + onSelect={key => setThreadViewPrefs({sort: key})} + initialSelection={preferences?.threadViewPrefs?.sort} + /> + </View> + </View> + + <View style={[pal.viewLight, styles.card]}> + <Text type="title-sm" style={[pal.text, s.pb5]}> + <Trans>Prioritize Your Follows</Trans> + </Text> + <Text style={[pal.text, s.pb10]}> + <Trans> + Show replies by people you follow before all other replies. + </Trans> + </Text> + <ToggleButton type="default-light" - items={[ - {key: 'oldest', label: 'Oldest replies first'}, - {key: 'newest', label: 'Newest replies first'}, - {key: 'most-likes', label: 'Most-liked replies first'}, - {key: 'random', label: 'Random (aka "Poster\'s Roulette")'}, - ]} - onSelect={store.preferences.setThreadSort} - initialSelection={store.preferences.thread.sort} + label={prioritizeFollowedUsers ? 'Yes' : 'No'} + isSelected={prioritizeFollowedUsers} + onPress={() => + setThreadViewPrefs({ + prioritizeFollowedUsers: !prioritizeFollowedUsers, + }) + } /> </View> - </View> - <View style={[pal.viewLight, styles.card]}> - <Text type="title-sm" style={[pal.text, s.pb5]}> - <Trans>Prioritize Your Follows</Trans> - </Text> - <Text style={[pal.text, s.pb10]}> - <Trans> - Show replies by people you follow before all other replies. - </Trans> - </Text> - <ToggleButton - type="default-light" - label={ - store.preferences.thread.prioritizeFollowedUsers ? 'Yes' : 'No' - } - isSelected={store.preferences.thread.prioritizeFollowedUsers} - onPress={store.preferences.togglePrioritizedFollowedUsers} - /> - </View> - - <View style={[pal.viewLight, styles.card]}> - <Text type="title-sm" style={[pal.text, s.pb5]}> - <FontAwesomeIcon icon="flask" color={pal.colors.text} />{' '} - <Trans>Threaded Mode</Trans> - </Text> - <Text style={[pal.text, s.pb10]}> - <Trans> - Set this setting to "Yes" to show replies in a threaded view. - This is an experimental feature. - </Trans> - </Text> - <ToggleButton - type="default-light" - label={ - store.preferences.thread.lab_treeViewEnabled ? 'Yes' : 'No' - } - isSelected={!!store.preferences.thread.lab_treeViewEnabled} - onPress={store.preferences.toggleThreadTreeViewEnabled} - /> + <View style={[pal.viewLight, styles.card]}> + <Text type="title-sm" style={[pal.text, s.pb5]}> + <FontAwesomeIcon icon="flask" color={pal.colors.text} />{' '} + <Trans>Threaded Mode</Trans> + </Text> + <Text style={[pal.text, s.pb10]}> + <Trans> + Set this setting to "Yes" to show replies in a threaded view. + This is an experimental feature. + </Trans> + </Text> + <ToggleButton + type="default-light" + label={treeViewEnabled ? 'Yes' : 'No'} + isSelected={treeViewEnabled} + onPress={() => + setThreadViewPrefs({ + lab_treeViewEnabled: !treeViewEnabled, + }) + } + /> + </View> </View> - </View> - </ScrollView> + </ScrollView> + ) : ( + <ActivityIndicator /> + )} <View style={[ diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx index 487f56643..8ca2383d2 100644 --- a/src/view/screens/SavedFeeds.tsx +++ b/src/view/screens/SavedFeeds.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useMemo} from 'react' +import React from 'react' import { StyleSheet, View, @@ -8,26 +8,34 @@ import { } from 'react-native' import {useFocusEffect} from '@react-navigation/native' import {NativeStackScreenProps} from '@react-navigation/native-stack' +import {useQueryClient} from '@tanstack/react-query' + +import {track} from '#/lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/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 {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 {ScrollView, CenteredView} from 'view/com/util/Views' import {Text} from 'view/com/util/text/Text' import {s, colors} from 'lib/styles' -import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' -import {FeedSourceModel} from 'state/models/content/feed-source' +import {NewFeedSourceCard} from 'view/com/feeds/FeedSourceCard' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import * as Toast from 'view/com/util/Toast' import {Haptics} from 'lib/haptics' import {TextLink} from 'view/com/util/Link' import {logger} from '#/logger' import {useSetMinimalShellMode} from '#/state/shell' +import { + usePreferencesQuery, + usePinFeedMutation, + useUnpinFeedMutation, + useSetSaveFeedsMutation, + usePreferencesQueryKey, + UsePreferencesQueryResponse, +} from '#/state/queries/preferences' const HITSLOP_TOP = { top: 20, @@ -43,150 +51,178 @@ const HITSLOP_BOTTOM = { } type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'> -export const SavedFeeds = withAuthRequired( - observer(function SavedFeedsImpl({}: Props) { - const pal = usePalette('default') - const store = useStores() - const {isMobile, isTabletOrDesktop} = useWebMediaQueries() - const {screen} = useAnalytics() - const setMinimalShellMode = useSetMinimalShellMode() +export const SavedFeeds = withAuthRequired(function SavedFeedsImpl({}: Props) { + const pal = usePalette('default') + const {isMobile, isTabletOrDesktop} = useWebMediaQueries() + const {screen} = useAnalytics() + const setMinimalShellMode = useSetMinimalShellMode() + const {data: preferences} = usePreferencesQuery() - const savedFeeds = useMemo(() => { - const model = new SavedFeedsModel(store) - model.refresh() - return model - }, [store]) - useFocusEffect( - useCallback(() => { - screen('SavedFeeds') - setMinimalShellMode(false) - savedFeeds.refresh() - }, [screen, setMinimalShellMode, savedFeeds]), - ) + useFocusEffect( + React.useCallback(() => { + screen('SavedFeeds') + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), + ) - 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} - /> - )) - ) + 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> + {preferences?.feeds ? ( + !preferences.feeds.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> ) : ( - <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} - /> - )) - ) + preferences?.feeds?.pinned?.map(uri => ( + <ListItem key={uri} feedUri={uri} isPinned /> + )) + ) + ) : ( + <ActivityIndicator style={{marginTop: 20}} /> + )} + <View style={[pal.text, pal.border, styles.title]}> + <Text type="title" style={pal.text}> + Saved Feeds + </Text> + </View> + {preferences?.feeds ? ( + !preferences.feeds.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> ) : ( - <ActivityIndicator style={{marginTop: 20}} /> - )} + preferences.feeds.unpinned.map(uri => ( + <ListItem key={uri} feedUri={uri} isPinned={false} /> + )) + ) + ) : ( + <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 - expertise.{' '} - <TextLink - type="sm" - style={pal.link} - href="https://github.com/bluesky-social/feed-generator" - text="See this guide" - />{' '} - for more information. - </Text> - </View> - <View style={{height: 100}} /> - </ScrollView> - </CenteredView> - ) - }), -) + <View style={styles.footerText}> + <Text type="sm" style={pal.textLight}> + Feeds are custom algorithms that users build with a little coding + expertise.{' '} + <TextLink + type="sm" + style={pal.link} + href="https://github.com/bluesky-social/feed-generator" + text="See this guide" + />{' '} + for more information. + </Text> + </View> + <View style={{height: 100}} /> + </ScrollView> + </CenteredView> + ) +}) const ListItem = observer(function ListItemImpl({ - savedFeeds, - item, + feedUri, + isPinned, }: { - savedFeeds: SavedFeedsModel - item: FeedSourceModel + feedUri: string // uri + isPinned: boolean }) { const pal = usePalette('default') - const isPinned = item.isPinned + const queryClient = useQueryClient() + const {isPending: isPinPending, mutateAsync: pinFeed} = usePinFeedMutation() + const {isPending: isUnpinPending, mutateAsync: unpinFeed} = + useUnpinFeedMutation() + const {isPending: isMovePending, mutateAsync: setSavedFeeds} = + useSetSaveFeedsMutation() - const onTogglePinned = useCallback(() => { + const onTogglePinned = React.useCallback(async () => { Haptics.default() - item.togglePin().catch(e => { + + try { + if (isPinned) { + await unpinFeed({uri: feedUri}) + } else { + await pinFeed({uri: feedUri}) + } + } catch (e) { Toast.show('There was an issue contacting the server') logger.error('Failed to toggle pinned feed', {error: e}) - }) - }, [item]) - const onPressUp = useCallback( - () => - savedFeeds.movePinnedFeed(item, 'up').catch(e => { - Toast.show('There was an issue contacting the server') - logger.error('Failed to set pinned feed order', {error: e}) - }), - [savedFeeds, item], - ) - const onPressDown = useCallback( - () => - savedFeeds.movePinnedFeed(item, 'down').catch(e => { - Toast.show('There was an issue contacting the server') - logger.error('Failed to set pinned feed order', {error: e}) - }), - [savedFeeds, item], - ) + } + }, [feedUri, isPinned, pinFeed, unpinFeed]) + + const onPressUp = React.useCallback(async () => { + if (!isPinned) return + + const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>( + usePreferencesQueryKey, + )?.feeds + const pinned = feeds?.pinned ?? [] + const index = pinned.indexOf(feedUri) + + if (index === -1 || index === 0) return + ;[pinned[index], pinned[index - 1]] = [pinned[index - 1], pinned[index]] + + try { + await setSavedFeeds({saved: feeds?.saved ?? [], pinned}) + track('CustomFeed:Reorder', { + uri: feedUri, + index: pinned.indexOf(feedUri), + }) + } catch (e) { + Toast.show('There was an issue contacting the server') + logger.error('Failed to set pinned feed order', {error: e}) + } + }, [feedUri, isPinned, queryClient, setSavedFeeds]) + + const onPressDown = React.useCallback(async () => { + if (!isPinned) return + + const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>( + usePreferencesQueryKey, + )?.feeds + const pinned = feeds?.pinned ?? [] + const index = pinned.indexOf(feedUri) + + if (index === -1 || index >= pinned.length - 1) return + ;[pinned[index], pinned[index + 1]] = [pinned[index + 1], pinned[index]] + + try { + await setSavedFeeds({saved: feeds?.saved ?? [], pinned}) + track('CustomFeed:Reorder', { + uri: feedUri, + index: pinned.indexOf(feedUri), + }) + } catch (e) { + Toast.show('There was an issue contacting the server') + logger.error('Failed to set pinned feed order', {error: e}) + } + }, [feedUri, isPinned, queryClient, setSavedFeeds]) return ( <Pressable @@ -195,6 +231,7 @@ const ListItem = observer(function ListItemImpl({ {isPinned ? ( <View style={styles.webArrowButtonsContainer}> <TouchableOpacity + disabled={isMovePending} accessibilityRole="button" onPress={onPressUp} hitSlop={HITSLOP_TOP}> @@ -205,6 +242,7 @@ const ListItem = observer(function ListItemImpl({ /> </TouchableOpacity> <TouchableOpacity + disabled={isMovePending} accessibilityRole="button" onPress={onPressDown} hitSlop={HITSLOP_BOTTOM}> @@ -212,13 +250,14 @@ const ListItem = observer(function ListItemImpl({ </TouchableOpacity> </View> ) : null} - <FeedSourceCard - key={item.uri} - item={item} - showSaveBtn + <NewFeedSourceCard + key={feedUri} + feedUri={feedUri} style={styles.noBorder} + showSaveBtn /> <TouchableOpacity + disabled={isPinPending || isUnpinPending} accessibilityRole="button" hitSlop={10} onPress={onTogglePinned}> diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index e56a50d79..baad2227b 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -59,6 +59,7 @@ import { } from '#/state/preferences' import {useSession, useSessionApi, SessionAccount} from '#/state/session' import {useProfileQuery} from '#/state/queries/profile' +import {useClearPreferencesMutation} from '#/state/queries/preferences' // TEMPORARY (APP-700) // remove after backend testing finishes @@ -153,6 +154,7 @@ export const SettingsScreen = withAuthRequired( const {openModal} = useModalControls() const {isSwitchingAccounts, accounts, currentAccount} = useSession() const {clearCurrentAccount} = useSessionApi() + const {mutate: clearPreferences} = useClearPreferencesMutation() const primaryBg = useCustomPalette<ViewStyle>({ light: {backgroundColor: colors.blue0}, @@ -219,9 +221,8 @@ export const SettingsScreen = withAuthRequired( }, [openModal]) const onPressResetPreferences = React.useCallback(async () => { - await store.preferences.reset() - Toast.show('Preferences reset') - }, [store]) + clearPreferences() + }, [clearPreferences]) const onPressResetOnboarding = React.useCallback(async () => { onboardingDispatch({type: 'start'}) @@ -300,7 +301,7 @@ export const SettingsScreen = withAuthRequired( </View> <View style={[styles.infoLine]}> <Text type="lg-medium" style={pal.text}> - <Trans>Birthday: </Trans> + <Trans>Birthday:</Trans>{' '} </Text> <Link onPress={() => openModal({name: 'birth-date-settings'})}> <Text type="lg" style={pal.link}> |