[APP-1031] Add new followerRule to threadgate settings (#7681)

* Add new followerRule to threadgate settings

* Handle WhoCanReply copy

* Handle follow case

* fix ci

* Revert "Handle follow case"

This reverts commit bc454dad89.

* Hide Follow button if followedBy rule enabled

* Revert "Revert "Handle follow case""

This reverts commit cadc46d2dc.

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
Eric Bailey
2025-02-11 16:07:10 -06:00
committed by GitHub
parent 03f75e8ff4
commit 459611ca7a
8 changed files with 94 additions and 13 deletions
+13
View File
@@ -258,6 +258,19 @@ function Rule({
if (rule.type === 'mention') {
return <Trans>mentioned users</Trans>
}
if (rule.type === 'followers') {
return (
<Trans>
users following{' '}
<InlineLinkText
label={`@${post.author.handle}`}
to={makeProfileLink(post.author)}
style={[a.text_sm, a.leading_snug]}>
@{post.author.handle}
</InlineLinkText>
</Trans>
)
}
if (rule.type === 'following') {
return (
<Trans>
@@ -429,7 +429,7 @@ export function PostInteractionSettingsForm({
disabled={replySettingsDisabled}
/>
<Selectable
label={_(msg`Followed users`)}
label={_(msg`Users you follow`)}
isSelected={
!!threadgateAllowUISettings.find(
v => v.type === 'following',
@@ -438,6 +438,16 @@ export function PostInteractionSettingsForm({
onPress={() => onPressAudience({type: 'following'})}
disabled={replySettingsDisabled}
/>
<Selectable
label={_(msg`Your followers`)}
isSelected={
!!threadgateAllowUISettings.find(
v => v.type === 'followers',
)
}
onPress={() => onPressAudience({type: 'followers'})}
disabled={replySettingsDisabled}
/>
{lists && lists.length > 0
? lists.map(list => (
<Selectable
+1
View File
@@ -3,4 +3,5 @@ export type ThreadgateAllowUISetting =
| {type: 'nobody'}
| {type: 'mention'}
| {type: 'following'}
| {type: 'followers'}
| {type: 'list'; list: unknown}
+4
View File
@@ -43,6 +43,8 @@ export function threadgateRecordToAllowUISetting(
setting = {type: 'mention'}
} else if (allow.$type === 'app.bsky.feed.threadgate#followingRule') {
setting = {type: 'following'}
} else if (allow.$type === 'app.bsky.feed.threadgate#followerRule') {
setting = {type: 'followers'}
} else if (allow.$type === 'app.bsky.feed.threadgate#listRule') {
setting = {type: 'list', list: allow.list}
}
@@ -79,6 +81,8 @@ export function threadgateAllowUISettingToAllowRecordValue(
allow.push({$type: 'app.bsky.feed.threadgate#mentionRule'})
} else if (rule.type === 'following') {
allow.push({$type: 'app.bsky.feed.threadgate#followingRule'})
} else if (rule.type === 'followers') {
allow.push({$type: 'app.bsky.feed.threadgate#followerRule'})
} else if (rule.type === 'list') {
allow.push({
$type: 'app.bsky.feed.threadgate#listRule',
+6 -1
View File
@@ -241,6 +241,11 @@ let PostThreadItemLoaded = ({
return makeProfileLink(post.author, 'post', urip.rkey, 'quotes')
}, [post.uri, post.author])
const quotesTitle = _(msg`Quotes of this post`)
const onlyFollowersCanReply = !!threadgateRecord?.allow?.find(
rule => rule.$type === 'app.bsky.feed.threadgate#followerRule',
)
const showFollowButton =
currentAccount?.did !== post.author.did && !onlyFollowersCanReply
const translatorUrl = getTranslatorLink(
record?.text || '',
@@ -343,7 +348,7 @@ let PostThreadItemLoaded = ({
</Text>
</Link>
</View>
{currentAccount?.did !== post.author.did && (
{showFollowButton && (
<View>
<PostThreadFollowBtn did={post.author.did} />
</View>
+12 -2
View File
@@ -26,6 +26,7 @@ import {makeProfileLink} from '#/lib/routes/links'
import {shareUrl} from '#/lib/sharing'
import {useGate} from '#/lib/statsig/statsig'
import {toShareUrl} from '#/lib/strings/url-helpers'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {Shadow} from '#/state/cache/types'
import {useFeedFeedbackContext} from '#/state/feed-feedback'
import {
@@ -94,6 +95,15 @@ let PostCtrls = ({
post.author.viewer?.blockingByList,
)
const shadowedAuthor = useProfileShadow(post.author)
const followersCanReply = !!threadgateRecord?.allow?.find(
rule => rule.$type === 'app.bsky.feed.threadgate#followerRule',
)
const canOverrideReplyDisabled =
followersCanReply &&
shadowedAuthor.viewer?.following?.startsWith('at://did')
const replyDisabled = post.viewer?.replyDisabled && !canOverrideReplyDisabled
const shouldShowLoggedOutWarning = React.useMemo(() => {
return (
post.author.did !== currentAccount?.did &&
@@ -247,13 +257,13 @@ let PostCtrls = ({
<View
style={[
big ? a.align_center : [a.flex_1, a.align_start, {marginLeft: -6}],
post.viewer?.replyDisabled ? {opacity: 0.5} : undefined,
replyDisabled ? {opacity: 0.5} : undefined,
]}>
<Pressable
testID="replyBtn"
style={btnStyle}
onPress={() => {
if (!post.viewer?.replyDisabled) {
if (!replyDisabled) {
playHaptic('Light')
requireAuth(() => onPressReply())
}