Clean up
This commit is contained in:
@@ -13,7 +13,10 @@ import {useSetDrawerOpen} from '#/state/shell'
|
|||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {shareUrl} from '#/lib/sharing'
|
import {shareUrl} from '#/lib/sharing'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {NativeDropdown, DropdownItem} from '#/view/com/util/forms/NativeDropdown'
|
import {
|
||||||
|
NativeDropdown,
|
||||||
|
DropdownItem,
|
||||||
|
} from '#/view/com/util/forms/NativeDropdown'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
|
|
||||||
@@ -95,7 +98,7 @@ export function Header({
|
|||||||
a.overflow_hidden,
|
a.overflow_hidden,
|
||||||
]}>
|
]}>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={tokens.gradients.sky.values.map(c => c[1])}
|
colors={tokens.gradients.bonfire.values.map(c => c[1])}
|
||||||
locations={tokens.gradients.bonfire.values.map(c => c[0])}
|
locations={tokens.gradients.bonfire.values.map(c => c[0])}
|
||||||
start={{x: 0, y: 0}}
|
start={{x: 0, y: 0}}
|
||||||
end={{x: 1, y: 1}}
|
end={{x: 1, y: 1}}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {msg} from '@lingui/macro'
|
||||||
|
|
||||||
|
import {
|
||||||
|
CONFIGURABLE_LABEL_GROUPS,
|
||||||
|
ConfigurableLabelGroup,
|
||||||
|
} from '#/state/queries/preferences'
|
||||||
|
|
||||||
|
import {useTheme, atoms as a} from '#/alf'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import * as ToggleButton from '#/components/forms/ToggleButton'
|
||||||
|
|
||||||
|
export function PreferenceRow({
|
||||||
|
labelGroup,
|
||||||
|
}: {
|
||||||
|
labelGroup: ConfigurableLabelGroup
|
||||||
|
}) {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const groupInfo = CONFIGURABLE_LABEL_GROUPS[labelGroup]
|
||||||
|
|
||||||
|
const labels = {
|
||||||
|
hide: _(msg`Hide`),
|
||||||
|
warn: _(msg`Warn`),
|
||||||
|
show: _(msg`Show`),
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_row,
|
||||||
|
a.justify_between,
|
||||||
|
a.gap_sm,
|
||||||
|
a.py_xs,
|
||||||
|
a.px_xs,
|
||||||
|
a.align_center,
|
||||||
|
]}>
|
||||||
|
<View style={[a.gap_xs, {width: '50%'}]}>
|
||||||
|
<Text style={[a.font_bold]}>{groupInfo.title}</Text>
|
||||||
|
<Text style={[t.atoms.text_contrast_700, a.leading_snug]}>
|
||||||
|
{groupInfo.subtitle}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[a.justify_center, {minHeight: 35}]}>
|
||||||
|
<ToggleButton.Group
|
||||||
|
label={_(
|
||||||
|
msg`Configure content filtering setting for category: ${groupInfo.title.toLowerCase()}`,
|
||||||
|
)}
|
||||||
|
values={['warn']}
|
||||||
|
onChange={() => {}}>
|
||||||
|
<ToggleButton.Button name="hide" label={labels.hide}>
|
||||||
|
{labels.hide}
|
||||||
|
</ToggleButton.Button>
|
||||||
|
<ToggleButton.Button name="warn" label={labels.warn}>
|
||||||
|
{labels.warn}
|
||||||
|
</ToggleButton.Button>
|
||||||
|
<ToggleButton.Button name="ignore" label={labels.show}>
|
||||||
|
{labels.show}
|
||||||
|
</ToggleButton.Button>
|
||||||
|
</ToggleButton.Group>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,32 +1,22 @@
|
|||||||
import React, {useMemo, useCallback} from 'react'
|
import React from 'react'
|
||||||
import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native'
|
import {Dimensions, View} from 'react-native'
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
import {useIsFocused, useNavigation} from '@react-navigation/native'
|
import {AppBskyModerationDefs} from '@atproto/api'
|
||||||
import {AppBskyModerationDefs, RichText as RichTextAPI} from '@atproto/api'
|
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
|
||||||
import {HeartIcon, HeartIconSolid} from 'lib/icons'
|
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {CommonNavigatorParams} from 'lib/routes/types'
|
|
||||||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
|
||||||
import {s} from 'lib/styles'
|
|
||||||
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
|
||||||
import {TextLink} from 'view/com/util/Link'
|
|
||||||
import {Button as OldButton} from 'view/com/util/forms/Button'
|
|
||||||
import {Text as RNText} from 'view/com/util/text/Text'
|
|
||||||
import {ModServicePrefs} from '#/view/com/moderation/ModServicePrefs'
|
|
||||||
import * as Toast from 'view/com/util/Toast'
|
|
||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
|
||||||
import {Haptics} from 'lib/haptics'
|
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
|
||||||
import {makeCustomFeedLink} from 'lib/routes/links'
|
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
|
||||||
import {CenteredView, ScrollView} from 'view/com/util/Views'
|
|
||||||
import {NavigationProp} from 'lib/routes/types'
|
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {Trans, msg} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useModalControls} from '#/state/modals'
|
|
||||||
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
|
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||||
|
import {s} from '#/lib/styles'
|
||||||
|
import {TextLink} from '#/view/com/util/Link'
|
||||||
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
|
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||||
|
import {Haptics} from '#/lib/haptics'
|
||||||
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
|
import {pluralize} from '#/lib/strings/helpers'
|
||||||
|
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||||
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
|
import {logger} from '#/logger'
|
||||||
import {useModServiceInfoQuery} from '#/state/queries/modservice'
|
import {useModServiceInfoQuery} from '#/state/queries/modservice'
|
||||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||||
import {
|
import {
|
||||||
@@ -40,14 +30,18 @@ import {sanitizeHandle} from '#/lib/strings/handles'
|
|||||||
import {useTheme, atoms as a} from '#/alf'
|
import {useTheme, atoms as a} from '#/alf'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Button, ButtonText} from '#/components/Button'
|
import {Button} from '#/components/Button'
|
||||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
import {
|
||||||
import {Heart2_Stroke2_Corner0_Rounded as Heart, Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled} from '#/components/icons/Heart2'
|
Heart2_Stroke2_Corner0_Rounded as Heart,
|
||||||
|
Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled,
|
||||||
|
} from '#/components/icons/Heart2'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {InlineLink} from '#/components/Link'
|
import {InlineLink} from '#/components/Link'
|
||||||
|
import {Divider} from '#/components/Divider'
|
||||||
|
|
||||||
import {ErrorState} from '#/screens/ProfileModerationService/ErrorState'
|
import {ErrorState} from '#/screens/ProfileModerationService/ErrorState'
|
||||||
import {Header} from '#/screens/ProfileModerationService/Header'
|
import {Header} from '#/screens/ProfileModerationService/Header'
|
||||||
|
import {PreferenceRow} from '#/screens/ProfileModerationService/PreferenceRow'
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
const MIN_HEIGHT = Dimensions.get('window').height * 1.5
|
const MIN_HEIGHT = Dimensions.get('window').height * 1.5
|
||||||
@@ -125,7 +119,7 @@ function ProfileModservicecreenIntermediate({modDid}: {modDid: string}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ProfileModserviceScreenInner({
|
export function ProfileModserviceScreenInner({
|
||||||
preferences,
|
// preferences,
|
||||||
modInfo,
|
modInfo,
|
||||||
}: {
|
}: {
|
||||||
preferences: UsePreferencesQueryResponse
|
preferences: UsePreferencesQueryResponse
|
||||||
@@ -144,10 +138,10 @@ export function ProfileModserviceScreenInner({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isLiked = !!likeUri
|
const isLiked = !!likeUri
|
||||||
const isSaved = false // TODO
|
// const isSaved = false // TODO
|
||||||
// !removedFeed &&
|
// !removedFeed &&
|
||||||
// (!!savedFeed || preferences.feeds.saved.includes(feedInfo.uri))
|
// (!!savedFeed || preferences.feeds.saved.includes(feedInfo.uri))
|
||||||
const isEnabled = false // TODO
|
// const isEnabled = false // TODO
|
||||||
// !unpinnedFeed &&
|
// !unpinnedFeed &&
|
||||||
// (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri))
|
// (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri))
|
||||||
|
|
||||||
@@ -207,7 +201,13 @@ export function ProfileModserviceScreenInner({
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Text style={[a.text_md, a.leading_normal, a.italic, t.atoms.text_contrast_700]}>
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_md,
|
||||||
|
a.leading_normal,
|
||||||
|
a.italic,
|
||||||
|
t.atoms.text_contrast_700,
|
||||||
|
]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Operated by{' '}
|
Operated by{' '}
|
||||||
<TextLink
|
<TextLink
|
||||||
@@ -223,10 +223,10 @@ export function ProfileModserviceScreenInner({
|
|||||||
<View style={[a.flex_row, a.gap_md, a.align_center]}>
|
<View style={[a.flex_row, a.gap_md, a.align_center]}>
|
||||||
<Button
|
<Button
|
||||||
testID="toggleLikeBtn"
|
testID="toggleLikeBtn"
|
||||||
size='small'
|
size="small"
|
||||||
color='secondary'
|
color="secondary"
|
||||||
variant='solid'
|
variant="solid"
|
||||||
shape='round'
|
shape="round"
|
||||||
label={_(msg`Like this feed`)}
|
label={_(msg`Like this feed`)}
|
||||||
disabled={!hasSession || isLikePending || isUnlikePending}
|
disabled={!hasSession || isLikePending || isUnlikePending}
|
||||||
onPress={onToggleLiked}>
|
onPress={onToggleLiked}>
|
||||||
@@ -238,17 +238,24 @@ export function ProfileModserviceScreenInner({
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{typeof modInfo.likeCount === 'number' && (
|
{typeof modInfo.likeCount === 'number' && (
|
||||||
<InlineLink
|
<InlineLink to={'#todo'} style={[pal.textLight, s.semiBold]}>
|
||||||
to={'#todo'}
|
<Trans>
|
||||||
style={[pal.textLight, s.semiBold]}
|
Liked by {modInfo.likeCount}{' '}
|
||||||
>
|
{pluralize(modInfo.likeCount, 'user')}
|
||||||
<Trans>Liked by {modInfo.likeCount} {pluralize(modInfo.likeCount, 'user')}</Trans>
|
</Trans>
|
||||||
</InlineLink>
|
</InlineLink>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<ModServicePrefs />
|
<View style={[a.gap_md, a.mt_xl]}>
|
||||||
|
<Divider />
|
||||||
|
<PreferenceRow labelGroup="nsfw" />
|
||||||
|
<Divider />
|
||||||
|
<PreferenceRow labelGroup="nudity" />
|
||||||
|
<Divider />
|
||||||
|
<PreferenceRow labelGroup="suggestive" />
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={{height: 20}} />
|
<View style={{height: 20}} />
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|||||||
@@ -1,68 +1,73 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleSheet, View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {RichText as RichTextAPI} from '@atproto/api'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {HandIcon} from '#/lib/icons'
|
|
||||||
import {Trans, msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import LinearGradient from 'react-native-linear-gradient'
|
||||||
import {Text} from '../util/text/Text'
|
|
||||||
import {RichText} from '../util/text/RichText'
|
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
|
||||||
import {s, colors} from 'lib/styles'
|
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
|
||||||
|
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a, useTheme, tokens, web} from '#/alf'
|
||||||
import {Link} from '#/components/Link'
|
import {Link, useLinkContext} from '#/components/Link'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
const richtext = new RichTextAPI({
|
import {RichText} from '#/components/RichText'
|
||||||
text: "Bluesky's official moderation service",
|
import {RaisingHande4Finger_Stroke2_Corner0_Rounded as RaisingHand} from '#/components/icons/RaisingHand'
|
||||||
})
|
|
||||||
|
|
||||||
export function ProfileHeaderModCard() {
|
export function ProfileHeaderModCard() {
|
||||||
const pal = usePalette('default')
|
const {_} = useLingui()
|
||||||
const {isMobile} = useWebMediaQueries()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to='/profile/alice.test/modservice' style={[a.flex_row]}>
|
<Link
|
||||||
<View
|
to="/profile/alice.test/modservice"
|
||||||
style={[
|
label={_(msg`View the moderation service provided by this profile`)}>
|
||||||
a.w_full,
|
<Inner />
|
||||||
pal.view,
|
|
||||||
pal.borderDark,
|
|
||||||
s.mt5,
|
|
||||||
{
|
|
||||||
borderWidth: 1,
|
|
||||||
borderRadius: 8,
|
|
||||||
paddingVertical: 10,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<View style={[s.flexRow, s.alignCenter, {gap: 8}]}>
|
|
||||||
{!isMobile && <HandIcon style={pal.text} size={24} strokeWidth={5.5} />}
|
|
||||||
<View style={{flex: 1}}>
|
|
||||||
<Text type="lg-bold" style={pal.text}>
|
|
||||||
<Trans>Moderation service</Trans>
|
|
||||||
</Text>
|
|
||||||
<RichText richText={richtext} />
|
|
||||||
</View>
|
|
||||||
{isMobile ? (
|
|
||||||
<HandIcon style={pal.text} size={24} strokeWidth={5.5} />
|
|
||||||
) : (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
pal.viewLight,
|
|
||||||
{paddingHorizontal: 12, paddingVertical: 6, borderRadius: 24},
|
|
||||||
]}>
|
|
||||||
<Text type="button" style={pal.text}>
|
|
||||||
<Trans>View</Trans>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({})
|
function Inner() {
|
||||||
|
const t = useTheme()
|
||||||
|
const {hovered, pressed, focused} = useLinkContext()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.justify_between,
|
||||||
|
a.gap_sm,
|
||||||
|
a.w_full,
|
||||||
|
a.rounded_sm,
|
||||||
|
a.pt_md,
|
||||||
|
a.pb_sm,
|
||||||
|
a.pl_lg,
|
||||||
|
a.pr_sm,
|
||||||
|
a.overflow_hidden,
|
||||||
|
web({
|
||||||
|
transition: 'transform 0.2s cubic-bezier(.02,.73,.27,.99)',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
transform: [{scale: pressed || hovered || focused ? 0.992 : 1}],
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={tokens.gradients.bonfire.values.map(c => c[1])}
|
||||||
|
locations={tokens.gradients.bonfire.values.map(c => c[0])}
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 1, y: 1}}
|
||||||
|
style={[a.absolute, a.inset_0]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={[a.z_10]}>
|
||||||
|
<Text
|
||||||
|
style={[a.text_md, a.font_bold, a.pb_2xs, {color: t.palette.white}]}>
|
||||||
|
<Trans>Moderation service</Trans>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<RichText
|
||||||
|
value={'Moderation service managed by bsky.app'}
|
||||||
|
style={[{color: t.palette.white}]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<RaisingHand size="xl" style={[a.z_10]} fill={t.palette.white} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,280 +0,0 @@
|
|||||||
import React, {useMemo, useCallback} from 'react'
|
|
||||||
import {Dimensions, StyleSheet, View, ActivityIndicator} from 'react-native'
|
|
||||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
|
||||||
import {useIsFocused, useNavigation} from '@react-navigation/native'
|
|
||||||
import {AppBskyModerationDefs, RichText as RichTextAPI} from '@atproto/api'
|
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
|
||||||
import {HeartIcon, HeartIconSolid} from 'lib/icons'
|
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|
||||||
import {CommonNavigatorParams} from 'lib/routes/types'
|
|
||||||
import {makeRecordUri} from 'lib/strings/url-helpers'
|
|
||||||
import {s} from 'lib/styles'
|
|
||||||
import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader'
|
|
||||||
import {TextLink} from 'view/com/util/Link'
|
|
||||||
import {Button} from 'view/com/util/forms/Button'
|
|
||||||
import {Text} from 'view/com/util/text/Text'
|
|
||||||
import {RichText} from 'view/com/util/text/RichText'
|
|
||||||
import {ModServicePrefs} from '../com/moderation/ModServicePrefs'
|
|
||||||
import * as Toast from 'view/com/util/Toast'
|
|
||||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
|
||||||
import {Haptics} from 'lib/haptics'
|
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
|
||||||
import {makeCustomFeedLink} from 'lib/routes/links'
|
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
|
||||||
import {CenteredView, ScrollView} from 'view/com/util/Views'
|
|
||||||
import {NavigationProp} from 'lib/routes/types'
|
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
|
||||||
import {logger} from '#/logger'
|
|
||||||
import {Trans, msg} from '@lingui/macro'
|
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
import {useModalControls} from '#/state/modals'
|
|
||||||
import {useModServiceInfoQuery} from '#/state/queries/modservice'
|
|
||||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
|
||||||
import {
|
|
||||||
UsePreferencesQueryResponse,
|
|
||||||
usePreferencesQuery,
|
|
||||||
} from '#/state/queries/preferences'
|
|
||||||
import {useSession} from '#/state/session'
|
|
||||||
import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like'
|
|
||||||
import {ModServiceHeader} from '../com/moderation/ModServiceHeader'
|
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileModservice'>
|
|
||||||
export function ProfileModserviceScreen(props: Props) {
|
|
||||||
const {name: handleOrDid} = props.route.params
|
|
||||||
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const {_} = useLingui()
|
|
||||||
const navigation = useNavigation<NavigationProp>()
|
|
||||||
|
|
||||||
const {error, data: resolvedDid} = useResolveDidQuery(handleOrDid)
|
|
||||||
|
|
||||||
const onPressBack = React.useCallback(() => {
|
|
||||||
if (navigation.canGoBack()) {
|
|
||||||
navigation.goBack()
|
|
||||||
} else {
|
|
||||||
navigation.navigate('Home')
|
|
||||||
}
|
|
||||||
}, [navigation])
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<CenteredView>
|
|
||||||
<View style={[pal.view, pal.border, styles.notFoundContainer]}>
|
|
||||||
<Text type="title-lg" style={[pal.text, s.mb10]}>
|
|
||||||
<Trans>Could not load moderation service</Trans>
|
|
||||||
</Text>
|
|
||||||
<Text type="md" style={[pal.text, s.mb20]}>
|
|
||||||
{error.toString()}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View style={{flexDirection: 'row'}}>
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
accessibilityLabel={_(msg`Go Back`)}
|
|
||||||
accessibilityHint="Return to previous page"
|
|
||||||
onPress={onPressBack}
|
|
||||||
style={{flexShrink: 1}}>
|
|
||||||
<Text type="button" style={pal.text}>
|
|
||||||
<Trans>Go Back</Trans>
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</CenteredView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolvedDid ? (
|
|
||||||
<ProfileModservicecreenIntermediate modDid={resolvedDid} />
|
|
||||||
) : (
|
|
||||||
<CenteredView>
|
|
||||||
<View style={s.p20}>
|
|
||||||
<ActivityIndicator size="large" />
|
|
||||||
</View>
|
|
||||||
</CenteredView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function ProfileModservicecreenIntermediate({modDid}: {modDid: string}) {
|
|
||||||
const {data: preferences} = usePreferencesQuery()
|
|
||||||
const {data: info} = useModServiceInfoQuery({did: modDid})
|
|
||||||
|
|
||||||
if (!preferences || !info) {
|
|
||||||
return (
|
|
||||||
<CenteredView>
|
|
||||||
<View style={s.p20}>
|
|
||||||
<ActivityIndicator size="large" />
|
|
||||||
</View>
|
|
||||||
</CenteredView>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ProfileModserviceScreenInner preferences={preferences} modInfo={info} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ProfileModserviceScreenInner({
|
|
||||||
preferences,
|
|
||||||
modInfo,
|
|
||||||
}: {
|
|
||||||
preferences: UsePreferencesQueryResponse
|
|
||||||
modInfo: AppBskyModerationDefs.ModServiceViewDetailed
|
|
||||||
}) {
|
|
||||||
const {_} = useLingui()
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const {hasSession} = useSession()
|
|
||||||
const {track} = useAnalytics()
|
|
||||||
const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation()
|
|
||||||
const {mutateAsync: unlikeMod, isPending: isUnlikePending} =
|
|
||||||
useUnlikeMutation()
|
|
||||||
const [likeUri, setLikeUri] = React.useState<string>(
|
|
||||||
modInfo.viewer?.like || '',
|
|
||||||
)
|
|
||||||
|
|
||||||
const isLiked = !!likeUri
|
|
||||||
const isSaved = false // TODO
|
|
||||||
// !removedFeed &&
|
|
||||||
// (!!savedFeed || preferences.feeds.saved.includes(feedInfo.uri))
|
|
||||||
const isEnabled = false // TODO
|
|
||||||
// !unpinnedFeed &&
|
|
||||||
// (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri))
|
|
||||||
|
|
||||||
const descriptionRT = useMemo(
|
|
||||||
() =>
|
|
||||||
modInfo.description
|
|
||||||
? new RichTextAPI({
|
|
||||||
text: modInfo.description,
|
|
||||||
facets: modInfo.descriptionFacets,
|
|
||||||
})
|
|
||||||
: undefined,
|
|
||||||
[modInfo],
|
|
||||||
)
|
|
||||||
|
|
||||||
useSetTitle(modInfo.creator.displayName || modInfo.creator.handle)
|
|
||||||
|
|
||||||
// event handlers
|
|
||||||
//
|
|
||||||
const onToggleLiked = React.useCallback(async () => {
|
|
||||||
try {
|
|
||||||
Haptics.default()
|
|
||||||
|
|
||||||
if (isLiked && likeUri) {
|
|
||||||
await unlikeMod({uri: likeUri})
|
|
||||||
track('CustomFeed:Unlike')
|
|
||||||
setLikeUri('')
|
|
||||||
} else {
|
|
||||||
const res = await likeMod({uri: modInfo.uri, cid: modInfo.cid})
|
|
||||||
track('CustomFeed:Like')
|
|
||||||
setLikeUri(res.uri)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
Toast.show(
|
|
||||||
_(
|
|
||||||
msg`There was an an issue contacting the server, please check your internet connection and try again.`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
logger.error('Failed up toggle like', {error: err})
|
|
||||||
}
|
|
||||||
}, [likeUri, isLiked, modInfo, likeMod, unlikeMod, track, _])
|
|
||||||
|
|
||||||
// render
|
|
||||||
// =
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={s.hContentRegion}>
|
|
||||||
<ScrollView
|
|
||||||
scrollEventThrottle={1}
|
|
||||||
contentContainerStyle={{
|
|
||||||
minHeight: Dimensions.get('window').height * 1.5,
|
|
||||||
}}>
|
|
||||||
<ModServiceHeader info={modInfo} />
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
{
|
|
||||||
borderTopWidth: 1,
|
|
||||||
paddingVertical: 20,
|
|
||||||
paddingHorizontal: 14,
|
|
||||||
gap: 12,
|
|
||||||
},
|
|
||||||
pal.border,
|
|
||||||
]}>
|
|
||||||
{descriptionRT ? (
|
|
||||||
<RichText
|
|
||||||
testID="modinfoDescription"
|
|
||||||
type="lg"
|
|
||||||
style={pal.text}
|
|
||||||
richText={descriptionRT}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Text type="lg" style={[{fontStyle: 'italic'}, pal.textLight]}>
|
|
||||||
<Trans>No description</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<Text type="lg" style={pal.textLight}>
|
|
||||||
<Trans>
|
|
||||||
Operated by{' '}
|
|
||||||
<TextLink
|
|
||||||
href={makeProfileLink(modInfo.creator)}
|
|
||||||
text={sanitizeHandle(modInfo.creator.handle, '@')}
|
|
||||||
style={pal.link}
|
|
||||||
/>
|
|
||||||
. Handles reports of anti-social behavior, illegal content,
|
|
||||||
unwanted sexual content, and misinformation.
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
|
|
||||||
<Button
|
|
||||||
type="default"
|
|
||||||
testID="toggleLikeBtn"
|
|
||||||
accessibilityLabel={_(msg`Like this feed`)}
|
|
||||||
accessibilityHint=""
|
|
||||||
disabled={!hasSession || isLikePending || isUnlikePending}
|
|
||||||
onPress={onToggleLiked}
|
|
||||||
style={{paddingHorizontal: 10}}>
|
|
||||||
{isLiked ? (
|
|
||||||
<HeartIconSolid size={19} style={s.likeColor} />
|
|
||||||
) : (
|
|
||||||
<HeartIcon strokeWidth={3} size={19} style={pal.textLight} />
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
{typeof modInfo.likeCount === 'number' && (
|
|
||||||
<TextLink
|
|
||||||
href={'#todo'}
|
|
||||||
text={_(
|
|
||||||
msg`Liked by ${modInfo.likeCount} ${pluralize(
|
|
||||||
modInfo.likeCount,
|
|
||||||
'user',
|
|
||||||
)}`,
|
|
||||||
)}
|
|
||||||
style={[pal.textLight, s.semiBold]}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<ModServicePrefs />
|
|
||||||
<View style={{height: 20}} />
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
btn: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: 6,
|
|
||||||
paddingVertical: 7,
|
|
||||||
paddingHorizontal: 14,
|
|
||||||
borderRadius: 50,
|
|
||||||
marginLeft: 6,
|
|
||||||
},
|
|
||||||
notFoundContainer: {
|
|
||||||
margin: 10,
|
|
||||||
paddingHorizontal: 18,
|
|
||||||
paddingVertical: 14,
|
|
||||||
borderRadius: 6,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user