Sam's crash testbed

(cherry picked from commit b0a0cb7799cd900777570cae7dc10461cf811e0f)
This commit is contained in:
Samuel Newman
2025-10-21 12:40:49 +03:00
committed by Eric Bailey
parent 1838f4a6dc
commit cc2c9828a0
4 changed files with 238 additions and 162 deletions
+113 -7
View File
@@ -3,6 +3,7 @@ import '#/logger/bitdrift/setup'
import '#/view/icons' import '#/view/icons'
import React, {useEffect, useState} from 'react' import React, {useEffect, useState} from 'react'
import {View} from 'react-native'
import {GestureHandlerRootView} from 'react-native-gesture-handler' import {GestureHandlerRootView} from 'react-native-gesture-handler'
import { import {
initialWindowMetrics, initialWindowMetrics,
@@ -60,22 +61,26 @@ import {Provider as ProgressGuideProvider} from '#/state/shell/progress-guide'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed' import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {Provider as StarterPackProvider} from '#/state/shell/starter-pack' import {Provider as StarterPackProvider} from '#/state/shell/starter-pack'
import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies' import {Provider as HiddenRepliesProvider} from '#/state/threadgate-hidden-replies'
import {TestCtrls} from '#/view/com/testing/TestCtrls'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {Shell} from '#/view/shell' import {atoms as a, ThemeProvider as Alf} from '#/alf'
import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme' import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {Button, ButtonText} from '#/components/Button'
import {Provider as ContextMenuProvider} from '#/components/ContextMenu' import {Provider as ContextMenuProvider} from '#/components/ContextMenu'
import {NuxDialogs} from '#/components/dialogs/nuxs' import * as Dialog from '#/components/Dialog'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs' import {Provider as IntentDialogProvider} from '#/components/intents/IntentDialogs'
import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay' import {Provider as PolicyUpdateOverlayProvider} from '#/components/PolicyUpdateOverlay'
import {Outlet as PortalOutlet} from '#/components/Portal'
import {Provider as PortalProvider} from '#/components/Portal' import {Provider as PortalProvider} from '#/components/Portal'
import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
import {ToastOutlet} from '#/components/Toast' import {ToastOutlet} from '#/components/Toast'
import {Splash} from '#/Splash' import {Splash} from '#/Splash'
import {BottomSheetOutlet} from '../modules/bottom-sheet'
import {BottomSheetProvider} from '../modules/bottom-sheet' import {BottomSheetProvider} from '../modules/bottom-sheet'
import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
import {useApplyPullRequestOTAUpdate} from './lib/hooks/useOTAUpdates'
import {RequestListItem} from './screens/Messages/components/RequestListItem'
import {List} from './view/com/util/List'
SplashScreen.preventAutoHideAsync() SplashScreen.preventAutoHideAsync()
if (isIOS) { if (isIOS) {
@@ -164,10 +169,10 @@ function InnerApp() {
style={s.h100pct}> style={s.h100pct}>
<GlobalGestureEventsProvider> <GlobalGestureEventsProvider>
<IntentDialogProvider> <IntentDialogProvider>
<TestCtrls /> <Testbed />
<Shell />
<NuxDialogs />
<ToastOutlet /> <ToastOutlet />
<PortalOutlet />
<BottomSheetOutlet />
</IntentDialogProvider> </IntentDialogProvider>
</GlobalGestureEventsProvider> </GlobalGestureEventsProvider>
</GestureHandlerRootView> </GestureHandlerRootView>
@@ -252,3 +257,104 @@ function App() {
} }
export default Sentry.wrap(App) export default Sentry.wrap(App)
function Testbed() {
const control = Dialog.useDialogControl()
const [showItem, setShowItem] = useState(true)
const {revertToEmbedded} = useApplyPullRequestOTAUpdate()
return (
<View style={[a.align_center, a.justify_center, {gap: 16}, a.h_full]}>
<Button
label="show dialog"
onPress={() => {
control.open()
}}
size="large"
color="primary">
<ButtonText>Show dialog</ButtonText>
</Button>
<Button
label="toggle list item + show toast"
onPress={() => {
Toast.show('toggle list item')
setShowItem(x => !x)
}}
size="large"
color="primary">
<ButtonText>toggle list item + show toast</ButtonText>
</Button>
<List
style={[{width: '100%', height: 300}, a.flex_grow_0]}
data={showItem ? [true] : []}
renderItem={() => (
<RequestListItem
convo={{
id: 'abc',
members: [{did: 'did:plc:abc', handle: 'alice.example.com'}],
muted: false,
rev: '1',
unreadCount: 0,
}}
/>
)}
/>
<Button
label="revert to embedded js"
onPress={() => revertToEmbedded()}
size="large"
color="secondary">
<ButtonText>revert to embedded js</ButtonText>
</Button>
<Dialog.Outer control={control}>
<Dialog.Handle />
<Dialog.ScrollableInner
label=""
style={{height: 300}}
contentContainerStyle={{gap: 12}}>
<Button
label="show dialog"
onPress={() => Toast.show('Hello')}
size="large"
color="secondary">
<ButtonText>Show dialog</ButtonText>
</Button>
<Button
label="close dialog"
onPress={() => {
Toast.show('closing')
control.close()
}}
size="large"
color="primary">
<ButtonText>Close - toast before</ButtonText>
</Button>
<Button
label="close dialog"
onPress={() => {
control.close(() => {
Toast.show('closed')
})
}}
size="large"
color="primary">
<ButtonText>Close - toast after</ButtonText>
</Button>
<Button
label="close dialog"
onPress={() => {
control.close(() => {
setShowItem(false)
Toast.show('closed')
})
}}
size="large"
color="primary">
<ButtonText>Close - close + hide item</ButtonText>
</Button>
</Dialog.ScrollableInner>
</Dialog.Outer>
</View>
)
}
@@ -30,16 +30,14 @@ import {
import {precacheProfile} from '#/state/queries/profile' import {precacheProfile} from '#/state/queries/profile'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {TimeElapsed} from '#/view/com/util/TimeElapsed' import {TimeElapsed} from '#/view/com/util/TimeElapsed'
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' import {atoms as a, useTheme, web} from '#/alf'
import * as tokens from '#/alf/tokens' import * as tokens from '#/alf/tokens'
import {Button} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {ConvoMenu} from '#/components/dms/ConvoMenu'
import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2' import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2'
import {Envelope_Open_Stroke2_Corner0_Rounded as EnvelopeOpen} from '#/components/icons/EnveopeOpen' import {Envelope_Open_Stroke2_Corner0_Rounded as EnvelopeOpen} from '#/components/icons/EnveopeOpen'
import {Trash_Stroke2_Corner0_Rounded} from '#/components/icons/Trash' import {Trash_Stroke2_Corner0_Rounded} from '#/components/icons/Trash'
import {Link} from '#/components/Link'
import {useMenuControl} from '#/components/Menu' import {useMenuControl} from '#/components/Menu'
import {PostAlerts} from '#/components/moderation/PostAlerts' import {PostAlerts} from '#/components/moderation/PostAlerts'
import {createPortalGroup} from '#/components/Portal' import {createPortalGroup} from '#/components/Portal'
@@ -87,7 +85,6 @@ function ChatListItemReady({
convo, convo,
profile: profileUnshadowed, profile: profileUnshadowed,
moderationOpts, moderationOpts,
showMenu,
children, children,
}: { }: {
convo: ChatBskyConvoDefs.ConvoView convo: ChatBskyConvoDefs.ConvoView
@@ -101,7 +98,6 @@ function ChatListItemReady({
const {currentAccount} = useSession() const {currentAccount} = useSession()
const menuControl = useMenuControl() const menuControl = useMenuControl()
const leaveConvoControl = useDialogControl() const leaveConvoControl = useDialogControl()
const {gtMobile} = useBreakpoints()
const profile = useProfileShadow(profileUnshadowed) const profile = useProfileShadow(profileUnshadowed)
const {mutate: markAsRead} = useMarkAsReadMutation() const {mutate: markAsRead} = useMarkAsReadMutation()
const moderation = React.useMemo( const moderation = React.useMemo(
@@ -115,17 +111,6 @@ function ChatListItemReady({
profile, profile,
}) })
const blockInfo = useMemo(() => {
const modui = moderation.ui('profileView')
const blocks = modui.alerts.filter(alert => alert.type === 'blocking')
const listBlocks = blocks.filter(alert => alert.source.type === 'list')
const userBlock = blocks.find(alert => alert.source.type === 'user')
return {
listBlocks,
userBlock,
}
}, [moderation])
const isDeletedAccount = profile.handle === 'missing.invalid' const isDeletedAccount = profile.handle === 'missing.invalid'
const displayName = isDeletedAccount const displayName = isDeletedAccount
? _(msg`Deleted Account`) ? _(msg`Deleted Account`)
@@ -136,13 +121,12 @@ function ChatListItemReady({
const isDimStyle = convo.muted || moderation.blocked || isDeletedAccount const isDimStyle = convo.muted || moderation.blocked || isDeletedAccount
const {lastMessage, lastMessageSentAt, latestReportableMessage} = const {lastMessage, lastMessageSentAt} = useMemo(() => {
useMemo(() => {
// eslint-disable-next-line @typescript-eslint/no-shadow // eslint-disable-next-line @typescript-eslint/no-shadow
let lastMessage = _(msg`No messages yet`) let lastMessage = _(msg`No messages yet`)
// eslint-disable-next-line @typescript-eslint/no-shadow // eslint-disable-next-line @typescript-eslint/no-shadow
let lastMessageSentAt: string | null = null let lastMessageSentAt: string | null = null
// eslint-disable-next-line @typescript-eslint/no-shadow
let latestReportableMessage: ChatBskyConvoDefs.MessageView | undefined let latestReportableMessage: ChatBskyConvoDefs.MessageView | undefined
if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) { if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) {
@@ -226,9 +210,7 @@ function ChatListItemReady({
) )
} else { } else {
const senderDid = convo.lastReaction.reaction.sender.did const senderDid = convo.lastReaction.reaction.sender.did
const sender = convo.members.find( const sender = convo.members.find(member => member.did === senderDid)
member => member.did === senderDid,
)
if (sender) { if (sender) {
lastMessage = _( lastMessage = _(
msg`${sanitizeDisplayName( msg`${sanitizeDisplayName(
@@ -266,7 +248,7 @@ function ChatListItemReady({
convo.members, convo.members,
]) ])
const [showActions, setShowActions] = useState(false) const [_showActions, setShowActions] = useState(false)
const onMouseEnter = useCallback(() => { const onMouseEnter = useCallback(() => {
setShowActions(true) setShowActions(true)
@@ -349,15 +331,14 @@ function ChatListItemReady({
a.absolute, a.absolute,
{top: tokens.space.md, left: tokens.space.lg}, {top: tokens.space.md, left: tokens.space.lg},
]}> ]}>
<PreviewableUserAvatar <UserAvatar
profile={profile} type="user"
size={52} size={52}
moderation={moderation.ui('avatar')} moderation={moderation.ui('avatar')}
/> />
</View> </View>
<Link <Button
to={`/messages/${convo.id}`}
label={displayName} label={displayName}
accessibilityHint={ accessibilityHint={
!isDeletedAccount !isDeletedAccount
@@ -509,10 +490,10 @@ function ChatListItemReady({
)} )}
</View> </View>
)} )}
</Link> </Button>
<ChatListItemPortal.Outlet /> <ChatListItemPortal.Outlet />
{/*
{showMenu && ( {showMenu && (
<ConvoMenu <ConvoMenu
convo={convo} convo={convo}
@@ -535,12 +516,12 @@ function ChatListItemReady({
]} ]}
latestReportableMessage={latestReportableMessage} latestReportableMessage={latestReportableMessage}
/> />
)} )}*/}
<LeaveConvoPrompt {/*<LeaveConvoPrompt
control={leaveConvoControl} control={leaveConvoControl}
convoId={convo.id} convoId={convo.id}
currentScreen="list" currentScreen="list"
/> />*/}
</View> </View>
</GestureActionView> </GestureActionView>
</ChatListItemPortal.Provider> </ChatListItemPortal.Provider>
@@ -2,10 +2,8 @@ import {useCallback} from 'react'
import {type ChatBskyActorDefs, ChatBskyConvoDefs} from '@atproto/api' import {type ChatBskyActorDefs, ChatBskyConvoDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {StackActions, useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {type NavigationProp} from '#/lib/routes/types'
import {useProfileShadow} from '#/state/cache/profile-shadow' import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useEmail} from '#/state/email-verification' import {useEmail} from '#/state/email-verification'
import {useAcceptConversation} from '#/state/queries/messages/accept-conversation' import {useAcceptConversation} from '#/state/queries/messages/accept-conversation'
@@ -50,11 +48,11 @@ export function RejectMenu({
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const shadowedProfile = useProfileShadow(profile) const shadowedProfile = useProfileShadow(profile)
const navigation = useNavigation<NavigationProp>() // const navigation = useNavigation<NavigationProp>()
const {mutate: leaveConvo} = useLeaveConvo(convo.id, { const {mutate: leaveConvo} = useLeaveConvo(convo.id, {
onMutate: () => { onMutate: () => {
if (currentScreen === 'conversation') { if (currentScreen === 'conversation') {
navigation.dispatch(StackActions.pop()) // navigation.dispatch(StackActions.pop())
} }
}, },
onError: () => { onError: () => {
@@ -192,7 +190,7 @@ export function AcceptChatButton({
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const navigation = useNavigation<NavigationProp>() // const navigation = useNavigation<NavigationProp>()
const {needsEmailVerification} = useEmail() const {needsEmailVerification} = useEmail()
const emailDialogControl = useEmailDialogControl() const emailDialogControl = useEmailDialogControl()
@@ -201,10 +199,10 @@ export function AcceptChatButton({
onAcceptConvo?.() onAcceptConvo?.()
if (currentScreen === 'list') { if (currentScreen === 'list') {
precacheConvoQuery(queryClient, {...convo, status: 'accepted'}) precacheConvoQuery(queryClient, {...convo, status: 'accepted'})
navigation.navigate('MessagesConversation', { // navigation.navigate('MessagesConversation', {
conversation: convo.id, // conversation: convo.id,
accept: true, // accept: true,
}) // })
} }
}, },
onError: () => { onError: () => {
@@ -272,12 +270,12 @@ export function DeleteChatButton({
currentScreen: 'list' | 'conversation' currentScreen: 'list' | 'conversation'
}) { }) {
const {_} = useLingui() const {_} = useLingui()
const navigation = useNavigation<NavigationProp>() // const navigation = useNavigation<NavigationProp>()
const {mutate: leaveConvo} = useLeaveConvo(convo.id, { const {mutate: leaveConvo} = useLeaveConvo(convo.id, {
onMutate: () => { onMutate: () => {
if (currentScreen === 'conversation') { if (currentScreen === 'conversation') {
navigation.dispatch(StackActions.pop()) // navigation.dispatch(StackActions.pop())
} }
}, },
onError: () => { onError: () => {
@@ -5,7 +5,6 @@ import {Trans} from '@lingui/macro'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {atoms as a, tokens} from '#/alf' import {atoms as a, tokens} from '#/alf'
import {KnownFollowers} from '#/components/KnownFollowers'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {ChatListItem, ChatListItemPortal} from './ChatListItem' import {ChatListItem, ChatListItemPortal} from './ChatListItem'
import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons' import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons'
@@ -27,14 +26,6 @@ export function RequestListItem({convo}: {convo: ChatBskyConvoDefs.ConvoView}) {
return ( return (
<View style={[a.relative, a.flex_1]}> <View style={[a.relative, a.flex_1]}>
<ChatListItem convo={convo} showMenu={false}> <ChatListItem convo={convo} showMenu={false}>
<View style={[a.pt_xs, a.pb_2xs]}>
<KnownFollowers
profile={otherUser}
moderationOpts={moderationOpts}
minimal
showIfEmpty
/>
</View>
{/* spacer, since you can't nest pressables */} {/* spacer, since you can't nest pressables */}
<View style={[a.pt_md, a.pb_xs, a.w_full, {opacity: 0}]} aria-hidden> <View style={[a.pt_md, a.pb_xs, a.w_full, {opacity: 0}]} aria-hidden>
{/* Placeholder text so that it responds to the font height */} {/* Placeholder text so that it responds to the font height */}