flip the component type imports to the generated lexicons

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-08-04 04:20:42 +03:00
parent dd957dd123
commit e056c43116
109 changed files with 716 additions and 741 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
import {View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
import {useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {MessageContextMenu} from '#/components/dms/MessageContextMenu'
import {useMessageReplies} from '#/components/dms/MessageReplies'
import {SwipeToReply} from '#/components/dms/SwipeToReply'
@@ -15,7 +15,7 @@ export function ActionsWrapper({
moderationOpts,
children,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
isFromSelf: boolean
senderProfile?: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts | undefined
+2 -2
View File
@@ -1,10 +1,10 @@
import {useCallback, useRef, useState} from 'react'
import {Pressable, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {EMOJI_REACTION_LIMIT} from '#/lib/constants'
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
import {useConvoActive} from '#/state/messages/convo'
@@ -29,7 +29,7 @@ export function ActionsWrapper({
moderationOpts,
children,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
isFromSelf: boolean
senderProfile?: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts | undefined
@@ -1,9 +1,9 @@
import {memo, useState} from 'react'
import {View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro'
import {StackActions, useNavigation} from '@react-navigation/native'
import {app} from '#/lexicons'
import {type NavigationProp} from '#/lib/routes/types'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
@@ -113,7 +113,7 @@ function DoneStep({
}: {
convoId: string
currentScreen: 'list' | 'conversation'
profile: AppBskyActorDefs.ProfileViewDetailed
profile: app.bsky.actor.defs.ProfileViewDetailed
}) {
const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>()
+2 -2
View File
@@ -1,9 +1,9 @@
import {memo, useState} from 'react'
import {View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro'
import {StackActions, useNavigation} from '@react-navigation/native'
import {app} from '#/lexicons'
import {type NavigationProp} from '#/lib/routes/types'
import {useProfileShadow} from '#/state/cache/profile-shadow'
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
@@ -116,7 +116,7 @@ function DoneStep({
}: {
convoId: string
currentScreen: 'list' | 'conversation'
profile: AppBskyActorDefs.ProfileViewDetailed
profile: app.bsky.actor.defs.ProfileViewDetailed
}) {
const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>()
+4 -2
View File
@@ -1,7 +1,8 @@
import {View} from 'react-native'
import {ChatBskyGroupDefs} from '@atproto/api'
import {Plural, Trans} from '@lingui/react/macro'
import * as bsky from '#/types/bsky'
import {chat} from '#/lexicons'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -21,7 +22,8 @@ export function Card({size}: {size: 'large' | 'small'}) {
const t = useTheme()
const {preview, hasFixedHeight} = useChatInvite()
if (!ChatBskyGroupDefs.isJoinLinkPreviewView(preview)) return null
if (!bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview))
return null
const ownerDisplayName = createSanitizedDisplayName(preview.owner)
const ownerHandle = sanitizeHandle(preview.owner.handle, '@')
+4 -3
View File
@@ -1,8 +1,9 @@
import {setStringAsync} from 'expo-clipboard'
import {ChatBskyGroupDefs} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native'
import * as bsky from '#/types/bsky'
import {chat} from '#/lexicons'
import {type NavigationProp} from '#/lib/routes/types'
import {
type ChatInvitePreview,
@@ -71,7 +72,7 @@ export function Root({
status = 'loading'
} else if (error) {
status = 'error'
} else if (ChatBskyGroupDefs.isJoinLinkPreviewView(preview)) {
} else if (bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview)) {
status = 'available'
} else {
// Resolved to a disabled/invalid/unrecognized preview - nothing to join.
@@ -79,7 +80,7 @@ export function Root({
}
let action: ChatInviteAction | undefined
if (ChatBskyGroupDefs.isJoinLinkPreviewView(preview)) {
if (bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, preview)) {
const convoId = preview.convo?.id
const isFollowing = preview.owner.viewer?.followedBy ?? false
const hasRequested = !convoId && preview.viewer?.requestedAt != null
+2 -2
View File
@@ -1,9 +1,9 @@
import {useMemo, useState} from 'react'
import {useWindowDimensions, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {chat} from '#/lexicons'
import {useSession} from '#/state/session'
import {atoms as a, tokens, useTheme} from '#/alf'
import * as ContextMenu from '#/components/ContextMenu'
@@ -21,7 +21,7 @@ export function EmojiReactionPicker({
message,
onEmojiSelect,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
children?: TriggerProps['children']
onEmojiSelect: (emoji: string) => void
}) {
@@ -1,9 +1,9 @@
import {useState} from 'react'
import {Pressable, View} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import {DropdownMenu} from 'radix-ui'
import {chat} from '#/lexicons'
import {useSession} from '#/state/session'
import {atoms as a, flatten, useTheme} from '#/alf'
import * as EmojiPicker from '#/components/EmojiPicker'
@@ -17,7 +17,7 @@ export function EmojiReactionPicker({
children,
onEmojiSelect,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
children?: EmojiPicker.TriggerProps['children']
onEmojiSelect: (emoji: string) => void
}) {
@@ -40,7 +40,7 @@ function MenuInner({
message,
onEmojiSelect,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
onEmojiSelect: (emoji: string) => void
}) {
const t = useTheme()
+2 -2
View File
@@ -2,12 +2,12 @@ import {memo, useCallback} from 'react'
import {Platform} from 'react-native'
import {type GestureType} from 'react-native-gesture-handler'
import * as Clipboard from 'expo-clipboard'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
import {RichText} from '@bsky.app/sdk/richtext'
import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {EMOJI_REACTION_LIMIT} from '#/lib/constants'
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
import {asSdkFacets, richTextToString} from '#/lib/strings/rich-text-helpers'
@@ -39,7 +39,7 @@ export let MessageContextMenu = ({
children,
swipeGesture,
}: {
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
senderProfile?: bsky.profile.AnyProfileView
moderationOpts: ModerationOpts | undefined
children: TriggerProps['children']
+55 -41
View File
@@ -22,17 +22,13 @@ import Animated, {
ZoomIn,
ZoomOut,
} from 'react-native-reanimated'
import {
AppBskyEmbedRecord,
type ChatBskyActorDefs,
ChatBskyConvoDefs,
ChatBskyEmbedJoinLink,
} from '@atproto/api'
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
import {plural} from '@lingui/core/macro'
import {Trans, useLingui} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query'
import * as bsky from '#/types/bsky'
import {app, chat} from '#/lexicons'
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {moderateProfile} from '#/lib/moderation/subjects'
@@ -77,16 +73,19 @@ const SQUARED_BORDER_RADIUS = 4
const DISPLAY_NAME_INSET = 20
export type MessageItemNeighbor =
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView
| chat.bsky.convo.defs.MessageView
| chat.bsky.convo.defs.DeletedMessageView
| null
function messageIsReply(message: MessageItemNeighbor): boolean {
return (
ChatBskyConvoDefs.isMessageView(message) &&
(ChatBskyConvoDefs.isMessageView(message.replyTo) ||
ChatBskyConvoDefs.isDeletedMessageView(message.replyTo) ||
ChatBskyConvoDefs.isMessageBeforeUserJoinedGroupView(message.replyTo))
bsky.isType(chat.bsky.convo.defs.messageView, message) &&
(bsky.isType(chat.bsky.convo.defs.messageView, message.replyTo) ||
bsky.isType(chat.bsky.convo.defs.deletedMessageView, message.replyTo) ||
bsky.isType(
chat.bsky.convo.defs.messageBeforeUserJoinedGroupView,
message.replyTo,
))
)
}
@@ -98,7 +97,7 @@ function isWithinClusterBoundary({
direction,
}: {
isPending: boolean
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
adjacentMessage: MessageItemNeighbor
isFromSameSender: boolean
direction: 'prev' | 'next'
@@ -110,7 +109,7 @@ function isWithinClusterBoundary({
return true
}
if (!isFromSameSender) return true
if (ChatBskyConvoDefs.isMessageView(adjacentMessage)) {
if (bsky.isType(chat.bsky.convo.defs.messageView, adjacentMessage)) {
const currentSentAt = message.sentAt
const thisDate = new Date(currentSentAt)
const adjDate = new Date(adjacentMessage.sentAt)
@@ -137,7 +136,7 @@ let MessageItem = ({
isGroupChat?: boolean
prevMessage: MessageItemNeighbor
nextMessage: MessageItemNeighbor
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
}): React.ReactNode => {
const t = useTheme()
const {currentAccount} = useSession()
@@ -155,13 +154,17 @@ let MessageItem = ({
// tombstone, or a before-joined placeholder. Narrow away the open-union
// fallback so we only render shapes we understand.
const replyTo =
ChatBskyConvoDefs.isMessageView(message.replyTo) ||
ChatBskyConvoDefs.isDeletedMessageView(message.replyTo) ||
ChatBskyConvoDefs.isMessageBeforeUserJoinedGroupView(message.replyTo)
bsky.isType(chat.bsky.convo.defs.messageView, message.replyTo) ||
bsky.isType(chat.bsky.convo.defs.deletedMessageView, message.replyTo) ||
bsky.isType(
chat.bsky.convo.defs.messageBeforeUserJoinedGroupView,
message.replyTo,
)
? message.replyTo
: undefined
const replyToMessageId =
replyTo && !ChatBskyConvoDefs.isMessageBeforeUserJoinedGroupView(replyTo)
replyTo &&
!bsky.isType(chat.bsky.convo.defs.messageBeforeUserJoinedGroupView, replyTo)
? replyTo.id
: undefined
const onPressReplyTo = replyToMessageId
@@ -175,8 +178,14 @@ let MessageItem = ({
const isFromSelf =
message.sender?.did != null && message.sender.did === currentAccount?.did
const prevIsMessage = ChatBskyConvoDefs.isMessageView(prevMessage)
const nextIsMessage = ChatBskyConvoDefs.isMessageView(nextMessage)
const prevIsMessage = bsky.isType(
chat.bsky.convo.defs.messageView,
prevMessage,
)
const nextIsMessage = bsky.isType(
chat.bsky.convo.defs.messageView,
nextMessage,
)
const isPrevFromSameSender =
prevIsMessage &&
@@ -204,7 +213,7 @@ let MessageItem = ({
})
const hasLargeGapFromPrev =
!ChatBskyConvoDefs.isMessageView(prevMessage) ||
!bsky.isType(chat.bsky.convo.defs.messageView, prevMessage) ||
new Date(message.sentAt).getTime() -
new Date(prevMessage.sentAt).getTime() >
MESSAGE_GAP_THRESHOLD_MS
@@ -254,8 +263,8 @@ let MessageItem = ({
const isEmojiOnly = isOnlyEmoji(message.text)
const hasEmbed =
AppBskyEmbedRecord.isView(message.embed) ||
ChatBskyEmbedJoinLink.isView(message.embed)
bsky.isType(app.bsky.embed.record.view, message.embed) ||
bsky.isType(chat.bsky.embed.joinLink.view, message.embed)
const hasEmbedAndText = hasEmbed && rt.text.length > 0
const targetBottomRadius = squaredBottomCorner
@@ -516,7 +525,7 @@ let MessageItem = ({
message={message}
senderProfile={profile}
moderationOpts={moderationOpts}>
{AppBskyEmbedRecord.isView(message.embed) && (
{bsky.isType(app.bsky.embed.record.view, message.embed) && (
<MessageItemEmbed
embed={message.embed}
isFromSelf={isFromSelf}
@@ -528,7 +537,10 @@ let MessageItem = ({
highlightSV={highlightSV}
/>
)}
{ChatBskyEmbedJoinLink.isView(message.embed) && (
{bsky.isType(
chat.bsky.embed.joinLink.view,
message.embed,
) && (
<MessageItemInviteEmbed
embed={message.embed}
isFromSelf={isFromSelf}
@@ -666,7 +678,7 @@ function BlockedPlaceholder({
profile,
style,
}: {
profile: Shadow<ChatBskyActorDefs.ProfileViewBasic>
profile: Shadow<chat.bsky.actor.defs.ProfileViewBasic>
style?: AnimatedStyle<ViewStyle>
}) {
const {t: l} = useLingui()
@@ -776,13 +788,13 @@ function ReplyCaption({
onPress,
}: {
replyTo:
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView
| ChatBskyConvoDefs.MessageBeforeUserJoinedGroupView
| chat.bsky.convo.defs.MessageView
| chat.bsky.convo.defs.DeletedMessageView
| chat.bsky.convo.defs.MessageBeforeUserJoinedGroupView
isFromSelf: boolean
isGroupChat: boolean
replierDisplayName: string | null
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
onPress?: () => void
}) {
const t = useTheme()
@@ -791,8 +803,8 @@ function ReplyCaption({
let caption: string = ''
if (
ChatBskyConvoDefs.isMessageView(replyTo) ||
ChatBskyConvoDefs.isDeletedMessageView(replyTo)
bsky.isType(chat.bsky.convo.defs.messageView, replyTo) ||
bsky.isType(chat.bsky.convo.defs.deletedMessageView, replyTo)
) {
const originalSenderIsSelf = replyTo.sender.did === currentAccount?.did
const originalProfile = relatedProfiles.get(replyTo.sender.did)
@@ -865,11 +877,11 @@ function ReplyQuote({
onPress,
}: {
replyTo:
| ChatBskyConvoDefs.MessageView
| ChatBskyConvoDefs.DeletedMessageView
| ChatBskyConvoDefs.MessageBeforeUserJoinedGroupView
| chat.bsky.convo.defs.MessageView
| chat.bsky.convo.defs.DeletedMessageView
| chat.bsky.convo.defs.MessageBeforeUserJoinedGroupView
isFromSelf: boolean
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
onPress?: () => void
}) {
const t = useTheme()
@@ -877,8 +889,8 @@ function ReplyQuote({
const getReplyPreviewText = useReplyPreviewText()
const senderDid =
ChatBskyConvoDefs.isMessageView(replyTo) ||
ChatBskyConvoDefs.isDeletedMessageView(replyTo)
bsky.isType(chat.bsky.convo.defs.messageView, replyTo) ||
bsky.isType(chat.bsky.convo.defs.deletedMessageView, replyTo)
? replyTo.sender.did
: undefined
const senderProfile = useMaybeProfileShadow(
@@ -908,9 +920,11 @@ function ReplyQuote({
comment: 'A reply summary in chat',
})
subtle = true
} else if (ChatBskyConvoDefs.isMessageView(replyTo)) {
} else if (bsky.isType(chat.bsky.convo.defs.messageView, replyTo)) {
;({text, subtle} = getReplyPreviewText(replyTo))
} else if (ChatBskyConvoDefs.isMessageBeforeUserJoinedGroupView(replyTo)) {
} else if (
bsky.isType(chat.bsky.convo.defs.messageBeforeUserJoinedGroupView, replyTo)
) {
text = l({
message: `(message sent before you joined)`,
comment: 'A reply summary in chat',
+3 -2
View File
@@ -5,8 +5,9 @@ import Animated, {
type SharedValue,
useAnimatedStyle,
} from 'react-native-reanimated'
import {type $Typed, type AppBskyEmbedRecord} from '@atproto/api'
import {type $Typed} from '@atproto/lex'
import {app} from '#/lexicons'
import {atoms as a, native, useTheme, web} from '#/alf'
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
import {MessageContextProvider} from './MessageContext'
@@ -22,7 +23,7 @@ let MessageItemEmbed = ({
squaredBottomCorner,
highlightSV,
}: {
embed: $Typed<AppBskyEmbedRecord.View>
embed: $Typed<app.bsky.embed.record.View>
isFromSelf: boolean
isGroupChat: boolean
squaredTopCorner: boolean
@@ -5,8 +5,9 @@ import Animated, {
type SharedValue,
useAnimatedStyle,
} from 'react-native-reanimated'
import {type $Typed, type ChatBskyEmbedJoinLink} from '@atproto/api'
import {type $Typed} from '@atproto/lex'
import {chat} from '#/lexicons'
import {useConvoActive} from '#/state/messages/convo'
import {isKnownJoinLinkPreview} from '#/state/queries/join-links'
import {atoms as a, native, useTheme, web} from '#/alf'
@@ -24,7 +25,7 @@ let MessageItemInviteEmbed = ({
squaredBottomCorner,
highlightSV,
}: {
embed: $Typed<ChatBskyEmbedJoinLink.View>
embed: $Typed<chat.bsky.embed.joinLink.View>
isFromSelf: boolean
isGroupChat: boolean
squaredTopCorner: boolean
+11 -11
View File
@@ -7,10 +7,10 @@ import {
useState,
} from 'react'
import {LayoutAnimation} from 'react-native'
import {type ChatBskyConvoDefs} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query'
import {chat} from '#/lexicons'
import {useConvoActive} from '#/state/messages/convo'
import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
import {useDialogControl} from '#/components/Dialog'
@@ -23,12 +23,12 @@ import * as Toast from '#/components/Toast'
import type * as bsky from '#/types/bsky'
type MessageDialogsContextType = {
openDeleteMessage: (message: ChatBskyConvoDefs.MessageView) => void
openDeleteMessage: (message: chat.bsky.convo.defs.MessageView) => void
openReportMessage: (
message: ChatBskyConvoDefs.MessageView,
message: chat.bsky.convo.defs.MessageView,
senderProfile: bsky.profile.AnyProfileView | undefined,
) => void
openReactions: (message: ChatBskyConvoDefs.MessageView) => void
openReactions: (message: chat.bsky.convo.defs.MessageView) => void
}
const Context = createContext<MessageDialogsContextType | null>(null)
@@ -52,18 +52,18 @@ export function MessageOverlays({children}: {children: React.ReactNode}) {
const reactionsControl = useDialogControl()
const [deleteTarget, setDeleteTarget] =
useState<ChatBskyConvoDefs.MessageView | null>(null)
useState<chat.bsky.convo.defs.MessageView | null>(null)
const [reportTarget, setReportTarget] = useState<{
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
senderProfile: bsky.profile.AnyProfileView | undefined
} | null>(null)
const [afterReportTarget, setAfterReportTarget] =
useState<ChatBskyConvoDefs.MessageView | null>(null)
useState<chat.bsky.convo.defs.MessageView | null>(null)
const [reactionsTarget, setReactionsTarget] =
useState<ChatBskyConvoDefs.MessageView | null>(null)
useState<chat.bsky.convo.defs.MessageView | null>(null)
const openDeleteMessage = useCallback(
(message: ChatBskyConvoDefs.MessageView) => {
(message: chat.bsky.convo.defs.MessageView) => {
setDeleteTarget(message)
deleteControl.open()
},
@@ -72,7 +72,7 @@ export function MessageOverlays({children}: {children: React.ReactNode}) {
const openReportMessage = useCallback(
(
message: ChatBskyConvoDefs.MessageView,
message: chat.bsky.convo.defs.MessageView,
senderProfile: bsky.profile.AnyProfileView | undefined,
) => {
setReportTarget({message, senderProfile})
@@ -82,7 +82,7 @@ export function MessageOverlays({children}: {children: React.ReactNode}) {
)
const openReactions = useCallback(
(message: ChatBskyConvoDefs.MessageView) => {
(message: chat.bsky.convo.defs.MessageView) => {
setReactionsTarget(message)
},
[],
+2 -2
View File
@@ -1,11 +1,11 @@
import {useCallback} from 'react'
import {View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native'
import {app} from '#/lexicons'
import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification'
import {type NavigationProp} from '#/lib/routes/types'
import {useGetConvoAvailabilityQuery} from '#/state/queries/messages/get-convo-availability'
@@ -20,7 +20,7 @@ import {useAnalytics} from '#/analytics'
export function MessageProfileButton({
profile,
}: {
profile: AppBskyActorDefs.ProfileViewDetailed
profile: app.bsky.actor.defs.ProfileViewDetailed
}) {
const {_} = useLingui()
const t = useTheme()
+6 -7
View File
@@ -1,3 +1,4 @@
import {chat} from '#/lexicons'
import {
createContext,
useCallback,
@@ -7,7 +8,6 @@ import {
useRef,
useState,
} from 'react'
import {type ChatBskyConvoDefs} from '@atproto/api'
/**
* How long a message stays highlighted after scrolling to it, before the flash
@@ -28,8 +28,8 @@ type MessageRepliesContextType = {
/**
* The message currently staged for reply in the composer, or null.
*/
replyTo: ChatBskyConvoDefs.MessageView | null
setReply: (message: ChatBskyConvoDefs.MessageView) => void
replyTo: chat.bsky.convo.defs.MessageView | null
setReply: (message: chat.bsky.convo.defs.MessageView) => void
clearReply: () => void
/**
* Scroll the list to a message, if it's currently loaded, and flash it. No-op
@@ -66,9 +66,8 @@ export function MessageRepliesProvider({
*/
scrollToMessage: (messageId: string) => boolean
}) {
const [replyTo, setReplyTo] = useState<ChatBskyConvoDefs.MessageView | null>(
null,
)
const [replyTo, setReplyTo] =
useState<chat.bsky.convo.defs.MessageView | null>(null)
const [highlightedMessage, setHighlightedMessage] =
useState<HighlightedMessage | null>(null)
const highlightKey = useRef(0)
@@ -76,7 +75,7 @@ export function MessageRepliesProvider({
null,
)
const setReply = useCallback((message: ChatBskyConvoDefs.MessageView) => {
const setReply = useCallback((message: chat.bsky.convo.defs.MessageView) => {
setReplyTo(message)
}, [])
+8 -8
View File
@@ -6,9 +6,9 @@ import {
useWindowDimensions,
View,
} from 'react-native'
import {type ChatBskyActorDefs, type ChatBskyConvoDefs} from '@atproto/api'
import {Trans, useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {HITSLOP_10} from '#/lib/constants'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -28,7 +28,7 @@ import type * as bsky from '#/types/bsky'
type Reaction = {
key: string
value: string
senders: ChatBskyConvoDefs.ReactionViewSender[]
senders: chat.bsky.convo.defs.ReactionViewSender[]
count: number
}
@@ -41,8 +41,8 @@ export function ReactionsDialog({
onClose,
}: {
control: Dialog.DialogControlProps
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
message: ChatBskyConvoDefs.MessageView
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
message: chat.bsky.convo.defs.MessageView
onClose?: () => void
}) {
const {t: l} = useLingui()
@@ -142,10 +142,10 @@ function ReactionRow({
control: Dialog.DialogControlProps
convo: ActiveConvoStates
currentAccount?: SessionAccount
message: ChatBskyConvoDefs.MessageView
message: chat.bsky.convo.defs.MessageView
profile: bsky.profile.AnyProfileView
reaction: ChatBskyConvoDefs.ReactionView
allReactions: ChatBskyConvoDefs.ReactionView[]
reaction: chat.bsky.convo.defs.ReactionView
allReactions: chat.bsky.convo.defs.ReactionView[]
selected: string
setSelected: React.Dispatch<React.SetStateAction<string>>
}) {
@@ -398,7 +398,7 @@ function ReactionTab({
}
export function groupReactions(
reactions: ChatBskyConvoDefs.ReactionView[] | undefined,
reactions: chat.bsky.convo.defs.ReactionView[] | undefined,
): Reaction[] {
const grouped = new Map<string, Reaction>()
for (const reaction of reactions ?? []) {
+2 -2
View File
@@ -7,10 +7,10 @@ import Animated, {
useDerivedValue,
withTiming,
} from 'react-native-reanimated'
import {type ChatBskyActorDefs} from '@atproto/api'
import {plural} from '@lingui/core/macro'
import {useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {HITSLOP_10} from '#/lib/constants'
import {type SystemMessageGroupItem} from '#/screens/Messages/components/groupSystemMessages'
import {atoms as a, useTheme} from '#/alf'
@@ -29,7 +29,7 @@ export function SystemMessageGroup({
item: SystemMessageGroupItem
expanded: boolean
onToggle: (key: string) => void
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
}) {
const t = useTheme()
const {t: l} = useLingui()
+2 -2
View File
@@ -1,7 +1,7 @@
import {View} from 'react-native'
import {type ChatBskyActorDefs} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import {chat} from '#/lexicons'
import {makeProfileLink} from '#/lib/routes/links'
import {type ConvoItem} from '#/state/messages/convo/types'
import {useInviteLinkDialog} from '#/screens/Messages/components/InviteLinkDialogProvider'
@@ -16,7 +16,7 @@ export function SystemMessageItem({
relatedProfiles,
}: {
item: ConvoItem & {type: 'system-message'}
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>
}) {
const t = useTheme()
const {i18n, t: l} = useLingui()
+10 -15
View File
@@ -1,12 +1,7 @@
import {
AppBskyEmbedRecord,
type ChatBskyActorDefs,
ChatBskyConvoDefs,
ChatBskyEmbedJoinLink,
} from '@atproto/api'
import {type I18n} from '@lingui/core'
import {msg} from '@lingui/core/macro'
import {app, chat} from '#/lexicons'
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {
@@ -14,12 +9,12 @@ import {
toBskyAppUrl,
toShortUrl,
} from '#/lib/strings/url-helpers'
import type * as bsky from '#/types/bsky'
import * as bsky from '#/types/bsky'
export type UserMessageInfo = {
message: string | null
sentAt: string
reportableMessage?: ChatBskyConvoDefs.MessageView
reportableMessage?: chat.bsky.convo.defs.MessageView
isBlockedMessage: boolean
}
@@ -36,7 +31,7 @@ export function isDidBlockedInConvo({
primaryProfile,
}: {
did: string | undefined
members: ChatBskyActorDefs.ProfileViewBasic[]
members: chat.bsky.actor.defs.ProfileViewBasic[]
primaryProfile?: bsky.profile.AnyProfileView
}): boolean {
if (!did) return false
@@ -53,12 +48,12 @@ export function getMessageInfo({
primaryProfile,
i18n,
}: {
convo: ChatBskyConvoDefs.ConvoView
convo: chat.bsky.convo.defs.ConvoView
currentAccountDid: string | undefined
primaryProfile?: bsky.profile.AnyProfileView
i18n: I18n
}): UserMessageInfo | null {
if (!ChatBskyConvoDefs.isMessageView(convo.lastMessage)) {
if (!bsky.isType(chat.bsky.convo.defs.messageView, convo.lastMessage)) {
return null
}
@@ -67,7 +62,7 @@ export function getMessageInfo({
const senderDid = lastMessage.sender?.did
const sender = convo.members.find(m => m.did === senderDid)
const name = sender ? createSanitizedDisplayName(sender) : null
const isGroup = ChatBskyConvoDefs.isGroupConvo(convo.kind)
const isGroup = bsky.isType(chat.bsky.convo.defs.groupConvo, convo.kind)
const reportableMessage = isFromMe ? undefined : lastMessage
const isBlockedMessage = isDidBlockedInConvo({
@@ -105,10 +100,10 @@ export function getMessageInfo({
msg`(contains embedded content)`,
)
if (AppBskyEmbedRecord.isView(lastMessage.embed)) {
if (bsky.isType(app.bsky.embed.record.view, lastMessage.embed)) {
const embed = lastMessage.embed
if (AppBskyEmbedRecord.isViewRecord(embed.record)) {
if (bsky.isType(app.bsky.embed.record.viewRecord, embed.record)) {
const record = embed.record
const path = postUriToRelativePath(record.uri, {
handle: record.author.handle,
@@ -119,7 +114,7 @@ export function getMessageInfo({
} else {
message = prefix(defaultEmbeddedContentMessage)
}
} else if (ChatBskyEmbedJoinLink.isView(lastMessage.embed)) {
} else if (bsky.isType(chat.bsky.embed.joinLink.view, lastMessage.embed)) {
message = prefix(i18n._(msg`(chat invite link)`))
} else {
message = prefix(defaultEmbeddedContentMessage)
+9 -4
View File
@@ -1,10 +1,10 @@
import {ChatBskyConvoDefs} from '@atproto/api'
import {type I18n} from '@lingui/core'
import {msg} from '@lingui/core/macro'
import {chat} from '#/lexicons'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {isDidBlockedInConvo} from '#/components/dms/getMessageInfo'
import type * as bsky from '#/types/bsky'
import * as bsky from '#/types/bsky'
export type UserReactionInfo = {
message: string
@@ -18,12 +18,17 @@ export function getReactionInfo({
primaryProfile,
i18n,
}: {
convo: ChatBskyConvoDefs.ConvoView
convo: chat.bsky.convo.defs.ConvoView
currentAccountDid: string | undefined
primaryProfile?: bsky.profile.AnyProfileView
i18n: I18n
}): UserReactionInfo | null {
if (!ChatBskyConvoDefs.isMessageAndReactionView(convo.lastReaction)) {
if (
!bsky.isType(
chat.bsky.convo.defs.messageAndReactionView,
convo.lastReaction,
)
) {
return null
}
+44 -18
View File
@@ -1,7 +1,8 @@
import {type ChatBskyActorDefs, ChatBskyConvoDefs} from '@atproto/api'
import {type MessageDescriptor} from '@lingui/core'
import {msg} from '@lingui/core/macro'
import * as bsky from '#/types/bsky'
import {chat} from '#/lexicons'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {ArrowBoxLeft_Stroke2_Corner0_Rounded as LeaveIcon} from '#/components/icons/ArrowBoxLeft'
import {ArrowBoxRight_Stroke2_Corner3_Rounded as JoinIcon} from '#/components/icons/ArrowBoxRight'
@@ -19,7 +20,7 @@ import {PencilLine_Stroke2_Corner0_Rounded as PencilIcon} from '#/components/ico
export type SystemMessageAction =
| {
kind: 'profile'
profile: ChatBskyActorDefs.ProfileViewBasic
profile: chat.bsky.actor.defs.ProfileViewBasic
displayName: string
}
| {kind: 'inviteLink'}
@@ -31,8 +32,8 @@ export type SystemMessageInfo = {
}
function getProfileAction(
user: ChatBskyConvoDefs.SystemMessageReferredUser,
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>,
user: chat.bsky.convo.defs.SystemMessageReferredUser,
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>,
): Extract<SystemMessageAction, {kind: 'profile'}> | null {
const profile = relatedProfiles.get(user.did)
if (!profile) return null
@@ -44,11 +45,11 @@ function getProfileAction(
}
export function getSystemMessageInfo(
data: ChatBskyConvoDefs.SystemMessageView['data'],
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>,
data: chat.bsky.convo.defs.SystemMessageView['data'],
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>,
opts = {short: false},
): SystemMessageInfo | null {
if (ChatBskyConvoDefs.isSystemMessageDataAddMember(data)) {
if (bsky.isType(chat.bsky.convo.defs.systemMessageDataAddMember, data)) {
const action = getProfileAction(data.member, relatedProfiles)
return {
Icon: JoinIcon,
@@ -61,7 +62,9 @@ export function getSystemMessageInfo(
: msg`Someone was added to the group`,
action: action ?? undefined,
}
} else if (ChatBskyConvoDefs.isSystemMessageDataRemoveMember(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataRemoveMember, data)
) {
const action = getProfileAction(data.member, relatedProfiles)
return {
Icon: LeaveIcon,
@@ -74,7 +77,9 @@ export function getSystemMessageInfo(
: msg`Someone was removed from the group`,
action: action ?? undefined,
}
} else if (ChatBskyConvoDefs.isSystemMessageDataMemberJoin(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataMemberJoin, data)
) {
const action = getProfileAction(data.member, relatedProfiles)
return {
Icon: JoinIcon,
@@ -87,7 +92,9 @@ export function getSystemMessageInfo(
: msg`Someone joined the group`,
action: action ?? undefined,
}
} else if (ChatBskyConvoDefs.isSystemMessageDataMemberLeave(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataMemberLeave, data)
) {
const action = getProfileAction(data.member, relatedProfiles)
return {
Icon: LeaveIcon,
@@ -100,13 +107,24 @@ export function getSystemMessageInfo(
: msg`Someone left the group`,
action: action ?? undefined,
}
} else if (ChatBskyConvoDefs.isSystemMessageDataLockConvo(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataLockConvo, data)
) {
return {Icon: LockIcon, message: msg`Chat locked`}
} else if (ChatBskyConvoDefs.isSystemMessageDataUnlockConvo(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataUnlockConvo, data)
) {
return {Icon: UnlockIcon, message: msg`Chat unlocked`}
} else if (ChatBskyConvoDefs.isSystemMessageDataLockConvoPermanently(data)) {
} else if (
bsky.isType(
chat.bsky.convo.defs.systemMessageDataLockConvoPermanently,
data,
)
) {
return {Icon: LockIcon, message: msg`Chat ended`}
} else if (ChatBskyConvoDefs.isSystemMessageDataEditGroup(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataEditGroup, data)
) {
return {
Icon: PencilIcon,
message:
@@ -114,25 +132,33 @@ export function getSystemMessageInfo(
? msg`Chat title changed to ${data.newName}`
: msg`Chat title changed`,
}
} else if (ChatBskyConvoDefs.isSystemMessageDataCreateJoinLink(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataCreateJoinLink, data)
) {
return {
Icon: ChainLinkIcon,
message: msg`Invite link created`,
action: {kind: 'inviteLink'},
}
} else if (ChatBskyConvoDefs.isSystemMessageDataEditJoinLink(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataEditJoinLink, data)
) {
return {
Icon: ChainLinkIcon,
message: msg`Invite link edited`,
action: {kind: 'inviteLink'},
}
} else if (ChatBskyConvoDefs.isSystemMessageDataEnableJoinLink(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataEnableJoinLink, data)
) {
return {
Icon: ChainLinkIcon,
message: msg`Invite link enabled`,
action: {kind: 'inviteLink'},
}
} else if (ChatBskyConvoDefs.isSystemMessageDataDisableJoinLink(data)) {
} else if (
bsky.isType(chat.bsky.convo.defs.systemMessageDataDisableJoinLink, data)
) {
return {
Icon: ChainLinkBrokenIcon,
message: msg`Invite link disabled`,
+24 -17
View File
@@ -1,12 +1,7 @@
import {
AppBskyEmbedExternal,
AppBskyEmbedRecord,
type ChatBskyConvoDefs,
ChatBskyEmbedJoinLink,
ChatBskyGroupDefs,
} from '@atproto/api'
import {useLingui} from '@lingui/react/macro'
import * as bsky from '#/types/bsky'
import {app, chat} from '#/lexicons'
import {BSKY_APP_HOST, toShortUrl} from '#/lib/strings/url-helpers'
/**
@@ -21,13 +16,13 @@ type ReplyEmbedSummary =
| {type: 'unknown'}
function summarizeReplyEmbed(
embed: ChatBskyConvoDefs.MessageView['embed'],
embed: chat.bsky.convo.defs.MessageView['embed'],
): ReplyEmbedSummary {
if (!AppBskyEmbedRecord.isView(embed)) return {type: 'unknown'}
if (!bsky.isType(app.bsky.embed.record.view, embed)) return {type: 'unknown'}
const {record} = embed
if (AppBskyEmbedRecord.isViewRecord(record)) {
if (bsky.isType(app.bsky.embed.record.viewRecord, record)) {
const inner = record.embeds?.[0]
if (AppBskyEmbedExternal.isView(inner)) {
if (bsky.isType(app.bsky.embed.external.view, inner)) {
return {type: 'external', uri: inner.external.uri}
}
return {type: 'post'}
@@ -45,25 +40,32 @@ function summarizeReplyEmbed(
* callers can render it in a muted/italic style.
*/
export function useReplyPreviewText(): (
message: ChatBskyConvoDefs.MessageView,
message: chat.bsky.convo.defs.MessageView,
) => {text: string; subtle: boolean} {
const {t: l} = useLingui()
return (message: ChatBskyConvoDefs.MessageView) => {
return (message: chat.bsky.convo.defs.MessageView) => {
const text = message.text
if (text.trim()) {
return {text, subtle: false}
}
if (ChatBskyEmbedJoinLink.isView(message.embed)) {
if (bsky.isType(chat.bsky.embed.joinLink.view, message.embed)) {
const {joinLinkPreview} = message.embed
if (ChatBskyGroupDefs.isJoinLinkPreviewView(joinLinkPreview)) {
if (
bsky.isType(chat.bsky.group.defs.joinLinkPreviewView, joinLinkPreview)
) {
return {
text: `${BSKY_APP_HOST}/chat/${joinLinkPreview.code}`,
subtle: true,
}
}
if (ChatBskyGroupDefs.isDisabledJoinLinkPreviewView(joinLinkPreview)) {
if (
bsky.isType(
chat.bsky.group.defs.disabledJoinLinkPreviewView,
joinLinkPreview,
)
) {
return {
text: l({
message: '(disabled chat invite link)',
@@ -72,7 +74,12 @@ export function useReplyPreviewText(): (
subtle: true,
}
}
if (ChatBskyGroupDefs.isInvalidJoinLinkPreviewView(joinLinkPreview)) {
if (
bsky.isType(
chat.bsky.group.defs.invalidJoinLinkPreviewView,
joinLinkPreview,
)
) {
return {
text: l({
message: '(invalid chat invite link)',
+19 -33
View File
@@ -1,6 +1,7 @@
import {type $Typed, ChatBskyActorDefs, ChatBskyConvoDefs} from '@atproto/api'
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
import {type $Typed} from '@atproto/lex'
import {chat} from '#/lexicons'
import {EMOJI_REACTION_LIMIT} from '#/lib/constants'
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
import {moderateProfile} from '#/lib/moderation/subjects'
@@ -77,7 +78,7 @@ export function localDateString(date: Date) {
}
export function hasAlreadyReacted(
message: ChatBskyConvoDefs.MessageView,
message: chat.bsky.convo.defs.MessageView,
myDid: string | undefined,
emoji: string,
): boolean {
@@ -98,9 +99,9 @@ export function hasAlreadyReacted(
* already render anonymously ("Someone reacted").
*/
export function filterBlockedReactions(
reactions: ChatBskyConvoDefs.ReactionView[] | undefined,
relatedProfiles: Map<string, ChatBskyActorDefs.ProfileViewBasic>,
): ChatBskyConvoDefs.ReactionView[] {
reactions: chat.bsky.convo.defs.ReactionView[] | undefined,
relatedProfiles: Map<string, chat.bsky.actor.defs.ProfileViewBasic>,
): chat.bsky.convo.defs.ReactionView[] {
if (!reactions) return []
return reactions.filter(reaction => {
const profile = relatedProfiles.get(reaction.sender.did)
@@ -109,7 +110,7 @@ export function filterBlockedReactions(
}
export function hasReachedReactionLimit(
message: ChatBskyConvoDefs.MessageView,
message: chat.bsky.convo.defs.MessageView,
myDid: string | undefined,
): boolean {
if (!message.reactions) {
@@ -170,25 +171,25 @@ export function canReact({
return true
}
export type GroupConvoMember = ChatBskyActorDefs.ProfileViewBasic & {
export type GroupConvoMember = chat.bsky.actor.defs.ProfileViewBasic & {
// can be missing if account deleted
kind?: $Typed<ChatBskyActorDefs.GroupConvoMember>
kind?: $Typed<chat.bsky.actor.defs.GroupConvoMember>
}
export type DirectConvoMember = ChatBskyActorDefs.ProfileViewBasic & {
kind: $Typed<ChatBskyActorDefs.DirectConvoMember>
export type DirectConvoMember = chat.bsky.actor.defs.ProfileViewBasic & {
kind: $Typed<chat.bsky.actor.defs.DirectConvoMember>
}
export type ConvoWithDetails = {view: ChatBskyConvoDefs.ConvoView} & (
export type ConvoWithDetails = {view: chat.bsky.convo.defs.ConvoView} & (
| {
kind: 'group'
details: $Typed<ChatBskyConvoDefs.GroupConvo>
details: $Typed<chat.bsky.convo.defs.GroupConvo>
primaryMember?: GroupConvoMember // the owner - may have left, thus optional
members: Array<GroupConvoMember>
}
| {
kind: 'direct'
details: $Typed<ChatBskyConvoDefs.DirectConvo>
details: $Typed<chat.bsky.convo.defs.DirectConvo>
primaryMember: DirectConvoMember // the other user
members: Array<DirectConvoMember>
}
@@ -199,24 +200,14 @@ export type ConvoWithDetails = {view: ChatBskyConvoDefs.ConvoView} & (
* and enforces the correct type for convo members.
*/
export function parseConvoView(
convoView: ChatBskyConvoDefs.ConvoView,
convoView: chat.bsky.convo.defs.ConvoView,
ownDid: string | undefined,
): ConvoWithDetails | null {
if (
bsky.dangerousIsType<ChatBskyConvoDefs.GroupConvo>(
convoView.kind,
ChatBskyConvoDefs.isGroupConvo,
)
) {
if (bsky.isType(chat.bsky.convo.defs.groupConvo, convoView.kind)) {
let owner: GroupConvoMember | undefined = undefined
for (const member of convoView.members) {
if (
bsky.dangerousIsType<ChatBskyActorDefs.GroupConvoMember>(
member.kind,
ChatBskyActorDefs.isGroupConvoMember,
)
) {
if (bsky.isType(chat.bsky.actor.defs.groupConvoMember, member.kind)) {
if (member.kind.role === 'owner') {
// have to do a type assertion here
// this works: {...member, kind: member.kind}
@@ -238,12 +229,7 @@ export function parseConvoView(
primaryMember: owner,
members: convoView.members as Array<GroupConvoMember>,
}
} else if (
bsky.dangerousIsType<ChatBskyConvoDefs.DirectConvo>(
convoView.kind,
ChatBskyConvoDefs.isDirectConvo,
)
) {
} else if (bsky.isType(chat.bsky.convo.defs.directConvo, convoView.kind)) {
const otherUser = convoView.members.find(m => m.did !== ownDid)
if (!otherUser) {
@@ -286,7 +272,7 @@ export function getConvoReportSubject(
const lastMessage = convo.view.lastMessage
const reportableMessage =
ChatBskyConvoDefs.isMessageView(lastMessage) &&
bsky.isType(chat.bsky.convo.defs.messageView, lastMessage) &&
lastMessage.sender?.did !== ownDid
? lastMessage
: null