diff options
author | Minseo Lee <itoupluk427@gmail.com> | 2024-03-02 13:04:51 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-02 13:04:51 +0900 |
commit | ab2b454be8f15ccd4176edce2d28abdce501274b (patch) | |
tree | 41e198f85a4372950ce39a6613d231b2d5932be1 /src/lib | |
parent | 537ae578d6501319e07132ea8b12c280e0755fca (diff) | |
parent | b70c404d4b369d6fab0dfbafd6b31390ffd20014 (diff) | |
download | voidsky-ab2b454be8f15ccd4176edce2d28abdce501274b.tar.zst |
Merge branch 'bluesky-social:main' into patch-3
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/hooks/useIntentHandler.ts | 20 | ||||
-rw-r--r-- | src/lib/moderatePost_wrapped.ts | 145 | ||||
-rw-r--r-- | src/lib/routes/types.ts | 3 | ||||
-rw-r--r-- | src/lib/strings/url-helpers.ts | 12 | ||||
-rw-r--r-- | src/lib/themes.ts | 4 |
5 files changed, 151 insertions, 33 deletions
diff --git a/src/lib/hooks/useIntentHandler.ts b/src/lib/hooks/useIntentHandler.ts index d1e2de31d..8741530b5 100644 --- a/src/lib/hooks/useIntentHandler.ts +++ b/src/lib/hooks/useIntentHandler.ts @@ -15,15 +15,20 @@ export function useIntentHandler() { React.useEffect(() => { const handleIncomingURL = (url: string) => { + // We want to be able to support bluesky:// deeplinks. It's unnatural for someone to use a deeplink with three + // slashes, like bluesky:///intent/follow. However, supporting just two slashes causes us to have to take care + // of two cases when parsing the url. If we ensure there is a third slash, we can always ensure the first + // path parameter is in pathname rather than in hostname. + if (url.startsWith('bluesky://') && !url.startsWith('bluesky:///')) { + url = url.replace('bluesky://', 'bluesky:///') + } + const urlp = new URL(url) - const [_, intentTypeNative, intentTypeWeb] = urlp.pathname.split('/') + const [_, intent, intentType] = urlp.pathname.split('/') // On native, our links look like bluesky://intent/SomeIntent, so we have to check the hostname for the // intent check. On web, we have to check the first part of the path since we have an actual hostname - const intentType = isNative ? intentTypeNative : intentTypeWeb - const isIntent = isNative - ? urlp.hostname === 'intent' - : intentTypeNative === 'intent' + const isIntent = intent === 'intent' const params = urlp.searchParams if (!isIntent) return @@ -69,10 +74,7 @@ function useComposeIntent() { return false } // We also should just filter out cases that don't have all the info we need - if (!VALID_IMAGE_REGEX.test(part)) { - return false - } - return true + return VALID_IMAGE_REGEX.test(part) }) .map(part => { const [uri, width, height] = part.split('|') diff --git a/src/lib/moderatePost_wrapped.ts b/src/lib/moderatePost_wrapped.ts index 92543b42c..9f6fa9c07 100644 --- a/src/lib/moderatePost_wrapped.ts +++ b/src/lib/moderatePost_wrapped.ts @@ -6,6 +6,7 @@ import { AppBskyFeedPost, AppBskyRichtextFacet, AppBskyEmbedImages, + AppBskyEmbedExternal, } from '@atproto/api' type ModeratePost = typeof moderatePost @@ -205,44 +206,151 @@ export function moderatePost_wrapped( if (subject.embed) { let embedHidden = false + let embedMuted = false + let externalMuted = false + if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) { embedHidden = hiddenPosts.includes(subject.embed.record.uri) + } + if ( + AppBskyEmbedRecordWithMedia.isView(subject.embed) && + AppBskyEmbedRecord.isViewRecord(subject.embed.record.record) + ) { + embedHidden = hiddenPosts.includes(subject.embed.record.record.uri) + } + if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) { if (AppBskyFeedPost.isRecord(subject.embed.record.value)) { - embedHidden = - embedHidden || + const embeddedPost = subject.embed.record.value + + embedMuted = + embedMuted || hasMutedWord({ mutedWords, - text: subject.embed.record.value.text, - facets: subject.embed.record.value.facets, - outlineTags: subject.embed.record.value.tags, - languages: subject.embed.record.value.langs, + text: embeddedPost.text, + facets: embeddedPost.facets, + outlineTags: embeddedPost.tags, + languages: embeddedPost.langs, isOwnPost, }) - if (AppBskyEmbedImages.isMain(subject.embed.record.value.embed)) { - for (const image of subject.embed.record.value.embed.images) { - embedHidden = - embedHidden || + if (AppBskyEmbedImages.isMain(embeddedPost.embed)) { + for (const image of embeddedPost.embed.images) { + embedMuted = + embedMuted || hasMutedWord({ mutedWords, text: image.alt, facets: [], outlineTags: [], - languages: subject.embed.record.value.langs, + languages: embeddedPost.langs, isOwnPost, }) } } + + if (AppBskyEmbedExternal.isMain(embeddedPost.embed)) { + const {external} = embeddedPost.embed + + embedMuted = + embedMuted || + hasMutedWord({ + mutedWords, + text: external.title + ' ' + external.description, + facets: [], + outlineTags: [], + languages: [], + isOwnPost, + }) + } + + if (AppBskyEmbedRecordWithMedia.isMain(embeddedPost.embed)) { + if (AppBskyEmbedExternal.isMain(embeddedPost.embed.media)) { + const {external} = embeddedPost.embed.media + + embedMuted = + embedMuted || + hasMutedWord({ + mutedWords, + text: external.title + ' ' + external.description, + facets: [], + outlineTags: [], + languages: [], + isOwnPost, + }) + } + + if (AppBskyEmbedImages.isMain(embeddedPost.embed.media)) { + for (const image of embeddedPost.embed.media.images) { + embedMuted = + embedMuted || + hasMutedWord({ + mutedWords, + text: image.alt, + facets: [], + outlineTags: [], + languages: AppBskyFeedPost.isRecord(embeddedPost.record) + ? embeddedPost.langs + : [], + isOwnPost, + }) + } + } + } } } + + if (AppBskyEmbedExternal.isView(subject.embed)) { + const {external} = subject.embed + + externalMuted = + externalMuted || + hasMutedWord({ + mutedWords, + text: external.title + ' ' + external.description, + facets: [], + outlineTags: [], + languages: [], + isOwnPost, + }) + } + if ( AppBskyEmbedRecordWithMedia.isView(subject.embed) && AppBskyEmbedRecord.isViewRecord(subject.embed.record.record) ) { - // TODO what - embedHidden = hiddenPosts.includes(subject.embed.record.record.uri) + if (AppBskyFeedPost.isRecord(subject.embed.record.record.value)) { + const post = subject.embed.record.record.value + embedMuted = + embedMuted || + hasMutedWord({ + mutedWords, + text: post.text, + facets: post.facets, + outlineTags: post.tags, + languages: post.langs, + isOwnPost, + }) + } + + if (AppBskyEmbedImages.isView(subject.embed.media)) { + for (const image of subject.embed.media.images) { + embedMuted = + embedMuted || + hasMutedWord({ + mutedWords, + text: image.alt, + facets: [], + outlineTags: [], + languages: AppBskyFeedPost.isRecord(subject.record) + ? subject.record.langs + : [], + isOwnPost, + }) + } + } } + if (embedHidden) { moderations.embed.filter = true moderations.embed.blur = true @@ -254,6 +362,17 @@ export function moderatePost_wrapped( priority: 1, } } + } else if (externalMuted || embedMuted) { + moderations.content.filter = true + moderations.content.blur = true + if (!moderations.content.cause) { + moderations.content.cause = { + // @ts-ignore Temporary extension to the moderation system -prf + type: 'muted-word', + source: {type: 'user'}, + priority: 1, + } + } } } diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts index 0ec09f610..6756a62a6 100644 --- a/src/lib/routes/types.ts +++ b/src/lib/routes/types.ts @@ -34,6 +34,7 @@ export type CommonNavigatorParams = { PreferencesThreads: undefined PreferencesExternalEmbeds: undefined Search: {q?: string} + Hashtag: {tag: string; author?: string} } export type BottomTabNavigatorParams = CommonNavigatorParams & { @@ -69,6 +70,7 @@ export type FlatNavigatorParams = CommonNavigatorParams & { Search: {q?: string} Feeds: undefined Notifications: undefined + Hashtag: {tag: string; author?: string} } export type AllNavigatorParams = CommonNavigatorParams & { @@ -81,6 +83,7 @@ export type AllNavigatorParams = CommonNavigatorParams & { NotificationsTab: undefined Notifications: undefined MyProfileTab: undefined + Hashtag: {tag: string; author?: string} } // NOTE diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts index ef341154d..ba2cdb39b 100644 --- a/src/lib/strings/url-helpers.ts +++ b/src/lib/strings/url-helpers.ts @@ -157,17 +157,11 @@ export function linkRequiresWarning(uri: string, label: string) { const host = urip.hostname.toLowerCase() - if (host === 'bsky.app') { + // Hosts that end with bsky.app or bsky.social should be trusted by default. + if (host.endsWith('bsky.app') || host.endsWith('bsky.social')) { // if this is a link to internal content, // warn if it represents itself as a URL to another app - if ( - labelDomain && - labelDomain !== 'bsky.app' && - isPossiblyAUrl(labelDomain) - ) { - return true - } - return false + return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain) } else { // if this is a link to external content, // warn if the label doesnt match the target diff --git a/src/lib/themes.ts b/src/lib/themes.ts index 135d50ab6..bd75aabea 100644 --- a/src/lib/themes.ts +++ b/src/lib/themes.ts @@ -357,8 +357,8 @@ export const dimTheme: Theme = { textVeryLight: dimPalette.contrast_400, replyLine: dimPalette.contrast_200, replyLineDot: dimPalette.contrast_200, - unreadNotifBg: `hsl(211, 48%, 17%)`, - unreadNotifBorder: `hsl(211, 48%, 30%)`, + unreadNotifBg: dimPalette.primary_975, + unreadNotifBorder: dimPalette.primary_900, postCtrl: dimPalette.contrast_500, brandText: dimPalette.primary_500, emptyStateIcon: dimPalette.contrast_300, |