about summary refs log tree commit diff
path: root/src/components/dms
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/dms')
-rw-r--r--src/components/dms/ConvoMenu.tsx40
-rw-r--r--src/components/dms/MessagesListHeader.tsx171
2 files changed, 87 insertions, 124 deletions
diff --git a/src/components/dms/ConvoMenu.tsx b/src/components/dms/ConvoMenu.tsx
index 8aa2335d0..1b1ebbcd5 100644
--- a/src/components/dms/ConvoMenu.tsx
+++ b/src/components/dms/ConvoMenu.tsx
@@ -1,12 +1,12 @@
 import React, {useCallback} from 'react'
-import {Keyboard, Pressable, View} from 'react-native'
-import {ChatBskyConvoDefs, ModerationCause} from '@atproto/api'
+import {Keyboard, View} from 'react-native'
+import {type ChatBskyConvoDefs, type ModerationCause} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useNavigation} from '@react-navigation/native'
 
-import {NavigationProp} from '#/lib/routes/types'
-import {Shadow} from '#/state/cache/types'
+import {type NavigationProp} from '#/lib/routes/types'
+import {type Shadow} from '#/state/cache/types'
 import {
   useConvoQuery,
   useMarkAsReadMutation,
@@ -14,11 +14,15 @@ import {
 import {useMuteConvo} from '#/state/queries/messages/mute-conversation'
 import {useProfileBlockMutationQueue} from '#/state/queries/profile'
 import * as Toast from '#/view/com/util/Toast'
-import {atoms as a, useTheme, ViewStyleProp} from '#/alf'
+import {type ViewStyleProp} from '#/alf'
+import {atoms as a} from '#/alf'
+import {Button, ButtonIcon} from '#/components/Button'
 import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog'
 import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
 import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
+import {ReportDialog} from '#/components/dms/ReportDialog'
 import {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft'
+import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble'
 import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
 import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag'
 import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute'
@@ -30,9 +34,7 @@ import {
 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
 import * as Menu from '#/components/Menu'
 import * as Prompt from '#/components/Prompt'
-import * as bsky from '#/types/bsky'
-import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble'
-import {ReportDialog} from './ReportDialog'
+import type * as bsky from '#/types/bsky'
 
 let ConvoMenu = ({
   convo,
@@ -59,7 +61,6 @@ let ConvoMenu = ({
   style?: ViewStyleProp['style']
 }): React.ReactNode => {
   const {_} = useLingui()
-  const t = useTheme()
 
   const leaveConvoControl = Prompt.usePromptControl()
   const reportControl = Prompt.usePromptControl()
@@ -73,22 +74,21 @@ let ConvoMenu = ({
         {!hideTrigger && (
           <View style={[style]}>
             <Menu.Trigger label={_(msg`Chat settings`)}>
-              {({props, state}) => (
-                <Pressable
+              {({props}) => (
+                <Button
+                  label={props.accessibilityLabel}
                   {...props}
                   onPress={() => {
                     Keyboard.dismiss()
                     props.onPress()
                   }}
-                  style={[
-                    a.p_sm,
-                    a.rounded_full,
-                    (state.hovered || state.pressed) && t.atoms.bg_contrast_25,
-                    // make sure pfp is in the middle
-                    {marginLeft: -10},
-                  ]}>
-                  <DotsHorizontal size="md" style={t.atoms.text} />
-                </Pressable>
+                  size="small"
+                  color="secondary"
+                  shape="round"
+                  variant="ghost"
+                  style={[a.bg_transparent]}>
+                  <ButtonIcon icon={DotsHorizontal} size="md" />
+                </Button>
               )}
             </Menu.Trigger>
           </View>
diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
index c8ed98f88..d37e4a34a 100644
--- a/src/components/dms/MessagesListHeader.tsx
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -1,48 +1,42 @@
-import React, {useCallback} from 'react'
-import {TouchableOpacity, View} from 'react-native'
+import {useMemo} from 'react'
+import {View} from 'react-native'
 import {
   type AppBskyActorDefs,
   type ModerationCause,
   type ModerationDecision,
 } from '@atproto/api'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
-import {useNavigation} from '@react-navigation/native'
 
-import {BACK_HITSLOP} from '#/lib/constants'
 import {makeProfileLink} from '#/lib/routes/links'
-import {type NavigationProp} from '#/lib/routes/types'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
 import {isWeb} from '#/platform/detection'
 import {type Shadow} from '#/state/cache/profile-shadow'
 import {isConvoActive, useConvo} from '#/state/messages/convo'
 import {type ConvoItem} from '#/state/messages/convo/types'
 import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
-import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
+import {atoms as a, useTheme, web} from '#/alf'
 import {ConvoMenu} from '#/components/dms/ConvoMenu'
 import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2'
+import * as Layout from '#/components/Layout'
 import {Link} from '#/components/Link'
 import {PostAlerts} from '#/components/moderation/PostAlerts'
 import {Text} from '#/components/Typography'
 import {useSimpleVerificationState} from '#/components/verification'
 import {VerificationCheck} from '#/components/verification/VerificationCheck'
 
-const PFP_SIZE = isWeb ? 40 : 34
+const PFP_SIZE = isWeb ? 40 : Layout.HEADER_SLOT_SIZE
 
-export let MessagesListHeader = ({
+export function MessagesListHeader({
   profile,
   moderation,
 }: {
   profile?: Shadow<AppBskyActorDefs.ProfileViewDetailed>
   moderation?: ModerationDecision
-}): React.ReactNode => {
+}) {
   const t = useTheme()
-  const {_} = useLingui()
-  const {gtTablet} = useBreakpoints()
-  const navigation = useNavigation<NavigationProp>()
 
-  const blockInfo = React.useMemo(() => {
+  const blockInfo = useMemo(() => {
     if (!moderation) return
     const modui = moderation.ui('profileView')
     const blocks = modui.alerts.filter(alert => alert.type === 'blocking')
@@ -54,87 +48,54 @@ export let MessagesListHeader = ({
     }
   }, [moderation])
 
-  const onPressBack = useCallback(() => {
-    if (navigation.canGoBack()) {
-      navigation.goBack()
-    } else {
-      navigation.navigate('Messages', {})
-    }
-  }, [navigation])
-
   return (
-    <View
-      style={[
-        t.atoms.bg,
-        t.atoms.border_contrast_low,
-        a.border_b,
-        a.flex_row,
-        a.align_start,
-        a.gap_sm,
-        gtTablet ? a.pl_lg : a.pl_xl,
-        a.pr_lg,
-        a.py_sm,
-      ]}>
-      <TouchableOpacity
-        testID="conversationHeaderBackBtn"
-        onPress={onPressBack}
-        hitSlop={BACK_HITSLOP}
-        style={{width: 30, height: 30, marginTop: isWeb ? 6 : 4}}
-        accessibilityRole="button"
-        accessibilityLabel={_(msg`Back`)}
-        accessibilityHint="">
-        <FontAwesomeIcon
-          size={18}
-          icon="angle-left"
-          style={{
-            marginTop: 6,
-          }}
-          color={t.atoms.text.color}
-        />
-      </TouchableOpacity>
-
-      {profile && moderation && blockInfo ? (
-        <HeaderReady
-          profile={profile}
-          moderation={moderation}
-          blockInfo={blockInfo}
-        />
-      ) : (
-        <>
-          <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}>
-            <View
-              style={[
-                {width: PFP_SIZE, height: PFP_SIZE},
-                a.rounded_full,
-                t.atoms.bg_contrast_25,
-              ]}
-            />
-            <View style={a.gap_xs}>
-              <View
-                style={[
-                  {width: 120, height: 16},
-                  a.rounded_xs,
-                  t.atoms.bg_contrast_25,
-                  a.mt_xs,
-                ]}
-              />
+    <Layout.Header.Outer>
+      <View style={[a.w_full, a.flex_row, a.gap_xs, a.align_start]}>
+        <View style={[{minHeight: PFP_SIZE}, a.justify_center]}>
+          <Layout.Header.BackButton />
+        </View>
+        {profile && moderation && blockInfo ? (
+          <HeaderReady
+            profile={profile}
+            moderation={moderation}
+            blockInfo={blockInfo}
+          />
+        ) : (
+          <>
+            <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}>
               <View
                 style={[
-                  {width: 175, height: 12},
-                  a.rounded_xs,
+                  {width: PFP_SIZE, height: PFP_SIZE},
+                  a.rounded_full,
                   t.atoms.bg_contrast_25,
                 ]}
               />
+              <View style={a.gap_xs}>
+                <View
+                  style={[
+                    {width: 120, height: 16},
+                    a.rounded_xs,
+                    t.atoms.bg_contrast_25,
+                    a.mt_xs,
+                  ]}
+                />
+                <View
+                  style={[
+                    {width: 175, height: 12},
+                    a.rounded_xs,
+                    t.atoms.bg_contrast_25,
+                  ]}
+                />
+              </View>
             </View>
-          </View>
 
-          <View style={{width: 30}} />
-        </>
-      )}
-    </View>
+            <Layout.Header.Slot />
+          </>
+        )}
+      </View>
+    </Layout.Header.Outer>
   )
 }
-MessagesListHeader = React.memo(MessagesListHeader)
 
 function HeaderReady({
   profile,
@@ -181,15 +142,13 @@ function HeaderReady({
           label={_(msg`View ${displayName}'s profile`)}
           style={[a.flex_row, a.align_start, a.gap_md, a.flex_1, a.pr_md]}
           to={makeProfileLink(profile)}>
-          <View style={[a.pt_2xs]}>
-            <PreviewableUserAvatar
-              size={PFP_SIZE}
-              profile={profile}
-              moderation={moderation.ui('avatar')}
-              disableHoverCard={moderation.blocked}
-            />
-          </View>
-          <View style={a.flex_1}>
+          <PreviewableUserAvatar
+            size={PFP_SIZE}
+            profile={profile}
+            moderation={moderation.ui('avatar')}
+            disableHoverCard={moderation.blocked}
+          />
+          <View style={[a.flex_1]}>
             <View style={[a.flex_row, a.align_center]}>
               <Text
                 emoji
@@ -215,7 +174,7 @@ function HeaderReady({
               <Text
                 style={[
                   t.atoms.text_contrast_medium,
-                  a.text_sm,
+                  a.text_xs,
                   web([a.leading_normal, {marginTop: -2}]),
                 ]}
                 numberOfLines={1}>
@@ -235,15 +194,19 @@ function HeaderReady({
           </View>
         </Link>
 
-        {isConvoActive(convoState) && (
-          <ConvoMenu
-            convo={convoState.convo}
-            profile={profile}
-            currentScreen="conversation"
-            blockInfo={blockInfo}
-            latestReportableMessage={latestReportableMessage}
-          />
-        )}
+        <View style={[{minHeight: PFP_SIZE}, a.justify_center]}>
+          <Layout.Header.Slot>
+            {isConvoActive(convoState) && (
+              <ConvoMenu
+                convo={convoState.convo}
+                profile={profile}
+                currentScreen="conversation"
+                blockInfo={blockInfo}
+                latestReportableMessage={latestReportableMessage}
+              />
+            )}
+          </Layout.Header.Slot>
+        </View>
       </View>
 
       <View