about summary refs log tree commit diff
path: root/src/view/screens/ProfileList.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens/ProfileList.tsx')
-rw-r--r--src/view/screens/ProfileList.tsx317
1 files changed, 128 insertions, 189 deletions
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index 27ede80a3..2e661ff46 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -1,5 +1,6 @@
 import React, {useCallback, useMemo} from 'react'
 import {Pressable, StyleSheet, View} from 'react-native'
+import {useAnimatedRef} from 'react-native-reanimated'
 import {
   AppBskyGraphDefs,
   AtUri,
@@ -19,12 +20,11 @@ import {usePalette} from '#/lib/hooks/usePalette'
 import {useSetTitle} from '#/lib/hooks/useSetTitle'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {ComposeIcon2} from '#/lib/icons'
-import {makeListLink, makeProfileLink} from '#/lib/routes/links'
+import {makeListLink} from '#/lib/routes/links'
 import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
 import {NavigationProp} from '#/lib/routes/types'
 import {shareUrl} from '#/lib/sharing'
 import {cleanError} from '#/lib/strings/errors'
-import {sanitizeHandle} from '#/lib/strings/handles'
 import {toShareUrl} from '#/lib/strings/url-helpers'
 import {s} from '#/lib/styles'
 import {logger} from '#/logger'
@@ -63,14 +63,13 @@ import {
   DropdownItem,
   NativeDropdown,
 } from '#/view/com/util/forms/NativeDropdown'
-import {TextLink} from '#/view/com/util/Link'
 import {ListRef} from '#/view/com/util/List'
 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn'
 import {LoadingScreen} from '#/view/com/util/LoadingScreen'
 import {Text} from '#/view/com/util/text/Text'
 import * as Toast from '#/view/com/util/Toast'
 import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen'
-import {atoms as a, useTheme} from '#/alf'
+import {atoms as a} from '#/alf'
 import {useDialogControl} from '#/components/Dialog'
 import * as Layout from '#/components/Layout'
 import * as Hider from '#/components/moderation/Hider'
@@ -78,8 +77,7 @@ import * as Prompt from '#/components/Prompt'
 import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
 import {RichText} from '#/components/RichText'
 
-const SECTION_TITLES_CURATE = ['Posts', 'About']
-const SECTION_TITLES_MOD = ['About']
+const SECTION_TITLES_CURATE = ['Posts', 'People']
 
 interface SectionRef {
   scrollToTop: () => void
@@ -161,6 +159,7 @@ function ProfileListScreenLoaded({
   const isScreenFocused = useIsFocused()
   const isHidden = list.labels?.findIndex(l => l.val === '!hide') !== -1
   const isOwner = currentAccount?.did === list.creator.did
+  const scrollElRef = useAnimatedRef()
 
   const moderation = React.useMemo(() => {
     return moderateUserList(list, moderationOpts)
@@ -259,19 +258,13 @@ function ProfileListScreenLoaded({
       </Hider.Mask>
       <Hider.Content>
         <View style={s.hContentRegion}>
-          <PagerWithHeader
-            items={SECTION_TITLES_MOD}
-            isHeaderReady={true}
-            renderHeader={renderHeader}>
-            {({headerHeight, scrollElRef}) => (
-              <AboutSection
-                list={list}
-                scrollElRef={scrollElRef as ListRef}
-                onPressAddUser={onPressAddUser}
-                headerHeight={headerHeight}
-              />
-            )}
-          </PagerWithHeader>
+          <Layout.Center>{renderHeader()}</Layout.Center>
+          <AboutSection
+            list={list}
+            scrollElRef={scrollElRef as ListRef}
+            onPressAddUser={onPressAddUser}
+            headerHeight={0}
+          />
           <FAB
             testID="composeFAB"
             onPress={() => openComposer({})}
@@ -652,101 +645,124 @@ function Header({
     ]
   }, [_, subscribeMutePromptControl.open, subscribeBlockPromptControl.open])
 
+  const descriptionRT = useMemo(
+    () =>
+      list.description
+        ? new RichTextAPI({
+            text: list.description,
+            facets: list.descriptionFacets,
+          })
+        : undefined,
+    [list],
+  )
+
   return (
-    <ProfileSubpageHeader
-      href={makeListLink(list.creator.handle || list.creator.did || '', rkey)}
-      title={list.name}
-      avatar={list.avatar}
-      isOwner={list.creator.did === currentAccount?.did}
-      creator={list.creator}
-      avatarType="list">
-      <ReportDialog
-        control={reportDialogControl}
-        params={{
-          type: 'list',
-          uri: list.uri,
-          cid: list.cid,
-        }}
-      />
-      {isCurateList ? (
-        <Button
-          testID={isPinned ? 'unpinBtn' : 'pinBtn'}
-          type={isPinned ? 'default' : 'inverted'}
-          label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
-          onPress={onTogglePinned}
-          disabled={isPending}
+    <>
+      <ProfileSubpageHeader
+        href={makeListLink(list.creator.handle || list.creator.did || '', rkey)}
+        title={list.name}
+        avatar={list.avatar}
+        isOwner={list.creator.did === currentAccount?.did}
+        creator={list.creator}
+        purpose={list.purpose}
+        avatarType="list">
+        <ReportDialog
+          control={reportDialogControl}
+          params={{
+            type: 'list',
+            uri: list.uri,
+            cid: list.cid,
+          }}
         />
-      ) : isModList ? (
-        isBlocking ? (
+        {isCurateList ? (
           <Button
-            testID="unblockBtn"
-            type="default"
-            label={_(msg`Unblock`)}
-            onPress={onUnsubscribeBlock}
+            testID={isPinned ? 'unpinBtn' : 'pinBtn'}
+            type={isPinned ? 'default' : 'inverted'}
+            label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
+            onPress={onTogglePinned}
+            disabled={isPending}
           />
-        ) : isMuting ? (
-          <Button
-            testID="unmuteBtn"
-            type="default"
-            label={_(msg`Unmute`)}
-            onPress={onUnsubscribeMute}
-          />
-        ) : (
-          <NativeDropdown
-            testID="subscribeBtn"
-            items={subscribeDropdownItems}
-            accessibilityLabel={_(msg`Subscribe to this list`)}
-            accessibilityHint="">
-            <View style={[palInverted.view, styles.btn]}>
-              <Text style={palInverted.text}>
-                <Trans>Subscribe</Trans>
-              </Text>
-            </View>
-          </NativeDropdown>
-        )
-      ) : null}
-      <NativeDropdown
-        testID="headerDropdownBtn"
-        items={dropdownItems}
-        accessibilityLabel={_(msg`More options`)}
-        accessibilityHint="">
-        <View style={[pal.viewLight, styles.btn]}>
-          <FontAwesomeIcon icon="ellipsis" size={20} color={pal.colors.text} />
-        </View>
-      </NativeDropdown>
+        ) : isModList ? (
+          isBlocking ? (
+            <Button
+              testID="unblockBtn"
+              type="default"
+              label={_(msg`Unblock`)}
+              onPress={onUnsubscribeBlock}
+            />
+          ) : isMuting ? (
+            <Button
+              testID="unmuteBtn"
+              type="default"
+              label={_(msg`Unmute`)}
+              onPress={onUnsubscribeMute}
+            />
+          ) : (
+            <NativeDropdown
+              testID="subscribeBtn"
+              items={subscribeDropdownItems}
+              accessibilityLabel={_(msg`Subscribe to this list`)}
+              accessibilityHint="">
+              <View style={[palInverted.view, styles.btn]}>
+                <Text style={palInverted.text}>
+                  <Trans>Subscribe</Trans>
+                </Text>
+              </View>
+            </NativeDropdown>
+          )
+        ) : null}
+        <NativeDropdown
+          testID="headerDropdownBtn"
+          items={dropdownItems}
+          accessibilityLabel={_(msg`More options`)}
+          accessibilityHint="">
+          <View style={[pal.viewLight, styles.btn]}>
+            <FontAwesomeIcon
+              icon="ellipsis"
+              size={20}
+              color={pal.colors.text}
+            />
+          </View>
+        </NativeDropdown>
 
-      <Prompt.Basic
-        control={deleteListPromptControl}
-        title={_(msg`Delete this list?`)}
-        description={_(
-          msg`If you delete this list, you won't be able to recover it.`,
-        )}
-        onConfirm={onPressDelete}
-        confirmButtonCta={_(msg`Delete`)}
-        confirmButtonColor="negative"
-      />
+        <Prompt.Basic
+          control={deleteListPromptControl}
+          title={_(msg`Delete this list?`)}
+          description={_(
+            msg`If you delete this list, you won't be able to recover it.`,
+          )}
+          onConfirm={onPressDelete}
+          confirmButtonCta={_(msg`Delete`)}
+          confirmButtonColor="negative"
+        />
 
-      <Prompt.Basic
-        control={subscribeMutePromptControl}
-        title={_(msg`Mute these accounts?`)}
-        description={_(
-          msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
-        )}
-        onConfirm={onSubscribeMute}
-        confirmButtonCta={_(msg`Mute list`)}
-      />
+        <Prompt.Basic
+          control={subscribeMutePromptControl}
+          title={_(msg`Mute these accounts?`)}
+          description={_(
+            msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
+          )}
+          onConfirm={onSubscribeMute}
+          confirmButtonCta={_(msg`Mute list`)}
+        />
 
-      <Prompt.Basic
-        control={subscribeBlockPromptControl}
-        title={_(msg`Block these accounts?`)}
-        description={_(
-          msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
-        )}
-        onConfirm={onSubscribeBlock}
-        confirmButtonCta={_(msg`Block list`)}
-        confirmButtonColor="negative"
-      />
-    </ProfileSubpageHeader>
+        <Prompt.Basic
+          control={subscribeBlockPromptControl}
+          title={_(msg`Block these accounts?`)}
+          description={_(
+            msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
+          )}
+          onConfirm={onSubscribeBlock}
+          confirmButtonCta={_(msg`Block list`)}
+          confirmButtonColor="negative"
+        />
+      </ProfileSubpageHeader>
+      {descriptionRT ? (
+        <View style={[a.px_lg, a.pt_sm, a.pb_sm, a.gap_md]}>
+          <RichText value={descriptionRT} style={[a.text_md, a.leading_snug]} />
+        </View>
+      ) : null}
+    </>
   )
 }
 
@@ -825,25 +841,12 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
     ref,
   ) {
     const pal = usePalette('default')
-    const t = useTheme()
     const {_} = useLingui()
     const {isMobile} = useWebMediaQueries()
     const {currentAccount} = useSession()
     const [isScrolledDown, setIsScrolledDown] = React.useState(false)
-    const isCurateList = list.purpose === 'app.bsky.graph.defs#curatelist'
     const isOwner = list.creator.did === currentAccount?.did
 
-    const descriptionRT = useMemo(
-      () =>
-        list.description
-          ? new RichTextAPI({
-              text: list.description,
-              facets: list.descriptionFacets,
-            })
-          : undefined,
-      [list],
-    )
-
     const onScrollToTop = useCallback(() => {
       scrollElRef.current?.scrollToOffset({
         animated: isNative,
@@ -856,59 +859,11 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
     }))
 
     const renderHeader = React.useCallback(() => {
+      if (!isOwner) {
+        return <View />
+      }
       return (
-        <View>
-          <View
-            style={[
-              {
-                borderTopWidth: StyleSheet.hairlineWidth,
-                padding: isMobile ? 14 : 20,
-                gap: 12,
-              },
-              pal.border,
-            ]}>
-            {descriptionRT ? (
-              <RichText
-                testID="listDescription"
-                style={[a.text_md]}
-                value={descriptionRT}
-              />
-            ) : (
-              <Text
-                testID="listDescriptionEmpty"
-                type="lg"
-                style={[{fontStyle: 'italic'}, pal.textLight]}>
-                <Trans>No description</Trans>
-              </Text>
-            )}
-            <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-              {isCurateList ? (
-                isOwner ? (
-                  <Trans>User list by you</Trans>
-                ) : (
-                  <Trans>
-                    User list by{' '}
-                    <TextLink
-                      text={sanitizeHandle(list.creator.handle || '', '@')}
-                      href={makeProfileLink(list.creator)}
-                      style={pal.textLight}
-                    />
-                  </Trans>
-                )
-              ) : isOwner ? (
-                <Trans>Moderation list by you</Trans>
-              ) : (
-                <Trans>
-                  Moderation list by{' '}
-                  <TextLink
-                    text={sanitizeHandle(list.creator.handle || '', '@')}
-                    href={makeProfileLink(list.creator)}
-                    style={pal.textLight}
-                  />
-                </Trans>
-              )}
-            </Text>
-          </View>
+        <View style={a.pt_lg}>
           <View
             style={[
               {
@@ -919,9 +874,6 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
                 paddingBottom: isMobile ? 14 : 18,
               },
             ]}>
-            <Text type="lg-bold" style={t.atoms.text}>
-              <Trans>Users</Trans>
-            </Text>
             {isOwner && (
               <Pressable
                 testID="addUserBtn"
@@ -943,20 +895,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
           </View>
         </View>
       )
-    }, [
-      isMobile,
-      pal.border,
-      pal.textLight,
-      pal.colors.link,
-      pal.link,
-      descriptionRT,
-      isCurateList,
-      isOwner,
-      list.creator,
-      t.atoms.text,
-      _,
-      onPressAddUser,
-    ])
+    }, [isMobile, pal.colors.link, pal.link, isOwner, _, onPressAddUser])
 
     const renderEmptyState = useCallback(() => {
       return (