Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[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 bc454dad896fe577bec91f3d65d971ad9e0fec8d.

* Hide Follow button if followedBy rule enabled

* Revert "Revert "Handle follow case""

This reverts commit cadc46d2dc50120424ed460943775c58efc59c4d.

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

authored by

Eric Bailey
Samuel Newman
and committed by
GitHub
459611ca 03f75e8f

+94 -13
+1 -1
package.json
··· 56 56 "icons:optimize": "svgo -f ./assets/icons" 57 57 }, 58 58 "dependencies": { 59 - "@atproto/api": "^0.13.33", 59 + "@atproto/api": "^0.13.35", 60 60 "@bitdrift/react-native": "^0.6.2", 61 61 "@braintree/sanitize-url": "^6.0.2", 62 62 "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
+13
src/components/WhoCanReply.tsx
··· 258 258 if (rule.type === 'mention') { 259 259 return <Trans>mentioned users</Trans> 260 260 } 261 + if (rule.type === 'followers') { 262 + return ( 263 + <Trans> 264 + users following{' '} 265 + <InlineLinkText 266 + label={`@${post.author.handle}`} 267 + to={makeProfileLink(post.author)} 268 + style={[a.text_sm, a.leading_snug]}> 269 + @{post.author.handle} 270 + </InlineLinkText> 271 + </Trans> 272 + ) 273 + } 261 274 if (rule.type === 'following') { 262 275 return ( 263 276 <Trans>
+11 -1
src/components/dialogs/PostInteractionSettingsDialog.tsx
··· 429 429 disabled={replySettingsDisabled} 430 430 /> 431 431 <Selectable 432 - label={_(msg`Followed users`)} 432 + label={_(msg`Users you follow`)} 433 433 isSelected={ 434 434 !!threadgateAllowUISettings.find( 435 435 v => v.type === 'following', 436 436 ) 437 437 } 438 438 onPress={() => onPressAudience({type: 'following'})} 439 + disabled={replySettingsDisabled} 440 + /> 441 + <Selectable 442 + label={_(msg`Your followers`)} 443 + isSelected={ 444 + !!threadgateAllowUISettings.find( 445 + v => v.type === 'followers', 446 + ) 447 + } 448 + onPress={() => onPressAudience({type: 'followers'})} 439 449 disabled={replySettingsDisabled} 440 450 /> 441 451 {lists && lists.length > 0
+1
src/state/queries/threadgate/types.ts
··· 3 3 | {type: 'nobody'} 4 4 | {type: 'mention'} 5 5 | {type: 'following'} 6 + | {type: 'followers'} 6 7 | {type: 'list'; list: unknown}
+4
src/state/queries/threadgate/util.ts
··· 43 43 setting = {type: 'mention'} 44 44 } else if (allow.$type === 'app.bsky.feed.threadgate#followingRule') { 45 45 setting = {type: 'following'} 46 + } else if (allow.$type === 'app.bsky.feed.threadgate#followerRule') { 47 + setting = {type: 'followers'} 46 48 } else if (allow.$type === 'app.bsky.feed.threadgate#listRule') { 47 49 setting = {type: 'list', list: allow.list} 48 50 } ··· 79 81 allow.push({$type: 'app.bsky.feed.threadgate#mentionRule'}) 80 82 } else if (rule.type === 'following') { 81 83 allow.push({$type: 'app.bsky.feed.threadgate#followingRule'}) 84 + } else if (rule.type === 'followers') { 85 + allow.push({$type: 'app.bsky.feed.threadgate#followerRule'}) 82 86 } else if (rule.type === 'list') { 83 87 allow.push({ 84 88 $type: 'app.bsky.feed.threadgate#listRule',
+6 -1
src/view/com/post-thread/PostThreadItem.tsx
··· 241 241 return makeProfileLink(post.author, 'post', urip.rkey, 'quotes') 242 242 }, [post.uri, post.author]) 243 243 const quotesTitle = _(msg`Quotes of this post`) 244 + const onlyFollowersCanReply = !!threadgateRecord?.allow?.find( 245 + rule => rule.$type === 'app.bsky.feed.threadgate#followerRule', 246 + ) 247 + const showFollowButton = 248 + currentAccount?.did !== post.author.did && !onlyFollowersCanReply 244 249 245 250 const translatorUrl = getTranslatorLink( 246 251 record?.text || '', ··· 343 348 </Text> 344 349 </Link> 345 350 </View> 346 - {currentAccount?.did !== post.author.did && ( 351 + {showFollowButton && ( 347 352 <View> 348 353 <PostThreadFollowBtn did={post.author.did} /> 349 354 </View>
+12 -2
src/view/com/util/post-ctrls/PostCtrls.tsx
··· 26 26 import {shareUrl} from '#/lib/sharing' 27 27 import {useGate} from '#/lib/statsig/statsig' 28 28 import {toShareUrl} from '#/lib/strings/url-helpers' 29 + import {useProfileShadow} from '#/state/cache/profile-shadow' 29 30 import {Shadow} from '#/state/cache/types' 30 31 import {useFeedFeedbackContext} from '#/state/feed-feedback' 31 32 import { ··· 93 94 post.author.viewer?.blockedBy || 94 95 post.author.viewer?.blockingByList, 95 96 ) 97 + 98 + const shadowedAuthor = useProfileShadow(post.author) 99 + const followersCanReply = !!threadgateRecord?.allow?.find( 100 + rule => rule.$type === 'app.bsky.feed.threadgate#followerRule', 101 + ) 102 + const canOverrideReplyDisabled = 103 + followersCanReply && 104 + shadowedAuthor.viewer?.following?.startsWith('at://did') 105 + const replyDisabled = post.viewer?.replyDisabled && !canOverrideReplyDisabled 96 106 97 107 const shouldShowLoggedOutWarning = React.useMemo(() => { 98 108 return ( ··· 247 257 <View 248 258 style={[ 249 259 big ? a.align_center : [a.flex_1, a.align_start, {marginLeft: -6}], 250 - post.viewer?.replyDisabled ? {opacity: 0.5} : undefined, 260 + replyDisabled ? {opacity: 0.5} : undefined, 251 261 ]}> 252 262 <Pressable 253 263 testID="replyBtn" 254 264 style={btnStyle} 255 265 onPress={() => { 256 - if (!post.viewer?.replyDisabled) { 266 + if (!replyDisabled) { 257 267 playHaptic('Light') 258 268 requireAuth(() => onPressReply()) 259 269 }
+46 -8
yarn.lock
··· 72 72 tlds "^1.234.0" 73 73 zod "^3.23.8" 74 74 75 - "@atproto/api@^0.13.33": 76 - version "0.13.33" 77 - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.33.tgz#01d31a1cfd1be311e11324b810b8a83fe4cbf9b0" 78 - integrity sha512-d8AOvtxo2J2zrmcakJTUtLdz2ns+pAqywNXhPxPzHrHcw79D6MKBLHR0vr8oxkGwhDBQTsHiQWTk4gSo8PF7YA== 75 + "@atproto/api@^0.13.35": 76 + version "0.13.35" 77 + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.35.tgz#1e3a6c6e035c8e06302508983ed206effc92a7e8" 78 + integrity sha512-vsEfBj0C333TLjDppvTdTE0IdKlXuljKSveAeI4PPx/l6eUKNnDTsYxvILtXUVzwUlTDmSRqy5O4Ryh78n1b7g== 79 79 dependencies: 80 80 "@atproto/common-web" "^0.4.0" 81 81 "@atproto/lexicon" "^0.4.6" ··· 3295 3295 "@babel/parser" "^7.25.9" 3296 3296 "@babel/types" "^7.25.9" 3297 3297 3298 - "@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3", "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9": 3298 + "@babel/traverse--for-generate-function-map@npm:@babel/traverse@^7.25.3": 3299 3299 version "7.25.9" 3300 3300 resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" 3301 3301 integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== ··· 3353 3353 "@babel/helper-split-export-declaration" "^7.24.5" 3354 3354 "@babel/parser" "^7.24.5" 3355 3355 "@babel/types" "^7.24.5" 3356 + debug "^4.3.1" 3357 + globals "^11.1.0" 3358 + 3359 + "@babel/traverse@^7.25.3", "@babel/traverse@^7.25.9": 3360 + version "7.25.9" 3361 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.9.tgz#a50f8fe49e7f69f53de5bea7e413cd35c5e13c84" 3362 + integrity sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw== 3363 + dependencies: 3364 + "@babel/code-frame" "^7.25.9" 3365 + "@babel/generator" "^7.25.9" 3366 + "@babel/parser" "^7.25.9" 3367 + "@babel/template" "^7.25.9" 3368 + "@babel/types" "^7.25.9" 3356 3369 debug "^4.3.1" 3357 3370 globals "^11.1.0" 3358 3371 ··· 17644 17657 resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" 17645 17658 integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== 17646 17659 17647 - "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: 17660 + "string-width-cjs@npm:string-width@^4.2.0": 17661 + version "4.2.3" 17662 + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 17663 + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 17664 + dependencies: 17665 + emoji-regex "^8.0.0" 17666 + is-fullwidth-code-point "^3.0.0" 17667 + strip-ansi "^6.0.1" 17668 + 17669 + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: 17648 17670 version "4.2.3" 17649 17671 resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 17650 17672 integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== ··· 17744 17766 dependencies: 17745 17767 safe-buffer "~5.1.0" 17746 17768 17747 - "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: 17769 + "strip-ansi-cjs@npm:strip-ansi@^6.0.1": 17748 17770 version "6.0.1" 17749 17771 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 17750 17772 integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== ··· 17757 17779 integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 17758 17780 dependencies: 17759 17781 ansi-regex "^4.1.0" 17782 + 17783 + strip-ansi@^6.0.0, strip-ansi@^6.0.1: 17784 + version "6.0.1" 17785 + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 17786 + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 17787 + dependencies: 17788 + ansi-regex "^5.0.1" 17760 17789 17761 17790 strip-ansi@^7.0.1: 17762 17791 version "7.1.0" ··· 19032 19061 resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 19033 19062 integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== 19034 19063 19035 - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: 19064 + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": 19036 19065 version "7.0.0" 19037 19066 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 19038 19067 integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== ··· 19045 19074 version "6.2.0" 19046 19075 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" 19047 19076 integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== 19077 + dependencies: 19078 + ansi-styles "^4.0.0" 19079 + string-width "^4.1.0" 19080 + strip-ansi "^6.0.0" 19081 + 19082 + wrap-ansi@^7.0.0: 19083 + version "7.0.0" 19084 + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 19085 + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 19048 19086 dependencies: 19049 19087 ansi-styles "^4.0.0" 19050 19088 string-width "^4.1.0"