1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00
This commit is contained in:
xmflsct
2023-01-26 23:07:13 +01:00
parent e8eb62e2d0
commit 653b588c29
18 changed files with 555 additions and 207 deletions

114
src/components/Filter.tsx Normal file
View File

@@ -0,0 +1,114 @@
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import { Fragment } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { View } from 'react-native'
import { TouchableNativeFeedback } from 'react-native-gesture-handler'
import Icon from './Icon'
import CustomText from './Text'
export type Props = {
onPress: () => void
filter: Mastodon.Filter<'v2'>
button?: React.ReactNode
}
export const Filter: React.FC<Props> = ({ onPress, filter, button }) => {
const { t } = useTranslation(['common', 'screenTabs'])
const { colors } = useTheme()
return (
<TouchableNativeFeedback onPress={onPress}>
<View
style={{
paddingVertical: StyleConstants.Spacing.S,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.backgroundDefault
}}
>
<View style={{ flex: 1 }}>
<CustomText
fontStyle='M'
children={filter.title}
style={{ color: colors.primaryDefault }}
numberOfLines={1}
/>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
marginVertical: StyleConstants.Spacing.XS
}}
>
{filter.expires_at && new Date() > new Date(filter.expires_at) ? (
<CustomText
fontStyle='S'
fontWeight='Bold'
children={t('screenTabs:me.preferencesFilters.expired')}
style={{ color: colors.red, marginRight: StyleConstants.Spacing.M }}
/>
) : null}
{filter.keywords?.length ? (
<CustomText
children={t('screenTabs:me.preferencesFilters.keywords', {
count: filter.keywords.length
})}
style={{ color: colors.primaryDefault }}
/>
) : null}
{filter.keywords?.length && filter.statuses?.length ? (
<CustomText
children={t('common:separator')}
style={{ color: colors.primaryDefault }}
/>
) : null}
{filter.statuses?.length ? (
<CustomText
children={t('screenTabs:me.preferencesFilters.statuses', {
count: filter.statuses.length
})}
style={{ color: colors.primaryDefault }}
/>
) : null}
</View>
<CustomText
style={{ color: colors.secondary }}
children={
<Trans
ns='screenTabs'
i18nKey='me.preferencesFilters.context'
components={[
<>
{filter.context.map((c, index) => (
<Fragment key={index}>
<CustomText
style={{
color: colors.secondary,
textDecorationColor: colors.disabled,
textDecorationLine: 'underline',
textDecorationStyle: 'solid'
}}
children={t(`screenTabs:me.preferencesFilters.contexts.${c}`)}
/>
<CustomText children={t('common:separator')} />
</Fragment>
))}
</>
]}
/>
}
/>
</View>
{button || (
<Icon
name='chevron-right'
size={StyleConstants.Font.Size.L}
color={colors.primaryDefault}
style={{ marginLeft: 8 }}
/>
)}
</View>
</TouchableNativeFeedback>
)
}

View File

@@ -22,7 +22,7 @@ const ComponentHashtag: React.FC<PropsWithChildren & Props> = ({
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
const onPress = () => {
navigation.push('Tab-Shared-Hashtag', { hashtag: hashtag.name })
navigation.push('Tab-Shared-Hashtag', { tag_name: hashtag.name })
}
const padding = StyleConstants.Spacing.Global.PagePadding

View File

@@ -69,7 +69,7 @@ const ParseHTML: React.FC<Props> = ({
const [followedTags] = useAccountStorage.object('followed_tags')
const MAX_ALLOWED_LINES = 30
const MAX_ALLOWED_LINES = 35
const [totalLines, setTotalLines] = useState<number>()
const [expanded, setExpanded] = useState(highlighted)
@@ -147,7 +147,7 @@ const ParseHTML: React.FC<Props> = ({
tag?.length &&
!disableDetails &&
!sameHashtag &&
navigation.push('Tab-Shared-Hashtag', { hashtag: tag })
navigation.push('Tab-Shared-Hashtag', { tag_name: tag })
}
children={children}
/>
@@ -203,9 +203,7 @@ const ParseHTML: React.FC<Props> = ({
onPress={async () => {
if (!disableDetails) {
if (shouldBeTag) {
navigation.push('Tab-Shared-Hashtag', {
hashtag: content.substring(1)
})
navigation.push('Tab-Shared-Hashtag', { tag_name: content.substring(1) })
} else {
await openLink(href, navigation)
}

View File

@@ -137,8 +137,8 @@ const TimelinePoll: React.FC = () => {
marginRight: StyleConstants.Spacing.S
}}
name={
`${poll.own_votes?.includes(index) ? 'Check' : ''}${
poll.multiple ? 'Square' : 'Circle'
`${poll.own_votes?.includes(index) ? 'check-' : ''}${
poll.multiple ? 'square' : 'circle'
}` as any
}
size={StyleConstants.Font.Size.M}

View File

@@ -0,0 +1,97 @@
import haptics from '@components/haptics'
import { displayMessage } from '@components/Message'
import { useNavigation } from '@react-navigation/native'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { useQueryClient } from '@tanstack/react-query'
import { featureCheck } from '@utils/helpers/featureCheck'
import { TabSharedStackParamList } from '@utils/navigation/navigators'
import { QueryKeyFollowedTags, useTagMutation, useTagQuery } from '@utils/queryHooks/tags'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import { useTranslation } from 'react-i18next'
const menuHashtag = ({
tag_name,
queryKey
}: {
tag_name: Mastodon.Tag['name']
queryKey?: QueryKeyTimeline
}): ContextMenu => {
const navigation =
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
const { t } = useTranslation(['common', 'componentContextMenu'])
const canFollowTags = featureCheck('follow_tags')
const queryClient = useQueryClient()
const {
data,
isFetching: tagIsFetching,
refetch: tagRefetch
} = useTagQuery({ tag_name, options: { enabled: canFollowTags } })
const tagMutation = useTagMutation({
onSuccess: () => {
haptics('Light')
tagRefetch()
const queryKeyFollowedTags: QueryKeyFollowedTags = ['FollowedTags']
queryClient.invalidateQueries({ queryKey: queryKeyFollowedTags })
},
onError: (err: any, { to }) => {
displayMessage({
type: 'error',
message: t('common:message.error.message', {
function: t('componentContextMenu:hashtag.follow', {
defaultValue: 'false',
context: to.toString()
})
}),
...(err.status &&
typeof err.status === 'number' &&
err.data &&
err.data.error &&
typeof err.data.error === 'string' && {
description: err.data.error
})
})
}
})
const menus: ContextMenu = []
menus.push([
{
type: 'item',
key: 'hashtag-follow',
props: {
onSelect: () =>
typeof data?.following === 'boolean' &&
tagMutation.mutate({ tag_name, to: !data.following }),
disabled: tagIsFetching,
destructive: false,
hidden: !canFollowTags
},
title: t('componentContextMenu:hashtag.follow.action', {
defaultValue: 'false',
context: (data?.following || false).toString()
}),
icon: data?.following ? 'rectangle.stack.badge.minus' : 'rectangle.stack.badge.plus'
},
{
type: 'item',
key: 'hashtag-filter',
props: {
onSelect: () =>
navigation.navigate('Tab-Shared-Filter', { source: 'hashtag', tag_name, queryKey }),
disabled: false,
destructive: false,
hidden: !canFollowTags
},
title: t('componentContextMenu:hashtag.filter.action'),
icon: 'line.3.horizontal.decrease'
}
])
return menus
}
export default menuHashtag

View File

@@ -231,6 +231,22 @@ const menuStatus = ({
context: (status.pinned || false).toString()
}),
icon: status.pinned ? 'pin.slash' : 'pin'
},
{
type: 'item',
key: 'status-filter',
props: {
// @ts-ignore
onSelect: () => navigation.navigate('Tab-Shared-Filter', { source: 'status', status, queryKey }),
disabled: false,
destructive: false,
hidden: !('filtered' in status)
},
title: t('componentContextMenu:status.filter.action', {
defaultValue: 'false',
context: (!!status.filtered?.length).toString()
}),
icon: status.pinned ? 'rectangle.badge.checkmark' : 'rectangle.badge.xmark'
}
])