diff --git a/src/components/Hr.tsx b/src/components/Hr.tsx
new file mode 100644
index 00000000..1af52002
--- /dev/null
+++ b/src/components/Hr.tsx
@@ -0,0 +1,23 @@
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+import { View, ViewStyle } from 'react-native'
+
+const Hr: React.FC<{ style?: ViewStyle }> = ({ style }) => {
+ const { colors } = useTheme()
+
+ return (
+
+ )
+}
+
+export default Hr
diff --git a/src/components/Input.tsx b/src/components/Input.tsx
index 02febb0c..736b2af6 100644
--- a/src/components/Input.tsx
+++ b/src/components/Input.tsx
@@ -9,7 +9,9 @@ import CustomText from './Text'
export type Props = {
title?: string
multiline?: boolean
-} & Pick, 'value' | 'selection' | 'isFocused'> &
+ invalid?: boolean
+} & Pick, 'value'> &
+ Pick, 'isFocused' | 'selection'> &
Omit<
TextInputProps,
| 'style'
@@ -27,8 +29,9 @@ const ComponentInput = forwardRef(
{
title,
multiline = false,
+ invalid = false,
value: [value, setValue],
- selection: [selection, setSelection],
+ selection,
isFocused,
...props
}: Props,
@@ -43,7 +46,7 @@ const ComponentInput = forwardRef(
paddingHorizontal: withTiming(StyleConstants.Spacing.XS),
left: withTiming(StyleConstants.Spacing.S),
top: withTiming(-(StyleConstants.Font.Size.S / 2) - 2),
- backgroundColor: withTiming(colors.backgroundDefault)
+ backgroundColor: colors.backgroundDefault
}
} else {
return {
@@ -62,7 +65,7 @@ const ComponentInput = forwardRef(
borderWidth: 1,
marginVertical: StyleConstants.Spacing.S,
padding: StyleConstants.Spacing.S,
- borderColor: colors.border,
+ borderColor: invalid ? colors.red : colors.border,
flexDirection: multiline ? 'column' : 'row',
alignItems: 'stretch'
}}
@@ -78,9 +81,13 @@ const ComponentInput = forwardRef(
}}
value={value}
onChangeText={setValue}
- onFocus={() => (isFocused.current = true)}
- onBlur={() => (isFocused.current = false)}
- onSelectionChange={({ nativeEvent }) => setSelection(nativeEvent.selection)}
+ {...(isFocused !== undefined && {
+ onFocus: () => (isFocused.current = true),
+ onBlur: () => (isFocused.current = false)
+ })}
+ {...(selection !== undefined && {
+ onSelectionChange: ({ nativeEvent }) => selection[1](nativeEvent.selection)
+ })}
{...(multiline && {
multiline,
numberOfLines: Platform.OS === 'android' ? 5 : undefined
diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx
index d140aa37..ffad2741 100644
--- a/src/components/Menu/Row.tsx
+++ b/src/components/Menu/Row.tsx
@@ -44,7 +44,7 @@ const MenuRow: React.FC = ({
loading = false,
onPress
}) => {
- const { colors, theme } = useTheme()
+ const { colors } = useTheme()
const { screenReaderEnabled } = useAccessibility()
return (
diff --git a/src/components/Selections.tsx b/src/components/Selections.tsx
index 8e62594a..bbad0a2b 100644
--- a/src/components/Selections.tsx
+++ b/src/components/Selections.tsx
@@ -8,17 +8,22 @@ import { ParseEmojis } from './Parse'
import CustomText from './Text'
export interface Props {
+ title?: string
+
multiple?: boolean
options: { selected: boolean; content: string }[]
setOptions: React.Dispatch>
disabled?: boolean
+ invalid?: boolean
}
const Selections: React.FC = ({
+ title,
multiple = false,
options,
setOptions,
- disabled = false
+ disabled = false,
+ invalid = false
}) => {
const { colors } = useTheme()
@@ -32,52 +37,71 @@ const Selections: React.FC = ({
: 'circle'
return (
-
- {options.map((option, index) => (
- {
- if (multiple) {
- haptics('Light')
-
- setOptions(options.map((o, i) => (i === index ? { ...o, selected: !o.selected } : o)))
- } else {
- if (!option.selected) {
+
+ {title ? (
+
+ ) : null}
+
+ {options.map((option, index) => (
+ {
+ if (multiple) {
haptics('Light')
+
setOptions(
- options.map((o, i) => {
- if (i === index) {
- return { ...o, selected: true }
- } else {
- return { ...o, selected: false }
- }
- })
+ options.map((o, i) => (i === index ? { ...o, selected: !o.selected } : o))
)
+ } else {
+ if (!option.selected) {
+ haptics('Light')
+ setOptions(
+ options.map((o, i) => {
+ if (i === index) {
+ return { ...o, selected: true }
+ } else {
+ return { ...o, selected: false }
+ }
+ })
+ )
+ }
}
- }
- }}
- >
-
-
-
-
+
+
-
-
-
- ))}
+
+
+
+
+
+ ))}
+
)
}
diff --git a/src/components/Timeline/Shared/Filtered.tsx b/src/components/Timeline/Shared/Filtered.tsx
index 9a8c11de..4a0c00da 100644
--- a/src/components/Timeline/Shared/Filtered.tsx
+++ b/src/components/Timeline/Shared/Filtered.tsx
@@ -99,7 +99,7 @@ export const shouldFilter = ({
break
}
}
- const queryKeyFilters: QueryKeyFilters = ['Filters']
+ const queryKeyFilters: QueryKeyFilters = ['Filters', { version: 'v1' }]
queryClient.getQueryData[]>(queryKeyFilters)?.forEach(filter => {
if (returnFilter) {
return
diff --git a/src/components/Timeline/Shared/Poll.tsx b/src/components/Timeline/Shared/Poll.tsx
index 7cda64ec..47f006b8 100644
--- a/src/components/Timeline/Shared/Poll.tsx
+++ b/src/components/Timeline/Shared/Poll.tsx
@@ -133,7 +133,7 @@ const TimelinePoll: React.FC = () => {
{
",
+ "contexts": {
+ "home": "following and lists",
+ "notifications": "notification",
+ "public": "federated",
+ "thread": "conversation",
+ "account": "profile"
+ }
+ },
+ "preferencesFilter": {
+ "name": "Name",
+ "expiration": "Expiration",
+ "expirationOptions": {
+ "0": "Never",
+ "1800": "After 30 minutes",
+ "3600": "After 1 hour",
+ "43200": "After 12 hours",
+ "86400": "After 1 day",
+ "604800": "After 1 week",
+ "18144000": "After 1 month"
+ },
+ "context": "Applies in",
+ "contexts": {
+ "home": "Following and lists",
+ "notifications": "Notification",
+ "public": "Federated timeline",
+ "thread": "Conversation view",
+ "account": "Profile view"
+ },
+ "action": "When matched",
+ "actions": {
+ "warn": "Collapsed but can be revealed",
+ "hide": "Hidden completely"
+ },
+ "keywords": "Matches for these keywords",
+ "keyword": "Keyword"
+ },
"profile": {
"feedback": {
"succeed": "{{type}} updated",
diff --git a/src/screens/Tabs/Me/List/Edit.tsx b/src/screens/Tabs/Me/List/Edit.tsx
index 77f011ac..2dc750b5 100644
--- a/src/screens/Tabs/Me/List/Edit.tsx
+++ b/src/screens/Tabs/Me/List/Edit.tsx
@@ -19,7 +19,7 @@ const TabMeListEdit: React.FC> = ({
navigation,
route: { params }
}) => {
- const { colors, theme } = useTheme()
+ const { colors } = useTheme()
const { t } = useTranslation(['common', 'screenTabs'])
const messageRef = useRef(null)
@@ -147,18 +147,11 @@ const TabMeListEdit: React.FC> = ({
-
- {t('screenTabs:me.listEdit.repliesPolicy.heading')}
-
-
+
diff --git a/src/screens/Tabs/Me/Preferences/Filter.tsx b/src/screens/Tabs/Me/Preferences/Filter.tsx
new file mode 100644
index 00000000..7f3088ab
--- /dev/null
+++ b/src/screens/Tabs/Me/Preferences/Filter.tsx
@@ -0,0 +1,265 @@
+import Button from '@components/Button'
+import haptics from '@components/haptics'
+import { HeaderLeft, HeaderRight } from '@components/Header'
+import Hr from '@components/Hr'
+import ComponentInput from '@components/Input'
+import { MenuRow } from '@components/Menu'
+import Selections from '@components/Selections'
+import CustomText from '@components/Text'
+import { useActionSheet } from '@expo/react-native-action-sheet'
+import apiInstance from '@utils/api/instance'
+import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles'
+import { TabMePreferencesStackScreenProps } from '@utils/navigation/navigators'
+import { queryClient } from '@utils/queryHooks'
+import { QueryKeyFilters } from '@utils/queryHooks/filters'
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+import React, { RefObject, useEffect, useState } from 'react'
+import { useTranslation } from 'react-i18next'
+import { KeyboardAvoidingView, Platform, View } from 'react-native'
+import FlashMessage from 'react-native-flash-message'
+import { ScrollView } from 'react-native-gesture-handler'
+import { SafeAreaView } from 'react-native-safe-area-context'
+
+const TabMePreferencesFilter: React.FC<
+ TabMePreferencesStackScreenProps<'Tab-Me-Preferences-Filter'> & {
+ messageRef: RefObject
+ }
+> = ({ navigation, route: { params } }) => {
+ const { colors } = useTheme()
+ const { t } = useTranslation(['common', 'screenTabs'])
+
+ const { showActionSheetWithOptions } = useActionSheet()
+
+ useEffect(() => {
+ navigation.setOptions({
+ title:
+ params.type === 'add'
+ ? t('screenTabs:me.stacks.preferencesFilterAdd.name')
+ : t('screenTabs:me.stacks.preferencesFilterEdit.name'),
+ headerLeft: () => (
+ navigation.navigate('Tab-Me-Preferences-Filters')}
+ />
+ )
+ })
+ }, [])
+
+ const titleState = useState(params.type === 'edit' ? params.filter.title : '')
+
+ const expirations = ['0', '1800', '3600', '43200', '86400', '604800', '18144000'] as const
+ const [expiration, setExpiration] = useState('0')
+
+ const [contexts, setContexts] = useState<
+ {
+ selected: boolean
+ content: string
+ type: 'home' | 'notifications' | 'public' | 'thread' | 'account'
+ }[]
+ >([
+ {
+ selected: params.type === 'edit' ? params.filter.context.includes('home') : true,
+ content: t('screenTabs:me.preferencesFilter.contexts.home'),
+ type: 'home'
+ },
+ {
+ selected: params.type === 'edit' ? params.filter.context.includes('notifications') : false,
+ content: t('screenTabs:me.preferencesFilter.contexts.notifications'),
+ type: 'notifications'
+ },
+ {
+ selected: params.type === 'edit' ? params.filter.context.includes('public') : false,
+ content: t('screenTabs:me.preferencesFilter.contexts.public'),
+ type: 'public'
+ },
+ {
+ selected: params.type === 'edit' ? params.filter.context.includes('thread') : false,
+ content: t('screenTabs:me.preferencesFilter.contexts.thread'),
+ type: 'thread'
+ },
+ {
+ selected: params.type === 'edit' ? params.filter.context.includes('account') : false,
+ content: t('screenTabs:me.preferencesFilter.contexts.account'),
+ type: 'account'
+ }
+ ])
+
+ const [actions, setActions] = useState<
+ { selected: boolean; content: string; type: 'warn' | 'hide' }[]
+ >([
+ {
+ selected: params.type === 'edit' ? params.filter.filter_action === 'warn' : true,
+ content: t('screenTabs:me.preferencesFilter.actions.warn'),
+ type: 'warn'
+ },
+ {
+ selected: params.type === 'edit' ? params.filter.filter_action === 'hide' : false,
+ content: t('screenTabs:me.preferencesFilter.actions.hide'),
+ type: 'hide'
+ }
+ ])
+
+ const [keywords, setKeywords] = useState(
+ params.type === 'edit' ? params.filter.keywords.map(({ keyword }) => keyword) : []
+ )
+
+ useEffect(() => {
+ let isLoading = false
+ navigation.setOptions({
+ headerRight: () => (
+ {
+ if (!titleState[0].length || !contexts.filter(context => context.selected).length)
+ return
+
+ switch (params.type) {
+ case 'add':
+ isLoading = true
+ await apiInstance({
+ method: 'post',
+ version: 'v2',
+ url: 'filters',
+ body: {
+ title: titleState[0],
+ context: contexts
+ .filter(context => context.selected)
+ .map(context => context.type),
+ filter_action: actions.filter(
+ action => action.type === 'hide' && action.selected
+ ).length
+ ? 'hide'
+ : 'warn',
+ ...(parseInt(expiration) && { expires_in: parseInt(expiration) }),
+ ...(keywords.filter(keyword => keyword.length).length && {
+ keywords_attributes: keywords
+ .filter(keyword => keyword.length)
+ .map(keyword => ({ keyword, whole_word: true }))
+ })
+ }
+ })
+ .then(() => {
+ isLoading = false
+ const queryKey: QueryKeyFilters = ['Filters', { version: 'v2' }]
+ queryClient.refetchQueries(queryKey)
+ navigation.navigate('Tab-Me-Preferences-Filters')
+ })
+ .catch(() => {
+ isLoading = false
+ haptics('Error')
+ })
+ break
+ case 'edit':
+ break
+ }
+ }}
+ />
+ )
+ })
+ }, [titleState[0], expiration, contexts, actions, keywords])
+
+ return (
+
+
+
+
+
+ showActionSheetWithOptions(
+ {
+ title: t('screenTabs:me.preferencesFilter.expiration'),
+ options: [
+ ...expirations.map(opt =>
+ t(`screenTabs:me.preferencesFilter.expirationOptions.${opt}`)
+ ),
+ t('common:buttons.cancel')
+ ],
+ cancelButtonIndex: expirations.length,
+ ...androidActionSheetStyles(colors)
+ },
+ (selectedIndex: number) => {
+ selectedIndex < expirations.length && setExpiration(expirations[selectedIndex])
+ }
+ )
+ }
+ />
+
+
+ context.selected).length}
+ options={contexts}
+ setOptions={setContexts}
+ />
+
+
+
+
+
+ {[...Array(keywords.length)].map((_, i) => (
+ setKeywords(keywords.map((curr, ii) => (i === ii ? k : curr)))
+ ]}
+ />
+ ))}
+
+
+
+
+
+
+ )
+}
+
+export default TabMePreferencesFilter
diff --git a/src/screens/Tabs/Me/Preferences/Filters.tsx b/src/screens/Tabs/Me/Preferences/Filters.tsx
new file mode 100644
index 00000000..6babb2d1
--- /dev/null
+++ b/src/screens/Tabs/Me/Preferences/Filters.tsx
@@ -0,0 +1,166 @@
+import { HeaderLeft, HeaderRight } from '@components/Header'
+import Icon from '@components/Icon'
+import ComponentSeparator from '@components/Separator'
+import CustomText from '@components/Text'
+import apiInstance from '@utils/api/instance'
+import { TabMePreferencesStackScreenProps } from '@utils/navigation/navigators'
+import { useFiltersQuery } from '@utils/queryHooks/filters'
+import { StyleConstants } from '@utils/styles/constants'
+import { useTheme } from '@utils/styles/ThemeManager'
+import React, { Fragment, useEffect } from 'react'
+import { Trans, useTranslation } from 'react-i18next'
+import { Pressable, TouchableNativeFeedback, View } from 'react-native'
+import { SwipeListView } from 'react-native-swipe-list-view'
+
+const TabMePreferencesFilters: React.FC<
+ TabMePreferencesStackScreenProps<'Tab-Me-Preferences-Filters'>
+> = ({ navigation }) => {
+ const { colors } = useTheme()
+ const { t } = useTranslation(['common', 'screenTabs'])
+
+ useEffect(() => {
+ navigation.setOptions({
+ headerLeft: () => (
+ navigation.navigate('Tab-Me-Preferences-Root')}
+ />
+ ),
+ headerRight: () => (
+ navigation.navigate('Tab-Me-Preferences-Filter', { type: 'add' })}
+ />
+ )
+ })
+ }, [])
+
+ const { data, refetch } = useFiltersQuery<'v2'>({ version: 'v2' })
+
+ return (
+ (
+ {
+ apiInstance({ method: 'delete', version: 'v2', url: `filters/${item.id}` }).then(() =>
+ refetch()
+ )
+ }}
+ >
+
+
+
+
+ )}
+ rightOpenValue={-(StyleConstants.Spacing.L * 2 + StyleConstants.Font.Size.L)}
+ disableRightSwipe
+ closeOnRowPress
+ data={data?.sort(filter =>
+ filter.expires_at ? new Date().getTime() - new Date(filter.expires_at).getTime() : 1
+ )}
+ renderItem={({ item: filter }) => (
+ navigation.navigate('Tab-Me-Preferences-Filter', { type: 'edit', filter })}
+ >
+
+
+
+
+ {filter.expires_at && new Date() > new Date(filter.expires_at) ? (
+
+ ) : null}
+ {filter.keywords?.length ? (
+
+ ) : null}
+ {filter.keywords?.length && filter.statuses?.length ? (
+
+ ) : null}
+ {filter.statuses?.length ? (
+
+ ) : null}
+
+
+ {filter.context.map((c, index) => (
+
+
+
+
+ ))}
+ >
+ ]}
+ />
+ }
+ />
+
+
+
+
+ )}
+ ItemSeparatorComponent={ComponentSeparator}
+ />
+ )
+}
+
+export default TabMePreferencesFilters
diff --git a/src/screens/Tabs/Me/Preferences.tsx b/src/screens/Tabs/Me/Preferences/Root.tsx
similarity index 82%
rename from src/screens/Tabs/Me/Preferences.tsx
rename to src/screens/Tabs/Me/Preferences/Root.tsx
index 631f10c0..4aeb2214 100644
--- a/src/screens/Tabs/Me/Preferences.tsx
+++ b/src/screens/Tabs/Me/Preferences/Root.tsx
@@ -1,21 +1,26 @@
import { MenuContainer, MenuRow } from '@components/Menu'
-import { Message } from '@components/Message'
import { useActionSheet } from '@expo/react-native-action-sheet'
import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles'
import browserPackage from '@utils/helpers/browserPackage'
-import { TabMeProfileStackScreenProps } from '@utils/navigation/navigators'
+import { featureCheck } from '@utils/helpers/featureCheck'
+import { TabMePreferencesStackScreenProps } from '@utils/navigation/navigators'
+import { useFiltersQuery } from '@utils/queryHooks/filters'
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
import { useProfileMutation } from '@utils/queryHooks/profile'
import { getAccountStorage } from '@utils/storage/actions'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import * as WebBrowser from 'expo-web-browser'
-import React, { useRef } from 'react'
+import React, { RefObject } from 'react'
import { useTranslation } from 'react-i18next'
import FlashMessage from 'react-native-flash-message'
import { ScrollView } from 'react-native-gesture-handler'
-const TabMePreferences: React.FC> = () => {
+const TabMePreferencesRoot: React.FC<
+ TabMePreferencesStackScreenProps<'Tab-Me-Preferences-Root'> & {
+ messageRef: RefObject
+ }
+> = ({ navigation, messageRef }) => {
const { colors } = useTheme()
const { t } = useTranslation(['common', 'screenTabs'])
@@ -25,7 +30,7 @@ const TabMePreferences: React.FC(null)
+ const { data: filters, isFetching: filtersIsFetching } = useFiltersQuery<'v2'>({ version: 'v2' })
return (
@@ -149,10 +154,23 @@ const TabMePreferences: React.FC
) : null}
-
-
+ {featureCheck('filter_server_side') ? (
+
+
+ filter.expires_at ? new Date(filter.expires_at) > new Date() : true
+ ).length
+ })}
+ loading={filtersIsFetching}
+ iconBack='chevron-right'
+ onPress={() => navigation.navigate('Tab-Me-Preferences-Filters')}
+ />
+
+ ) : null}
)
}
-export default TabMePreferences
+export default TabMePreferencesRoot
diff --git a/src/screens/Tabs/Me/Preferences/index.tsx b/src/screens/Tabs/Me/Preferences/index.tsx
new file mode 100644
index 00000000..411a39d4
--- /dev/null
+++ b/src/screens/Tabs/Me/Preferences/index.tsx
@@ -0,0 +1,49 @@
+import { HeaderLeft } from '@components/Header'
+import { Message } from '@components/Message'
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import { TabMePreferencesStackParamList, TabMeStackScreenProps } from '@utils/navigation/navigators'
+import React, { useRef } from 'react'
+import { useTranslation } from 'react-i18next'
+import FlashMessage from 'react-native-flash-message'
+import TabMePreferencesFilter from './Filter'
+import TabMePreferencesFilters from './Filters'
+import TabMePreferencesRoot from './Root'
+
+const Stack = createNativeStackNavigator()
+
+const TabMePreferences: React.FC> = ({
+ navigation
+}) => {
+ const { t } = useTranslation('screenTabs')
+ const messageRef = useRef(null)
+
+ return (
+ <>
+
+ (
+ navigation.goBack()} />
+ )
+ }}
+ >
+ {props => }
+
+
+
+ {props => }
+
+
+
+
+ >
+ )
+}
+
+export default TabMePreferences
diff --git a/src/screens/Tabs/Me/Profile/Fields.tsx b/src/screens/Tabs/Me/Profile/Fields.tsx
index cc36a9f1..4ea66d80 100644
--- a/src/screens/Tabs/Me/Profile/Fields.tsx
+++ b/src/screens/Tabs/Me/Profile/Fields.tsx
@@ -90,7 +90,7 @@ const TabMeProfileFields: React.FC<
navigation.setOptions({
headerLeft: () => (
{
if (dirty) {
Alert.alert(t('common:discard.title'), t('common:discard.message'), [
diff --git a/src/screens/Tabs/Me/Profile/Name.tsx b/src/screens/Tabs/Me/Profile/Name.tsx
index 36708b0c..c978ca92 100644
--- a/src/screens/Tabs/Me/Profile/Name.tsx
+++ b/src/screens/Tabs/Me/Profile/Name.tsx
@@ -44,7 +44,7 @@ const TabMeProfileName: React.FC<
navigation.setOptions({
headerLeft: () => (
{
if (dirty) {
Alert.alert(t('common:discard.title'), t('common:discard.message'), [
diff --git a/src/screens/Tabs/Me/Profile/Note.tsx b/src/screens/Tabs/Me/Profile/Note.tsx
index 63adf948..12071660 100644
--- a/src/screens/Tabs/Me/Profile/Note.tsx
+++ b/src/screens/Tabs/Me/Profile/Note.tsx
@@ -44,7 +44,7 @@ const TabMeProfileNote: React.FC<
navigation.setOptions({
headerLeft: () => (
{
if (dirty) {
Alert.alert(t('common:discard.title'), t('common:discard.message'), [
diff --git a/src/screens/Tabs/Me/Profile/index.tsx b/src/screens/Tabs/Me/Profile/index.tsx
index 3328711f..7f28238c 100644
--- a/src/screens/Tabs/Me/Profile/index.tsx
+++ b/src/screens/Tabs/Me/Profile/index.tsx
@@ -32,33 +32,25 @@ const TabMeProfile: React.FC> = ({ naviga
)
}}
>
- {({ route, navigation }) => (
-
- )}
+ {props => }
- {({ route, navigation }) => (
-
- )}
+ {props => }
- {({ route, navigation }) => (
-
- )}
+ {props => }
- {({ route, navigation }) => (
-
- )}
+ {props => }
diff --git a/src/screens/Tabs/Me/index.tsx b/src/screens/Tabs/Me/index.tsx
index 7c942f15..bd10f706 100644
--- a/src/screens/Tabs/Me/index.tsx
+++ b/src/screens/Tabs/Me/index.tsx
@@ -104,11 +104,7 @@ const TabMe: React.FC = () => {
({
- presentation: 'modal',
- title: t('me.stacks.preferences.name'),
- headerLeft: () => navigation.pop(1)} />
- })}
+ options={{ headerShown: false, presentation: 'modal' }}
/>
{
presentation: 'modal',
headerShown: true,
title: t('me.stacks.switch.name'),
- headerLeft: () => navigation.goBack()} />
+ headerLeft: () => (
+ navigation.goBack()} />
+ )
})}
/>
diff --git a/src/screens/Tabs/Shared/Account/Information/Actions.tsx b/src/screens/Tabs/Shared/Account/Information/Actions.tsx
index d3a22aad..4291cfeb 100644
--- a/src/screens/Tabs/Shared/Account/Information/Actions.tsx
+++ b/src/screens/Tabs/Shared/Account/Information/Actions.tsx
@@ -48,7 +48,9 @@ const AccountInformationActions: React.FC = () => {
disabled={account === undefined}
content='sliders'
style={{ marginLeft: StyleConstants.Spacing.S }}
- onPress={() => navigation.navigate('Tab-Me-Preferences')}
+ onPress={() =>
+ navigation.navigate('Tab-Me-Preferences', { screen: 'Tab-Me-Preferences-Root' })
+ }
/>
)
diff --git a/src/screens/Tabs/Shared/Report.tsx b/src/screens/Tabs/Shared/Report.tsx
index 78c2a770..150e3074 100644
--- a/src/screens/Tabs/Shared/Report.tsx
+++ b/src/screens/Tabs/Shared/Report.tsx
@@ -125,7 +125,11 @@ const TabSharedReport: React.FC>
>
{t('screenTabs:shared.report.forward.heading', {
@@ -140,15 +144,11 @@ const TabSharedReport: React.FC>
) : null}
-
- {t('screenTabs:shared.report.reasons.heading')}
-
-
-
-
+
{categories[1].selected || comment.length ? (
<>
@@ -200,26 +200,13 @@ const TabSharedReport: React.FC>
) : null}
{rules.length ? (
- <>
-
- {t('screenTabs:shared.report.violatedRules.heading')}
-
-
-
-
- >
+
) : null}
diff --git a/src/utils/navigation/navigators.ts b/src/utils/navigation/navigators.ts
index 335f87c5..38bdf429 100644
--- a/src/utils/navigation/navigators.ts
+++ b/src/utils/navigation/navigators.ts
@@ -186,3 +186,18 @@ export type TabMeProfileStackParamList = {
}
export type TabMeProfileStackScreenProps =
NativeStackScreenProps
+
+export type TabMePreferencesStackParamList = {
+ 'Tab-Me-Preferences-Root': undefined
+ 'Tab-Me-Preferences-Filters': undefined
+ 'Tab-Me-Preferences-Filter':
+ | {
+ type: 'add'
+ }
+ | {
+ type: 'edit'
+ filter: Mastodon.Filter<'v2'>
+ }
+}
+export type TabMePreferencesStackScreenProps =
+ NativeStackScreenProps
diff --git a/src/utils/queryHooks/apps.ts b/src/utils/queryHooks/apps.ts
index 840885fb..636fb621 100644
--- a/src/utils/queryHooks/apps.ts
+++ b/src/utils/queryHooks/apps.ts
@@ -1,10 +1,4 @@
-import {
- QueryFunctionContext,
- useMutation,
- UseMutationOptions,
- useQuery,
- UseQueryOptions
-} from '@tanstack/react-query'
+import { useMutation, UseMutationOptions, useQuery, UseQueryOptions } from '@tanstack/react-query'
import apiGeneral from '@utils/api/general'
import apiInstance from '@utils/api/instance'
import { AxiosError } from 'axios'
@@ -12,7 +6,7 @@ import * as AuthSession from 'expo-auth-session'
export type QueryKeyApps = ['Apps']
-const queryFunctionApps = async ({ queryKey }: QueryFunctionContext) => {
+const queryFunctionApps = async () => {
const res = await apiInstance({
method: 'get',
url: 'apps/verify_credentials'
diff --git a/src/utils/queryHooks/filters.ts b/src/utils/queryHooks/filters.ts
index cc67e468..2968b764 100644
--- a/src/utils/queryHooks/filters.ts
+++ b/src/utils/queryHooks/filters.ts
@@ -1,24 +1,57 @@
-import { useQuery, UseQueryOptions } from '@tanstack/react-query'
+import { QueryFunctionContext, useQuery, UseQueryOptions } from '@tanstack/react-query'
import apiInstance from '@utils/api/instance'
import { AxiosError } from 'axios'
-export type QueryKeyFilters = ['Filters']
+export type QueryKeyFilter = ['Filter', { id: Mastodon.Filter<'v2'>['id'] }]
-const queryFunction = () =>
- apiInstance[]>({
+const filterQueryFunction = async ({ queryKey }: QueryFunctionContext) => {
+ const res = await apiInstance>({
method: 'get',
- url: 'filters'
- }).then(res => res.body)
+ version: 'v2',
+ url: `filters/${queryKey[1].id}`
+ })
+ return res.body
+}
-const useFiltersQuery = (params?: {
- options: UseQueryOptions[], AxiosError>
+const useFilterQuery = ({
+ filter,
+ options
+}: {
+ filter: Mastodon.Filter<'v2'>
+ options?: UseQueryOptions, AxiosError>
}) => {
- const queryKey: QueryKeyFilters = ['Filters']
- return useQuery(queryKey, queryFunction, {
+ const queryKey: QueryKeyFilter = ['Filter', { id: filter.id }]
+ return useQuery(queryKey, filterQueryFunction, {
+ ...options,
+ staleTime: Infinity,
+ cacheTime: Infinity
+ })
+}
+
+export type QueryKeyFilters = ['Filters', { version: 'v1' | 'v2' }]
+
+const filtersQueryFunction = async ({
+ queryKey
+}: QueryFunctionContext) => {
+ const version = queryKey[1].version
+ const res = await apiInstance[]>({
+ method: 'get',
+ version,
+ url: 'filters'
+ })
+ return res.body
+}
+
+const useFiltersQuery = (params?: {
+ version?: T
+ options?: UseQueryOptions[], AxiosError>
+}) => {
+ const queryKey: QueryKeyFilters = ['Filters', { version: params?.version || 'v1' }]
+ return useQuery(queryKey, filtersQueryFunction, {
...params?.options,
staleTime: Infinity,
cacheTime: Infinity
})
}
-export { useFiltersQuery }
+export { useFilterQuery, useFiltersQuery }
diff --git a/src/utils/styles/themes.ts b/src/utils/styles/themes.ts
index eafbb16f..4f6bc268 100644
--- a/src/utils/styles/themes.ts
+++ b/src/utils/styles/themes.ts
@@ -42,9 +42,9 @@ const themeColors: {
dark_darker: 'rgb(130, 130, 130)'
},
disabled: {
- light: 'rgb(200, 200, 200)',
- dark_lighter: 'rgb(120, 120, 120)',
- dark_darker: 'rgb(66, 66, 66)'
+ light: 'rgb(220, 220, 220)',
+ dark_lighter: 'rgb(70, 70, 70)',
+ dark_darker: 'rgb(50, 50, 50)'
},
blue: {
light: 'rgb(43, 144, 221)',