Bluesky app fork with some witchin' additions 💫

Update DM header to match new Layout style (#8846)

authored by samuel.fm and committed by

GitHub 54f7af12 ecb77a9b

+88 -125
+1 -1
src/components/Layout/const.ts
··· 13 13 /** 14 14 * Corresponds to the width of a small square or round button 15 15 */ 16 - export const HEADER_SLOT_SIZE = 34 16 + export const HEADER_SLOT_SIZE = 33 17 17 18 18 /** 19 19 * How far to shift the center column when in the tablet breakpoint
+20 -20
src/components/dms/ConvoMenu.tsx
··· 1 1 import React, {useCallback} from 'react' 2 - import {Keyboard, Pressable, View} from 'react-native' 3 - import {ChatBskyConvoDefs, ModerationCause} from '@atproto/api' 2 + import {Keyboard, View} from 'react-native' 3 + import {type ChatBskyConvoDefs, type ModerationCause} from '@atproto/api' 4 4 import {msg, Trans} from '@lingui/macro' 5 5 import {useLingui} from '@lingui/react' 6 6 import {useNavigation} from '@react-navigation/native' 7 7 8 - import {NavigationProp} from '#/lib/routes/types' 9 - import {Shadow} from '#/state/cache/types' 8 + import {type NavigationProp} from '#/lib/routes/types' 9 + import {type Shadow} from '#/state/cache/types' 10 10 import { 11 11 useConvoQuery, 12 12 useMarkAsReadMutation, ··· 14 14 import {useMuteConvo} from '#/state/queries/messages/mute-conversation' 15 15 import {useProfileBlockMutationQueue} from '#/state/queries/profile' 16 16 import * as Toast from '#/view/com/util/Toast' 17 - import {atoms as a, useTheme, ViewStyleProp} from '#/alf' 17 + import {type ViewStyleProp} from '#/alf' 18 + import {atoms as a} from '#/alf' 19 + import {Button, ButtonIcon} from '#/components/Button' 18 20 import {BlockedByListDialog} from '#/components/dms/BlockedByListDialog' 19 21 import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt' 20 22 import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt' 23 + import {ReportDialog} from '#/components/dms/ReportDialog' 21 24 import {ArrowBoxLeft_Stroke2_Corner0_Rounded as ArrowBoxLeft} from '#/components/icons/ArrowBoxLeft' 25 + import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '#/components/icons/Bubble' 22 26 import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid' 23 27 import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag' 24 28 import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' ··· 30 34 import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' 31 35 import * as Menu from '#/components/Menu' 32 36 import * as Prompt from '#/components/Prompt' 33 - import * as bsky from '#/types/bsky' 34 - import {Bubble_Stroke2_Corner2_Rounded as Bubble} from '../icons/Bubble' 35 - import {ReportDialog} from './ReportDialog' 37 + import type * as bsky from '#/types/bsky' 36 38 37 39 let ConvoMenu = ({ 38 40 convo, ··· 59 61 style?: ViewStyleProp['style'] 60 62 }): React.ReactNode => { 61 63 const {_} = useLingui() 62 - const t = useTheme() 63 64 64 65 const leaveConvoControl = Prompt.usePromptControl() 65 66 const reportControl = Prompt.usePromptControl() ··· 73 74 {!hideTrigger && ( 74 75 <View style={[style]}> 75 76 <Menu.Trigger label={_(msg`Chat settings`)}> 76 - {({props, state}) => ( 77 - <Pressable 77 + {({props}) => ( 78 + <Button 79 + label={props.accessibilityLabel} 78 80 {...props} 79 81 onPress={() => { 80 82 Keyboard.dismiss() 81 83 props.onPress() 82 84 }} 83 - style={[ 84 - a.p_sm, 85 - a.rounded_full, 86 - (state.hovered || state.pressed) && t.atoms.bg_contrast_25, 87 - // make sure pfp is in the middle 88 - {marginLeft: -10}, 89 - ]}> 90 - <DotsHorizontal size="md" style={t.atoms.text} /> 91 - </Pressable> 85 + size="small" 86 + color="secondary" 87 + shape="round" 88 + variant="ghost" 89 + style={[a.bg_transparent]}> 90 + <ButtonIcon icon={DotsHorizontal} size="md" /> 91 + </Button> 92 92 )} 93 93 </Menu.Trigger> 94 94 </View>
+67 -104
src/components/dms/MessagesListHeader.tsx
··· 1 - import React, {useCallback} from 'react' 2 - import {TouchableOpacity, View} from 'react-native' 1 + import {useMemo} from 'react' 2 + import {View} from 'react-native' 3 3 import { 4 4 type AppBskyActorDefs, 5 5 type ModerationCause, 6 6 type ModerationDecision, 7 7 } from '@atproto/api' 8 - import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 9 8 import {msg} from '@lingui/macro' 10 9 import {useLingui} from '@lingui/react' 11 - import {useNavigation} from '@react-navigation/native' 12 10 13 - import {BACK_HITSLOP} from '#/lib/constants' 14 11 import {makeProfileLink} from '#/lib/routes/links' 15 - import {type NavigationProp} from '#/lib/routes/types' 16 12 import {sanitizeDisplayName} from '#/lib/strings/display-names' 17 13 import {isWeb} from '#/platform/detection' 18 14 import {type Shadow} from '#/state/cache/profile-shadow' 19 15 import {isConvoActive, useConvo} from '#/state/messages/convo' 20 16 import {type ConvoItem} from '#/state/messages/convo/types' 21 17 import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' 22 - import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' 18 + import {atoms as a, useTheme, web} from '#/alf' 23 19 import {ConvoMenu} from '#/components/dms/ConvoMenu' 24 20 import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2' 21 + import * as Layout from '#/components/Layout' 25 22 import {Link} from '#/components/Link' 26 23 import {PostAlerts} from '#/components/moderation/PostAlerts' 27 24 import {Text} from '#/components/Typography' 28 25 import {useSimpleVerificationState} from '#/components/verification' 29 26 import {VerificationCheck} from '#/components/verification/VerificationCheck' 30 27 31 - const PFP_SIZE = isWeb ? 40 : 34 28 + const PFP_SIZE = isWeb ? 40 : Layout.HEADER_SLOT_SIZE 32 29 33 - export let MessagesListHeader = ({ 30 + export function MessagesListHeader({ 34 31 profile, 35 32 moderation, 36 33 }: { 37 34 profile?: Shadow<AppBskyActorDefs.ProfileViewDetailed> 38 35 moderation?: ModerationDecision 39 - }): React.ReactNode => { 36 + }) { 40 37 const t = useTheme() 41 - const {_} = useLingui() 42 - const {gtTablet} = useBreakpoints() 43 - const navigation = useNavigation<NavigationProp>() 44 38 45 - const blockInfo = React.useMemo(() => { 39 + const blockInfo = useMemo(() => { 46 40 if (!moderation) return 47 41 const modui = moderation.ui('profileView') 48 42 const blocks = modui.alerts.filter(alert => alert.type === 'blocking') ··· 54 48 } 55 49 }, [moderation]) 56 50 57 - const onPressBack = useCallback(() => { 58 - if (navigation.canGoBack()) { 59 - navigation.goBack() 60 - } else { 61 - navigation.navigate('Messages', {}) 62 - } 63 - }, [navigation]) 64 - 65 51 return ( 66 - <View 67 - style={[ 68 - t.atoms.bg, 69 - t.atoms.border_contrast_low, 70 - a.border_b, 71 - a.flex_row, 72 - a.align_start, 73 - a.gap_sm, 74 - gtTablet ? a.pl_lg : a.pl_xl, 75 - a.pr_lg, 76 - a.py_sm, 77 - ]}> 78 - <TouchableOpacity 79 - testID="conversationHeaderBackBtn" 80 - onPress={onPressBack} 81 - hitSlop={BACK_HITSLOP} 82 - style={{width: 30, height: 30, marginTop: isWeb ? 6 : 4}} 83 - accessibilityRole="button" 84 - accessibilityLabel={_(msg`Back`)} 85 - accessibilityHint=""> 86 - <FontAwesomeIcon 87 - size={18} 88 - icon="angle-left" 89 - style={{ 90 - marginTop: 6, 91 - }} 92 - color={t.atoms.text.color} 93 - /> 94 - </TouchableOpacity> 95 - 96 - {profile && moderation && blockInfo ? ( 97 - <HeaderReady 98 - profile={profile} 99 - moderation={moderation} 100 - blockInfo={blockInfo} 101 - /> 102 - ) : ( 103 - <> 104 - <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}> 105 - <View 106 - style={[ 107 - {width: PFP_SIZE, height: PFP_SIZE}, 108 - a.rounded_full, 109 - t.atoms.bg_contrast_25, 110 - ]} 111 - /> 112 - <View style={a.gap_xs}> 52 + <Layout.Header.Outer> 53 + <View style={[a.w_full, a.flex_row, a.gap_xs, a.align_start]}> 54 + <View style={[{minHeight: PFP_SIZE}, a.justify_center]}> 55 + <Layout.Header.BackButton /> 56 + </View> 57 + {profile && moderation && blockInfo ? ( 58 + <HeaderReady 59 + profile={profile} 60 + moderation={moderation} 61 + blockInfo={blockInfo} 62 + /> 63 + ) : ( 64 + <> 65 + <View style={[a.flex_row, a.align_center, a.gap_md, a.flex_1]}> 113 66 <View 114 67 style={[ 115 - {width: 120, height: 16}, 116 - a.rounded_xs, 68 + {width: PFP_SIZE, height: PFP_SIZE}, 69 + a.rounded_full, 117 70 t.atoms.bg_contrast_25, 118 - a.mt_xs, 119 71 ]} 120 72 /> 121 - <View 122 - style={[ 123 - {width: 175, height: 12}, 124 - a.rounded_xs, 125 - t.atoms.bg_contrast_25, 126 - ]} 127 - /> 73 + <View style={a.gap_xs}> 74 + <View 75 + style={[ 76 + {width: 120, height: 16}, 77 + a.rounded_xs, 78 + t.atoms.bg_contrast_25, 79 + a.mt_xs, 80 + ]} 81 + /> 82 + <View 83 + style={[ 84 + {width: 175, height: 12}, 85 + a.rounded_xs, 86 + t.atoms.bg_contrast_25, 87 + ]} 88 + /> 89 + </View> 128 90 </View> 129 - </View> 130 91 131 - <View style={{width: 30}} /> 132 - </> 133 - )} 134 - </View> 92 + <Layout.Header.Slot /> 93 + </> 94 + )} 95 + </View> 96 + </Layout.Header.Outer> 135 97 ) 136 98 } 137 - MessagesListHeader = React.memo(MessagesListHeader) 138 99 139 100 function HeaderReady({ 140 101 profile, ··· 181 142 label={_(msg`View ${displayName}'s profile`)} 182 143 style={[a.flex_row, a.align_start, a.gap_md, a.flex_1, a.pr_md]} 183 144 to={makeProfileLink(profile)}> 184 - <View style={[a.pt_2xs]}> 185 - <PreviewableUserAvatar 186 - size={PFP_SIZE} 187 - profile={profile} 188 - moderation={moderation.ui('avatar')} 189 - disableHoverCard={moderation.blocked} 190 - /> 191 - </View> 192 - <View style={a.flex_1}> 145 + <PreviewableUserAvatar 146 + size={PFP_SIZE} 147 + profile={profile} 148 + moderation={moderation.ui('avatar')} 149 + disableHoverCard={moderation.blocked} 150 + /> 151 + <View style={[a.flex_1]}> 193 152 <View style={[a.flex_row, a.align_center]}> 194 153 <Text 195 154 emoji ··· 215 174 <Text 216 175 style={[ 217 176 t.atoms.text_contrast_medium, 218 - a.text_sm, 177 + a.text_xs, 219 178 web([a.leading_normal, {marginTop: -2}]), 220 179 ]} 221 180 numberOfLines={1}> ··· 235 194 </View> 236 195 </Link> 237 196 238 - {isConvoActive(convoState) && ( 239 - <ConvoMenu 240 - convo={convoState.convo} 241 - profile={profile} 242 - currentScreen="conversation" 243 - blockInfo={blockInfo} 244 - latestReportableMessage={latestReportableMessage} 245 - /> 246 - )} 197 + <View style={[{minHeight: PFP_SIZE}, a.justify_center]}> 198 + <Layout.Header.Slot> 199 + {isConvoActive(convoState) && ( 200 + <ConvoMenu 201 + convo={convoState.convo} 202 + profile={profile} 203 + currentScreen="conversation" 204 + blockInfo={blockInfo} 205 + latestReportableMessage={latestReportableMessage} 206 + /> 207 + )} 208 + </Layout.Header.Slot> 209 + </View> 247 210 </View> 248 211 249 212 <View