Bluesky app fork with some witchin' additions ๐Ÿ’ซ
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[๐Ÿด] Post embeds polish (#4339)

* Handle message cleanup

* Handle last message in chat list

* Memoize lastMessage

authored by

Eric Bailey and committed by
GitHub
de93e8de da96fb1e

+94 -30
+21
src/lib/strings/url-helpers.ts
··· 3 3 import TLDs from 'tlds' 4 4 5 5 import {BSKY_SERVICE} from 'lib/constants' 6 + import {isInvalidHandle} from 'lib/strings/handles' 6 7 7 8 export const BSKY_APP_HOST = 'https://bsky.app' 8 9 const BSKY_TRUSTED_HOSTS = [ ··· 81 82 url = urlp.toString() 82 83 } 83 84 return url 85 + } 86 + 87 + export function toBskyAppUrl(url: string): string { 88 + return new URL(url, BSKY_APP_HOST).toString() 84 89 } 85 90 86 91 export function isBskyAppUrl(url: string): boolean { ··· 180 185 return `/profile/${hostname}/feed/${rkey}` 181 186 } catch { 182 187 return '' 188 + } 189 + } 190 + 191 + export function postUriToRelativePath( 192 + uri: string, 193 + options?: {handle?: string}, 194 + ): string | undefined { 195 + try { 196 + const {hostname, rkey} = new AtUri(uri) 197 + const handleOrDid = 198 + options?.handle && !isInvalidHandle(options.handle) 199 + ? options.handle 200 + : hostname 201 + return `/profile/${handleOrDid}/post/${rkey}` 202 + } catch { 203 + return undefined 183 204 } 184 205 } 185 206
+10 -16
src/screens/Messages/Conversation/MessagesList.tsx
··· 312 312 }) 313 313 314 314 if (postLinkFacet) { 315 - // remove the post link from the text 316 - rt.delete( 317 - postLinkFacet.index.byteStart, 318 - postLinkFacet.index.byteEnd, 319 - ) 315 + const isAtStart = postLinkFacet.index.byteStart === 0 316 + const isAtEnd = 317 + postLinkFacet.index.byteEnd === rt.unicodeText.graphemeLength 320 318 321 - // re-trim the text, now that we've removed the post link 322 - // 323 - // if the post link is at the start of the text, we don't want to leave a leading space 324 - // so trim on both sides 325 - if (postLinkFacet.index.byteStart === 0) { 326 - rt = new RichText({text: rt.text.trim()}, {cleanNewlines: true}) 327 - } else { 328 - // otherwise just trim the end 329 - rt = new RichText( 330 - {text: rt.text.trimEnd()}, 331 - {cleanNewlines: true}, 319 + // remove the post link from the text 320 + if (isAtStart || isAtEnd) { 321 + rt.delete( 322 + postLinkFacet.index.byteStart, 323 + postLinkFacet.index.byteEnd, 332 324 ) 333 325 } 326 + 327 + rt = new RichText({text: rt.text.trim()}, {cleanNewlines: true}) 334 328 } 335 329 } 336 330 } catch (error) {
+63 -14
src/screens/Messages/List/ChatListItem.tsx
··· 2 2 import {GestureResponderEvent, View} from 'react-native' 3 3 import { 4 4 AppBskyActorDefs, 5 + AppBskyEmbedRecord, 5 6 ChatBskyConvoDefs, 6 7 moderateProfile, 7 8 ModerationOpts, ··· 9 10 import {msg} from '@lingui/macro' 10 11 import {useLingui} from '@lingui/react' 11 12 13 + import { 14 + postUriToRelativePath, 15 + toBskyAppUrl, 16 + toShortUrl, 17 + } from '#/lib/strings/url-helpers' 12 18 import {isNative} from '#/platform/detection' 13 19 import {useProfileShadow} from '#/state/cache/profile-shadow' 14 20 import {useModerationOpts} from '#/state/preferences/moderation-opts' ··· 95 101 96 102 const isDimStyle = convo.muted || moderation.blocked || isDeletedAccount 97 103 98 - let lastMessage = _(msg`No messages yet`) 99 - let lastMessageSentAt: string | null = null 100 - if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) { 101 - if (convo.lastMessage.sender?.did === currentAccount?.did) { 102 - lastMessage = _(msg`You: ${convo.lastMessage.text}`) 103 - } else { 104 - lastMessage = convo.lastMessage.text 104 + const {lastMessage, lastMessageSentAt} = React.useMemo(() => { 105 + let lastMessage = _(msg`No messages yet`) 106 + let lastMessageSentAt: string | null = null 107 + 108 + if (ChatBskyConvoDefs.isMessageView(convo.lastMessage)) { 109 + const isFromMe = convo.lastMessage.sender?.did === currentAccount?.did 110 + 111 + if (convo.lastMessage.text) { 112 + if (isFromMe) { 113 + lastMessage = _(msg`You: ${convo.lastMessage.text}`) 114 + } else { 115 + lastMessage = convo.lastMessage.text 116 + } 117 + } else if (convo.lastMessage.embed) { 118 + const defaultEmbeddedContentMessage = _( 119 + msg`(contains embedded content)`, 120 + ) 121 + 122 + if (AppBskyEmbedRecord.isView(convo.lastMessage.embed)) { 123 + const embed = convo.lastMessage.embed 124 + 125 + if (AppBskyEmbedRecord.isViewRecord(embed.record)) { 126 + const record = embed.record 127 + const path = postUriToRelativePath(record.uri, { 128 + handle: record.author.handle, 129 + }) 130 + const href = path ? toBskyAppUrl(path) : undefined 131 + const short = href 132 + ? toShortUrl(href) 133 + : defaultEmbeddedContentMessage 134 + if (isFromMe) { 135 + lastMessage = _(msg`You: ${short}`) 136 + } else { 137 + lastMessage = short 138 + } 139 + } 140 + } else { 141 + if (isFromMe) { 142 + lastMessage = _(msg`You: ${defaultEmbeddedContentMessage}`) 143 + } else { 144 + lastMessage = defaultEmbeddedContentMessage 145 + } 146 + } 147 + } 148 + 149 + lastMessageSentAt = convo.lastMessage.sentAt 150 + } 151 + if (ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage)) { 152 + lastMessage = isDeletedAccount 153 + ? _(msg`Conversation deleted`) 154 + : _(msg`Message deleted`) 155 + } 156 + 157 + return { 158 + lastMessage, 159 + lastMessageSentAt, 105 160 } 106 - lastMessageSentAt = convo.lastMessage.sentAt 107 - } 108 - if (ChatBskyConvoDefs.isDeletedMessageView(convo.lastMessage)) { 109 - lastMessage = isDeletedAccount 110 - ? _(msg`Conversation deleted`) 111 - : _(msg`Message deleted`) 112 - } 161 + }, [_, convo.lastMessage, currentAccount?.did, isDeletedAccount]) 113 162 114 163 const [showActions, setShowActions] = useState(false) 115 164