about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/WhoCanReply.tsx (renamed from src/view/com/threadgate/WhoCanReply.tsx)95
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx305
2 files changed, 164 insertions, 236 deletions
diff --git a/src/view/com/threadgate/WhoCanReply.tsx b/src/components/WhoCanReply.tsx
index 3f9970f5f..cd171a0a4 100644
--- a/src/view/com/threadgate/WhoCanReply.tsx
+++ b/src/components/WhoCanReply.tsx
@@ -33,7 +33,8 @@ import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/componen
 import {Earth_Stroke2_Corner0_Rounded as Earth} from '#/components/icons/Globe'
 import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
 import {Text} from '#/components/Typography'
-import {TextLink} from '../util/Link'
+import {TextLink} from '../view/com/util/Link'
+import {PencilLine_Stroke2_Corner0_Rounded as PencilLine} from './icons/Pencil'
 
 interface WhoCanReplyProps {
   post: AppBskyFeedDefs.PostView
@@ -41,11 +42,7 @@ interface WhoCanReplyProps {
   style?: StyleProp<ViewStyle>
 }
 
-export function WhoCanReplyInline({
-  post,
-  isThreadAuthor,
-  style,
-}: WhoCanReplyProps) {
+export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
   const {_} = useLingui()
   const t = useTheme()
   const infoDialogControl = useDialogControl()
@@ -90,73 +87,13 @@ export function WhoCanReplyInline({
               ]}>
               {description}
             </Text>
+            {isThreadAuthor && (
+              <PencilLine width={12} fill={t.palette.primary_500} />
+            )}
           </View>
         )}
       </Button>
-      <InfoDialog control={infoDialogControl} post={post} settings={settings} />
-    </>
-  )
-}
-
-export function WhoCanReplyBlock({
-  post,
-  isThreadAuthor,
-  style,
-}: WhoCanReplyProps) {
-  const {_} = useLingui()
-  const t = useTheme()
-  const infoDialogControl = useDialogControl()
-  const {settings, isRootPost, onPressEdit} = useWhoCanReply(post)
-
-  if (!isRootPost) {
-    return null
-  }
-  if (!settings.length && !isThreadAuthor) {
-    return null
-  }
-
-  const isEverybody = settings.length === 0
-  const isNobody = !!settings.find(gate => gate.type === 'nobody')
-  const description = isEverybody
-    ? _(msg`Everybody can reply`)
-    : isNobody
-    ? _(msg`Replies on this thread are disabled`)
-    : _(msg`Some people can reply`)
-
-  return (
-    <>
-      <Button
-        label={
-          isThreadAuthor ? _(msg`Edit who can reply`) : _(msg`Who can reply`)
-        }
-        onPress={isThreadAuthor ? onPressEdit : infoDialogControl.open}
-        hitSlop={HITSLOP_10}>
-        {({hovered}) => (
-          <View
-            style={[
-              a.flex_1,
-              a.flex_row,
-              a.align_center,
-              a.py_sm,
-              a.pr_lg,
-              style,
-            ]}>
-            <View style={[{paddingLeft: 25, paddingRight: 18}]}>
-              <Icon color={t.palette.contrast_300} settings={settings} />
-            </View>
-            <Text
-              style={[
-                a.text_sm,
-                a.leading_tight,
-                t.atoms.text_contrast_medium,
-                hovered && a.underline,
-              ]}>
-              {description}
-            </Text>
-          </View>
-        )}
-      </Button>
-      <InfoDialog control={infoDialogControl} post={post} settings={settings} />
+      <WhoCanReplyDialog control={infoDialogControl} post={post} />
     </>
   )
 }
@@ -176,31 +113,24 @@ function Icon({
   return <IconComponent fill={color} width={width} />
 }
 
-function InfoDialog({
+export function WhoCanReplyDialog({
   control,
   post,
-  settings,
 }: {
   control: Dialog.DialogControlProps
   post: AppBskyFeedDefs.PostView
-  settings: ThreadgateSetting[]
 }) {
   return (
     <Dialog.Outer control={control}>
       <Dialog.Handle />
-      <InfoDialogInner post={post} settings={settings} />
+      <WhoCanReplyDialogInner post={post} />
     </Dialog.Outer>
   )
 }
 
-function InfoDialogInner({
-  post,
-  settings,
-}: {
-  post: AppBskyFeedDefs.PostView
-  settings: ThreadgateSetting[]
-}) {
+function WhoCanReplyDialogInner({post}: {post: AppBskyFeedDefs.PostView}) {
   const {_} = useLingui()
+  const {settings} = useWhoCanReply(post)
   return (
     <Dialog.ScrollableInner
       label={_(msg`Who can reply dialog`)}
@@ -334,6 +264,9 @@ function useWhoCanReply(post: AppBskyFeedDefs.PostView) {
       name: 'threadgate',
       settings,
       async onConfirm(newSettings: ThreadgateSetting[]) {
+        if (JSON.stringify(settings) === JSON.stringify(newSettings)) {
+          return
+        }
         try {
           if (newSettings.length) {
             await createThreadgate(agent, post.uri, newSettings)
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 92b529db7..46c6c958e 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -34,8 +34,8 @@ import {ContentHider} from '../../../components/moderation/ContentHider'
 import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe'
 import {PostAlerts} from '../../../components/moderation/PostAlerts'
 import {PostHider} from '../../../components/moderation/PostHider'
+import {WhoCanReply} from '../../../components/WhoCanReply'
 import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
-import {WhoCanReplyBlock, WhoCanReplyInline} from '../threadgate/WhoCanReply'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {Link, TextLink} from '../util/Link'
 import {formatCount} from '../util/numeric/format'
@@ -406,177 +406,172 @@ let PostThreadItemLoaded = ({
     const isThreadedChildAdjacentBot =
       isThreadedChild && nextPost?.ctx.depth === depth
     return (
-      <>
-        <PostOuterWrapper
-          post={post}
-          depth={depth}
-          showParentReplyLine={!!showParentReplyLine}
-          treeView={treeView}
-          hasPrecedingItem={hasPrecedingItem}
-          hideTopBorder={hideTopBorder}>
-          <PostHider
-            testID={`postThreadItem-by-${post.author.handle}`}
-            href={postHref}
-            disabled={overrideBlur}
-            style={[pal.view]}
-            modui={moderation.ui('contentList')}
-            iconSize={isThreadedChild ? 26 : 38}
-            iconStyles={
-              isThreadedChild
-                ? {marginRight: 4}
-                : {marginLeft: 2, marginRight: 2}
-            }
-            profile={post.author}
-            interpretFilterAsBlur>
-            <View
-              style={{
-                flexDirection: 'row',
-                gap: 10,
-                paddingLeft: 8,
-                height: isThreadedChildAdjacentTop ? 8 : 16,
-              }}>
-              <View style={{width: 38}}>
-                {!isThreadedChild && showParentReplyLine && (
+      <PostOuterWrapper
+        post={post}
+        depth={depth}
+        showParentReplyLine={!!showParentReplyLine}
+        treeView={treeView}
+        hasPrecedingItem={hasPrecedingItem}
+        hideTopBorder={hideTopBorder}>
+        <PostHider
+          testID={`postThreadItem-by-${post.author.handle}`}
+          href={postHref}
+          disabled={overrideBlur}
+          style={[pal.view]}
+          modui={moderation.ui('contentList')}
+          iconSize={isThreadedChild ? 26 : 38}
+          iconStyles={
+            isThreadedChild ? {marginRight: 4} : {marginLeft: 2, marginRight: 2}
+          }
+          profile={post.author}
+          interpretFilterAsBlur>
+          <View
+            style={{
+              flexDirection: 'row',
+              gap: 10,
+              paddingLeft: 8,
+              height: isThreadedChildAdjacentTop ? 8 : 16,
+            }}>
+            <View style={{width: 38}}>
+              {!isThreadedChild && showParentReplyLine && (
+                <View
+                  style={[
+                    styles.replyLine,
+                    {
+                      flexGrow: 1,
+                      backgroundColor: pal.colors.replyLine,
+                      marginBottom: 4,
+                    },
+                  ]}
+                />
+              )}
+            </View>
+          </View>
+
+          <View
+            style={[
+              styles.layout,
+              {
+                paddingBottom:
+                  showChildReplyLine && !isThreadedChild
+                    ? 0
+                    : isThreadedChildAdjacentBot
+                    ? 4
+                    : 8,
+              },
+            ]}>
+            {/* If we are in threaded mode, the avatar is rendered in PostMeta */}
+            {!isThreadedChild && (
+              <View style={styles.layoutAvi}>
+                <PreviewableUserAvatar
+                  size={38}
+                  profile={post.author}
+                  moderation={moderation.ui('avatar')}
+                  type={post.author.associated?.labeler ? 'labeler' : 'user'}
+                />
+
+                {showChildReplyLine && (
                   <View
                     style={[
                       styles.replyLine,
                       {
                         flexGrow: 1,
                         backgroundColor: pal.colors.replyLine,
-                        marginBottom: 4,
+                        marginTop: 4,
                       },
                     ]}
                   />
                 )}
               </View>
-            </View>
+            )}
 
             <View
-              style={[
-                styles.layout,
-                {
-                  paddingBottom:
-                    showChildReplyLine && !isThreadedChild
-                      ? 0
-                      : isThreadedChildAdjacentBot
-                      ? 4
-                      : 8,
-                },
-              ]}>
-              {/* If we are in threaded mode, the avatar is rendered in PostMeta */}
-              {!isThreadedChild && (
-                <View style={styles.layoutAvi}>
-                  <PreviewableUserAvatar
-                    size={38}
-                    profile={post.author}
-                    moderation={moderation.ui('avatar')}
-                    type={post.author.associated?.labeler ? 'labeler' : 'user'}
-                  />
-
-                  {showChildReplyLine && (
-                    <View
-                      style={[
-                        styles.replyLine,
-                        {
-                          flexGrow: 1,
-                          backgroundColor: pal.colors.replyLine,
-                          marginTop: 4,
-                        },
-                      ]}
-                    />
-                  )}
-                </View>
-              )}
-
-              <View
+              style={
+                isThreadedChild
+                  ? styles.layoutContentThreaded
+                  : styles.layoutContent
+              }>
+              <PostMeta
+                author={post.author}
+                moderation={moderation}
+                authorHasWarning={!!post.author.labels?.length}
+                timestamp={post.indexedAt}
+                postHref={postHref}
+                showAvatar={isThreadedChild}
+                avatarModeration={moderation.ui('avatar')}
+                avatarSize={28}
+                displayNameType="md-bold"
+                displayNameStyle={isThreadedChild && s.ml2}
                 style={
-                  isThreadedChild
-                    ? styles.layoutContentThreaded
-                    : styles.layoutContent
-                }>
-                <PostMeta
-                  author={post.author}
-                  moderation={moderation}
-                  authorHasWarning={!!post.author.labels?.length}
-                  timestamp={post.indexedAt}
-                  postHref={postHref}
-                  showAvatar={isThreadedChild}
-                  avatarModeration={moderation.ui('avatar')}
-                  avatarSize={28}
-                  displayNameType="md-bold"
-                  displayNameStyle={isThreadedChild && s.ml2}
-                  style={
-                    isThreadedChild && {
-                      alignItems: 'center',
-                      paddingBottom: isWeb ? 5 : 2,
-                    }
+                  isThreadedChild && {
+                    alignItems: 'center',
+                    paddingBottom: isWeb ? 5 : 2,
                   }
-                />
-                <LabelsOnMyPost post={post} />
-                <PostAlerts
-                  modui={moderation.ui('contentList')}
-                  style={[a.pt_2xs, a.pb_2xs]}
-                />
-                {richText?.text ? (
-                  <View style={styles.postTextContainer}>
-                    <RichText
-                      enableTags
-                      value={richText}
-                      style={[a.flex_1, a.text_md]}
-                      numberOfLines={limitLines ? MAX_POST_LINES : undefined}
-                      authorHandle={post.author.handle}
-                    />
-                  </View>
-                ) : undefined}
-                {limitLines ? (
-                  <TextLink
-                    text={_(msg`Show More`)}
-                    style={pal.link}
-                    onPress={onPressShowMore}
-                    href="#"
+                }
+              />
+              <LabelsOnMyPost post={post} />
+              <PostAlerts
+                modui={moderation.ui('contentList')}
+                style={[a.pt_2xs, a.pb_2xs]}
+              />
+              {richText?.text ? (
+                <View style={styles.postTextContainer}>
+                  <RichText
+                    enableTags
+                    value={richText}
+                    style={[a.flex_1, a.text_md]}
+                    numberOfLines={limitLines ? MAX_POST_LINES : undefined}
+                    authorHandle={post.author.handle}
                   />
-                ) : undefined}
-                {post.embed && (
-                  <View style={[a.pb_xs]}>
-                    <PostEmbeds embed={post.embed} moderation={moderation} />
-                  </View>
-                )}
-                <PostCtrls
-                  post={post}
-                  record={record}
-                  richText={richText}
-                  onPressReply={onPressReply}
-                  logContext="PostThreadItem"
+                </View>
+              ) : undefined}
+              {limitLines ? (
+                <TextLink
+                  text={_(msg`Show More`)}
+                  style={pal.link}
+                  onPress={onPressShowMore}
+                  href="#"
                 />
-              </View>
+              ) : undefined}
+              {post.embed && (
+                <View style={[a.pb_xs]}>
+                  <PostEmbeds embed={post.embed} moderation={moderation} />
+                </View>
+              )}
+              <PostCtrls
+                post={post}
+                record={record}
+                richText={richText}
+                onPressReply={onPressReply}
+                logContext="PostThreadItem"
+              />
             </View>
-            {hasMore ? (
-              <Link
-                style={[
-                  styles.loadMore,
-                  {
-                    paddingLeft: treeView ? 8 : 70,
-                    paddingTop: 0,
-                    paddingBottom: treeView ? 4 : 12,
-                  },
-                ]}
-                href={postHref}
-                title={itemTitle}
-                noFeedback>
-                <Text type="sm-medium" style={pal.textLight}>
-                  <Trans>More</Trans>
-                </Text>
-                <FontAwesomeIcon
-                  icon="angle-right"
-                  color={pal.colors.textLight}
-                  size={14}
-                />
-              </Link>
-            ) : undefined}
-          </PostHider>
-        </PostOuterWrapper>
-        <WhoCanReplyBlock post={post} isThreadAuthor={isThreadAuthor} />
-      </>
+          </View>
+          {hasMore ? (
+            <Link
+              style={[
+                styles.loadMore,
+                {
+                  paddingLeft: treeView ? 8 : 70,
+                  paddingTop: 0,
+                  paddingBottom: treeView ? 4 : 12,
+                },
+              ]}
+              href={postHref}
+              title={itemTitle}
+              noFeedback>
+              <Text type="sm-medium" style={pal.textLight}>
+                <Trans>More</Trans>
+              </Text>
+              <FontAwesomeIcon
+                icon="angle-right"
+                color={pal.colors.textLight}
+                size={14}
+              />
+            </Link>
+          ) : undefined}
+        </PostHider>
+      </PostOuterWrapper>
     )
   }
 }
@@ -671,7 +666,7 @@ function ExpandedPostDetails({
         s.mb10,
       ]}>
       <Text style={[a.text_sm, pal.textLight]}>{niceDate(post.indexedAt)}</Text>
-      <WhoCanReplyInline post={post} isThreadAuthor={isThreadAuthor} />
+      <WhoCanReply post={post} isThreadAuthor={isThreadAuthor} />
       {needsTranslation && (
         <>
           <Text style={[a.text_sm, pal.textLight]}>&middot;</Text>