[SDK] Remove @atproto/api (#11386)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Codemod to replace BskyAgent with AtpAgent
|
||||
*
|
||||
* Before:
|
||||
* import {BskyAgent} from '@atproto/api`
|
||||
* BskyAgent.appLabelers.includes(labeler)
|
||||
*
|
||||
* After:
|
||||
* import {AtpAgent} from '@atproto/api`
|
||||
* AtpAgent.appLabelers.includes(labeler)
|
||||
*
|
||||
* Handles import specifiers, type annotations, static member access
|
||||
* (BskyAgent.configure), `extends BskyAgent`, and `new BskyAgent()`. Whole
|
||||
* identifiers only, so names like `OpaqueBskyAgent` are left untouched.
|
||||
*
|
||||
* Usage: jscodeshift -t .jscodeshift/repo/bsky-agent.js <file-path>
|
||||
* Example: jscodeshift -t .jscodeshift/repo/bsky-agent.js src/lib/moderation.ts
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
export const parser = 'tsx'
|
||||
|
||||
export default function transformer(file, api) {
|
||||
const j = api.jscodeshift
|
||||
const root = j(file.source)
|
||||
|
||||
// Replace every standalone `BskyAgent` identifier with `AtpAgent`. This
|
||||
// covers imports, type references, member expressions, `extends`, and `new`.
|
||||
root
|
||||
.find(j.Identifier, {name: 'BskyAgent'})
|
||||
.replaceWith(() => j.identifier('AtpAgent'))
|
||||
|
||||
// Renaming can leave a duplicate `AtpAgent` specifier on the @atproto/api
|
||||
// import if the file already imported it. Dedupe by imported name, keeping
|
||||
// the type-only modifier only if every duplicate was type-only.
|
||||
root
|
||||
.find(j.ImportDeclaration, {source: {value: '@atproto/api'}})
|
||||
.forEach(path => {
|
||||
const seen = new Map()
|
||||
for (const spec of path.value.specifiers) {
|
||||
if (spec.type !== 'ImportSpecifier') {
|
||||
seen.set(Symbol(), spec)
|
||||
continue
|
||||
}
|
||||
const name = spec.imported.name
|
||||
const existing = seen.get(name)
|
||||
if (!existing) {
|
||||
seen.set(name, spec)
|
||||
} else if (
|
||||
existing.importKind === 'type' &&
|
||||
spec.importKind !== 'type'
|
||||
) {
|
||||
// Prefer the value (non-type) import if either usage needs it.
|
||||
seen.set(name, spec)
|
||||
}
|
||||
}
|
||||
path.value.specifiers = Array.from(seen.values())
|
||||
})
|
||||
|
||||
return root.toSource()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {RichText} from '@atproto/api'
|
||||
import {RichText} from '@bsky.app/sdk/richtext'
|
||||
import {i18n} from '@lingui/core'
|
||||
|
||||
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
||||
|
||||
@@ -6,48 +6,31 @@
|
||||
"type": "object",
|
||||
"required": ["uri"],
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string",
|
||||
"format": "at-uri"
|
||||
}
|
||||
"uri": { "type": "string", "format": "at-uri" }
|
||||
}
|
||||
},
|
||||
"skeletonSearchActor": {
|
||||
"type": "object",
|
||||
"required": ["did"],
|
||||
"properties": {
|
||||
"did": {
|
||||
"type": "string",
|
||||
"format": "did"
|
||||
}
|
||||
"did": { "type": "string", "format": "did" }
|
||||
}
|
||||
},
|
||||
"skeletonSearchStarterPack": {
|
||||
"type": "object",
|
||||
"required": ["uri"],
|
||||
"properties": {
|
||||
"uri": {
|
||||
"type": "string",
|
||||
"format": "at-uri"
|
||||
}
|
||||
"uri": { "type": "string", "format": "at-uri" }
|
||||
}
|
||||
},
|
||||
"trendingTopic": {
|
||||
"type": "object",
|
||||
"required": ["topic", "link"],
|
||||
"properties": {
|
||||
"topic": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
}
|
||||
"topic": { "type": "string" },
|
||||
"displayName": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"link": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"skeletonTrend": {
|
||||
@@ -61,32 +44,14 @@
|
||||
"dids"
|
||||
],
|
||||
"properties": {
|
||||
"topic": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
},
|
||||
"startedAt": {
|
||||
"type": "string",
|
||||
"format": "datetime"
|
||||
},
|
||||
"postCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"knownValues": ["hot"]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"topic": { "type": "string" },
|
||||
"displayName": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"link": { "type": "string" },
|
||||
"startedAt": { "type": "string", "format": "datetime" },
|
||||
"postCount": { "type": "integer" },
|
||||
"status": { "type": "string", "knownValues": ["hot"] },
|
||||
"category": { "type": "string" },
|
||||
"dids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -107,32 +72,14 @@
|
||||
"actors"
|
||||
],
|
||||
"properties": {
|
||||
"topic": {
|
||||
"type": "string"
|
||||
},
|
||||
"displayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"link": {
|
||||
"type": "string"
|
||||
},
|
||||
"startedAt": {
|
||||
"type": "string",
|
||||
"format": "datetime"
|
||||
},
|
||||
"postCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"knownValues": ["hot"]
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"topic": { "type": "string" },
|
||||
"displayName": { "type": "string" },
|
||||
"description": { "type": "string" },
|
||||
"link": { "type": "string" },
|
||||
"startedAt": { "type": "string", "format": "datetime" },
|
||||
"postCount": { "type": "integer" },
|
||||
"status": { "type": "string", "knownValues": ["hot"] },
|
||||
"category": { "type": "string" },
|
||||
"actors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -153,10 +100,7 @@
|
||||
"mutedByViewer"
|
||||
],
|
||||
"properties": {
|
||||
"post": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.feed.defs#postView"
|
||||
},
|
||||
"post": { "type": "ref", "ref": "app.bsky.feed.defs#postView" },
|
||||
"moreParents": {
|
||||
"type": "boolean",
|
||||
"description": "This post has more parents that were not present in the response. This is just a boolean, without the number of parents."
|
||||
@@ -167,7 +111,15 @@
|
||||
},
|
||||
"opThread": {
|
||||
"type": "boolean",
|
||||
"description": "This post is part of a contiguous thread by the OP from the thread root. Many different OP threads can happen in the same thread."
|
||||
"description": "This post is part of a contiguous thread by the OP from the thread root. Sub-threads by OP deeper in the tree are not considered an OP thread."
|
||||
},
|
||||
"opThreadPostIndex": {
|
||||
"type": "integer",
|
||||
"description": "The 1-indexed position of this post within the contiguous OP thread. Only present when this post is part of the OP thread (see `opThread`)."
|
||||
},
|
||||
"opThreadPostCount": {
|
||||
"type": "integer",
|
||||
"description": "The total number of posts in the contiguous OP thread that this post belongs to. Only present when this post is part of the OP thread (see `opThread`)."
|
||||
},
|
||||
"hiddenByThreadgate": {
|
||||
"type": "boolean",
|
||||
@@ -191,10 +143,7 @@
|
||||
"type": "object",
|
||||
"required": ["author"],
|
||||
"properties": {
|
||||
"author": {
|
||||
"type": "ref",
|
||||
"ref": "app.bsky.feed.defs#blockedAuthor"
|
||||
}
|
||||
"author": { "type": "ref", "ref": "app.bsky.feed.defs#blockedAuthor" }
|
||||
}
|
||||
},
|
||||
"ageAssuranceState": {
|
||||
|
||||
@@ -1645,7 +1645,7 @@
|
||||
"count": 8
|
||||
},
|
||||
"typescript/no-unsafe-member-access": {
|
||||
"count": 9
|
||||
"count": 8
|
||||
}
|
||||
},
|
||||
"src/view/com/util/EmptyState.tsx": {
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
"prettier": "prettier --check ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@atproto/api": "0.20.39",
|
||||
"@atproto/common-web": "0.5.9",
|
||||
"@atproto/lex": "0.3.6",
|
||||
"@atproto/lex-password-session": "0.2.0",
|
||||
|
||||
Generated
-43
@@ -242,9 +242,6 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@atproto/api':
|
||||
specifier: 0.20.39
|
||||
version: 0.20.39
|
||||
'@atproto/common-web':
|
||||
specifier: 0.5.9
|
||||
version: 0.5.9
|
||||
@@ -908,10 +905,6 @@ packages:
|
||||
resolution: {integrity: sha512-vfvoDhu6ds6BT3Pqe+d2/LBU1WpDRtt69y6zltlfMCoucPm82m1j50/Wb6xTvv+oZ+2j0JyZVXsmXQ12SWYQJg==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
'@atproto/api@0.20.39':
|
||||
resolution: {integrity: sha512-FRjwAmYe0kKlWsAe8IvfbmAAKyjpXnl2NV67vWEEjux0FwIEIG6JbOo6YkD5tjK2xjL0Daa429R0E8phmxRrrQ==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
'@atproto/common-web@0.5.9':
|
||||
resolution: {integrity: sha512-2c5C6YV8352JJz9Z5fNfcsstllaKGAb3cQW9aO7unMAGh/FzTGFq+xOwNMW2lTeagO6z530uxYm8AiSRM6O+DQ==}
|
||||
engines: {node: '>=22'}
|
||||
@@ -973,10 +966,6 @@ packages:
|
||||
engines: {node: '>=22'}
|
||||
hasBin: true
|
||||
|
||||
'@atproto/lexicon@0.7.11':
|
||||
resolution: {integrity: sha512-ukCZMCWmiu7fAlssBbLs+IMaf2K2R9mADaTKz2jEeC/xeZ3jT77Ka0S2G+ELBB+Dc9ijBACU0iPMQLhquOkuzQ==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
'@atproto/repo@0.10.11':
|
||||
resolution: {integrity: sha512-QqDzEv8d6NUuqZ0xvWG+n8DfWd4Vuka04nyuD9oglKsj5avB1zbEsWx3Oit1oYtZFUf9JSVWMDqMXhu3UbB+lA==}
|
||||
engines: {node: '>=22'}
|
||||
@@ -985,10 +974,6 @@ packages:
|
||||
resolution: {integrity: sha512-EHsEHtasH/DGPljBYecVDjweGMQ5eTu6Ns0GZ5z0qdqpOI8ipBvldWnMIxWkA+5HfZ9Dsu4V1MX0WP7wgL8cuA==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
'@atproto/xrpc@0.8.10':
|
||||
resolution: {integrity: sha512-++FNpTVF61fF8+3Kk1RYtdTO7xyUTdIc/Cmfk2CMn29Qw9tZD8bmW+M5db1Z0okYWFWK8Wqu7bc9VmF8tUB8Jg==}
|
||||
engines: {node: '>=22'}
|
||||
|
||||
'@babel/code-frame@7.10.4':
|
||||
resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==}
|
||||
|
||||
@@ -4320,9 +4305,6 @@ packages:
|
||||
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
await-lock@3.0.0:
|
||||
resolution: {integrity: sha512-eO6fLiSnrJrMdjWMNK8zbVRXPs2TKJg78iKZd9wDpN3na5tcoV6EoeiOlMgk2QaAQ1gIrK1YuMsJHXWqz89tSA==}
|
||||
|
||||
babel-jest@29.7.0:
|
||||
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
@@ -9754,17 +9736,6 @@ snapshots:
|
||||
|
||||
'@atproto-labs/simple-store@0.5.1': {}
|
||||
|
||||
'@atproto/api@0.20.39':
|
||||
dependencies:
|
||||
'@atproto/common-web': 0.5.9
|
||||
'@atproto/lexicon': 0.7.11
|
||||
'@atproto/syntax': 0.7.4
|
||||
'@atproto/xrpc': 0.8.10
|
||||
await-lock: 3.0.0
|
||||
multiformats: 13.4.2
|
||||
tlds: 1.261.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@atproto/common-web@0.5.9':
|
||||
dependencies:
|
||||
'@atproto/lex-data': 0.1.7
|
||||
@@ -9875,13 +9846,6 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
yargs: 18.1.0
|
||||
|
||||
'@atproto/lexicon@0.7.11':
|
||||
dependencies:
|
||||
'@atproto/common-web': 0.5.9
|
||||
'@atproto/syntax': 0.7.4
|
||||
multiformats: 13.4.2
|
||||
zod: 3.25.76
|
||||
|
||||
'@atproto/repo@0.10.11':
|
||||
dependencies:
|
||||
'@atproto/common': 0.8.0
|
||||
@@ -9898,11 +9862,6 @@ snapshots:
|
||||
iso-datestring-validator: 2.2.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@atproto/xrpc@0.8.10':
|
||||
dependencies:
|
||||
'@atproto/lexicon': 0.7.11
|
||||
zod: 3.25.76
|
||||
|
||||
'@babel/code-frame@7.10.4':
|
||||
dependencies:
|
||||
'@babel/highlight': 7.25.9
|
||||
@@ -13788,8 +13747,6 @@ snapshots:
|
||||
dependencies:
|
||||
possible-typed-array-names: 1.1.0
|
||||
|
||||
await-lock@3.0.0: {}
|
||||
|
||||
babel-jest@29.7.0(@babel/core@7.29.0(supports-color@8.1.1))(supports-color@8.1.1):
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0(supports-color@8.1.1)
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import {
|
||||
ageAssuranceRuleIDs as ids,
|
||||
type AppBskyAgeassuranceDefs,
|
||||
} from '@atproto/api'
|
||||
|
||||
import {AgeAssuranceAccess} from '#/ageAssurance/types'
|
||||
import {
|
||||
ANDROID_API_LEVEL,
|
||||
@@ -11,6 +6,7 @@ import {
|
||||
IS_IOS,
|
||||
IS_WEB,
|
||||
} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* Minimum age required to access the app at all.
|
||||
@@ -44,19 +40,17 @@ export const AGE_ASSURANCE_PLATFORM: 'web' | 'ios' | 'android' = IS_WEB
|
||||
export const DEVICE_SIGNALS_SUPPORTED: boolean =
|
||||
(IS_IOS && IOS_MAJOR_VERSION >= 26) || (IS_ANDROID && ANDROID_API_LEVEL >= 23)
|
||||
|
||||
export const FALLBACK_REGION_CONFIG: AppBskyAgeassuranceDefs.ConfigRegion = {
|
||||
export const FALLBACK_REGION_CONFIG: app.bsky.ageassurance.defs.ConfigRegion = {
|
||||
countryCode: '*',
|
||||
regionCode: undefined,
|
||||
minAccessAge: MIN_ACCESS_AGE,
|
||||
rules: [
|
||||
{
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: MIN_ACCESS_AGE,
|
||||
access: AgeAssuranceAccess.Full,
|
||||
},
|
||||
{
|
||||
$type: ids.Default,
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: AgeAssuranceAccess.None,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
+18
-26
@@ -1,11 +1,5 @@
|
||||
import {createContext, useCallback, useContext, useEffect, useMemo} from 'react'
|
||||
import * as AgeRange from 'expo-age-range'
|
||||
import {
|
||||
type AppBskyAgeassuranceDefs,
|
||||
type AppBskyAgeassuranceGetConfig,
|
||||
type AppBskyAgeassuranceGetState,
|
||||
type ChatBskyActorDeclaration,
|
||||
} from '@atproto/api'
|
||||
import {type Client} from '@atproto/lex'
|
||||
import {getPreferences} from '@bsky.app/sdk'
|
||||
import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister'
|
||||
@@ -38,7 +32,7 @@ import {
|
||||
} from '#/ageAssurance/util'
|
||||
import {IS_DEV} from '#/env'
|
||||
import {useGeolocation} from '#/geolocation'
|
||||
import {app} from '#/lexicons'
|
||||
import {app, type chat} from '#/lexicons'
|
||||
import {device} from '#/storage'
|
||||
|
||||
/**
|
||||
@@ -102,14 +96,12 @@ export async function getConfig() {
|
||||
* before there is any session (and while logged out), so it goes through the
|
||||
* process-wide public client rather than a bundle one.
|
||||
*/
|
||||
return (await getPublicAppviewClient().call(
|
||||
app.bsky.ageassurance.getConfig,
|
||||
)) as AppBskyAgeassuranceGetConfig.OutputSchema
|
||||
return await getPublicAppviewClient().call(app.bsky.ageassurance.getConfig)
|
||||
}
|
||||
export function getConfigFromCache():
|
||||
| AppBskyAgeassuranceGetConfig.OutputSchema
|
||||
| app.bsky.ageassurance.getConfig.$OutputBody
|
||||
| undefined {
|
||||
return qc.getQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
|
||||
return qc.getQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
|
||||
configQueryKey,
|
||||
)
|
||||
}
|
||||
@@ -130,7 +122,7 @@ export function prefetchConfig() {
|
||||
try {
|
||||
logger.debug(`prefetchAgeAssuranceConfig: resolving...`)
|
||||
const res = await networkRetry(3, () => getConfig())
|
||||
qc.setQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
|
||||
qc.setQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
|
||||
configQueryKey,
|
||||
res,
|
||||
)
|
||||
@@ -146,7 +138,7 @@ export function prefetchConfig() {
|
||||
export async function refetchConfig() {
|
||||
logger.debug(`refetchConfig: fetching...`)
|
||||
const res = await getConfig()
|
||||
qc.setQueryData<AppBskyAgeassuranceGetConfig.OutputSchema>(
|
||||
qc.setQueryData<app.bsky.ageassurance.getConfig.$OutputBody>(
|
||||
configQueryKey,
|
||||
res,
|
||||
)
|
||||
@@ -216,8 +208,8 @@ export function getServerStateFromCache({
|
||||
did,
|
||||
}: {
|
||||
did: string
|
||||
}): AppBskyAgeassuranceGetState.OutputSchema | undefined {
|
||||
return qc.getQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
|
||||
}): app.bsky.ageassurance.getState.$OutputBody | undefined {
|
||||
return qc.getQueryData<app.bsky.ageassurance.getState.$OutputBody>(
|
||||
createServerStateQueryKey({did}),
|
||||
)
|
||||
}
|
||||
@@ -243,7 +235,7 @@ export async function prefetchServerState({
|
||||
logger.debug(`prefetchServerState: resolving...`)
|
||||
const res = await networkRetry(3, () => getServerState({appviewClient}))
|
||||
if (res) {
|
||||
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(qk, res)
|
||||
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(qk, res)
|
||||
}
|
||||
} catch (err) {
|
||||
const e = err as Error
|
||||
@@ -262,7 +254,7 @@ export async function refetchServerState({
|
||||
logger.debug(`refetchServerState: fetching...`)
|
||||
const res = await networkRetry(3, () => getServerState({appviewClient}))
|
||||
if (res) {
|
||||
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
|
||||
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(
|
||||
createServerStateQueryKey({did}),
|
||||
res,
|
||||
)
|
||||
@@ -272,16 +264,16 @@ export async function refetchServerState({
|
||||
export function usePatchServerState() {
|
||||
const {currentAccount} = useSession()
|
||||
return useCallback(
|
||||
(next: AppBskyAgeassuranceDefs.State) => {
|
||||
(next: app.bsky.ageassurance.defs.State) => {
|
||||
if (!currentAccount) return
|
||||
const did = currentAccount.did
|
||||
const prev = getServerStateFromCache({did})
|
||||
const merged: AppBskyAgeassuranceGetState.OutputSchema = {
|
||||
const merged: app.bsky.ageassurance.getState.$OutputBody = {
|
||||
metadata: {},
|
||||
...(prev || {}),
|
||||
state: next,
|
||||
}
|
||||
qc.setQueryData<AppBskyAgeassuranceGetState.OutputSchema>(
|
||||
qc.setQueryData<app.bsky.ageassurance.getState.$OutputBody>(
|
||||
createServerStateQueryKey({did}),
|
||||
merged,
|
||||
)
|
||||
@@ -347,7 +339,7 @@ export function useServerStateQuery() {
|
||||
|
||||
export type OtherRequiredData = {
|
||||
birthdate: string | undefined
|
||||
actorDeclaration?: ChatBskyActorDeclaration.Main
|
||||
actorDeclaration?: chat.bsky.actor.declaration.Main
|
||||
}
|
||||
export function createOtherRequiredDataQueryKey({did}: {did: string}) {
|
||||
return ['otherRequiredData', did]
|
||||
@@ -422,7 +414,7 @@ export function setOtherRequiredDataActorDeclarationCache({
|
||||
actorDeclaration,
|
||||
}: {
|
||||
did: string
|
||||
actorDeclaration: ChatBskyActorDeclaration.Main
|
||||
actorDeclaration: chat.bsky.actor.declaration.Main
|
||||
}) {
|
||||
const prev = getOtherRequiredDataFromCache({did})
|
||||
const next: OtherRequiredData = {
|
||||
@@ -564,7 +556,7 @@ export function getDeviceSignalsFromCacheForRegion({
|
||||
region,
|
||||
}: {
|
||||
did: string
|
||||
region: AppBskyAgeassuranceDefs.ConfigRegion
|
||||
region: app.bsky.ageassurance.defs.ConfigRegion
|
||||
}): AgeRange.AgeRangeResponse | undefined {
|
||||
const regionKey = createRegionKey(region)
|
||||
return getDeviceSignalsMapFromCache({did})?.[regionKey]
|
||||
@@ -718,11 +710,11 @@ export type AgeAssuranceServerData = {
|
||||
/**
|
||||
* The raw config from the appview.
|
||||
*/
|
||||
config: AppBskyAgeassuranceDefs.Config | undefined
|
||||
config: app.bsky.ageassurance.defs.Config | undefined
|
||||
/**
|
||||
* The raw state from the appview. Must be further processed before being useful.
|
||||
*/
|
||||
state: AppBskyAgeassuranceDefs.State | undefined
|
||||
state: app.bsky.ageassurance.defs.State | undefined
|
||||
metadata: AgeAssuranceMetadata | undefined
|
||||
/**
|
||||
* The native on-device age signals for the region the user is currently in,
|
||||
|
||||
+81
-115
@@ -1,13 +1,10 @@
|
||||
import type * as AgeRange from 'expo-age-range'
|
||||
import {
|
||||
ageAssuranceRuleIDs as ids,
|
||||
type AppBskyAgeassuranceDefs,
|
||||
type AppBskyAgeassuranceGetState,
|
||||
} from '@atproto/api'
|
||||
import {toDatetimeString} from '@atproto/syntax'
|
||||
|
||||
import {type OtherRequiredData} from '#/ageAssurance/data'
|
||||
import {IS_DEV, IS_E2E} from '#/env'
|
||||
import {type Geolocation} from '#/geolocation'
|
||||
import {app} from '#/lexicons'
|
||||
|
||||
export const enabled = (IS_DEV && false) || IS_E2E
|
||||
|
||||
@@ -31,31 +28,31 @@ export const otherRequiredData: OtherRequiredData = {
|
||||
}
|
||||
|
||||
const serverStateEnabled = false || IS_E2E
|
||||
export const serverState: AppBskyAgeassuranceGetState.OutputSchema | undefined =
|
||||
serverStateEnabled
|
||||
? {
|
||||
state: {
|
||||
lastInitiatedAt: undefined, // new Date(2025, 1, 1).toISOString(),
|
||||
status: 'unknown',
|
||||
access: 'unknown',
|
||||
},
|
||||
metadata: {
|
||||
accountCreatedAt: new Date(2023, 1, 1).toISOString(),
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
export const serverState:
|
||||
| app.bsky.ageassurance.getState.$OutputBody
|
||||
| undefined = serverStateEnabled
|
||||
? {
|
||||
state: {
|
||||
lastInitiatedAt: undefined, // new Date(2025, 1, 1).toISOString(),
|
||||
status: 'unknown',
|
||||
access: 'unknown',
|
||||
},
|
||||
metadata: {
|
||||
accountCreatedAt: toDatetimeString(new Date(2023, 1, 1)),
|
||||
},
|
||||
}
|
||||
: undefined
|
||||
|
||||
export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
export const config: app.bsky.ageassurance.defs.Config = {
|
||||
regions: [
|
||||
{
|
||||
countryCode: 'AA',
|
||||
regionCode: undefined,
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
$type: ids.Default,
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'full',
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -68,65 +65,55 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
minAccessAge: 18,
|
||||
additionalVerificationMethods: ['device'],
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
countryCode: 'GB',
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 13,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
countryCode: 'AU',
|
||||
minAccessAge: 16,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAccountNewerThan.build({
|
||||
date: '2025-12-10T00:00:00Z',
|
||||
access: 'none',
|
||||
$type: ids.IfAccountNewerThan,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 16,
|
||||
access: 'safe',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 16,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -134,20 +121,17 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'SD',
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 13,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -155,20 +139,17 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'WY',
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 13,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -176,20 +157,17 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'OH',
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 13,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -197,15 +175,13 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'MS',
|
||||
minAccessAge: 18,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -213,20 +189,17 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'VA',
|
||||
minAccessAge: 16,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 16,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 16,
|
||||
access: 'full',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -234,45 +207,38 @@ export const config: AppBskyAgeassuranceDefs.Config = {
|
||||
regionCode: 'TN',
|
||||
minAccessAge: 18,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
countryCode: 'BR',
|
||||
minAccessAge: 13,
|
||||
rules: [
|
||||
{
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfAssuredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfAssuredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 18,
|
||||
access: 'full',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge.build({
|
||||
age: 13,
|
||||
access: 'safe',
|
||||
$type: ids.IfDeclaredOverAge,
|
||||
},
|
||||
{
|
||||
}),
|
||||
app.bsky.ageassurance.defs.configRegionRuleDefault.build({
|
||||
access: 'none',
|
||||
$type: ids.Default,
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import type * as AgeRange from 'expo-age-range'
|
||||
import {
|
||||
type AppBskyAgeassuranceDefs,
|
||||
computeAgeAssuranceRegionAccess,
|
||||
} from '@atproto/api'
|
||||
import {computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
|
||||
|
||||
import {getAge} from '#/lib/strings/time'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -30,6 +27,7 @@ import {
|
||||
getAgeAssuranceRegionConfigWithFallback,
|
||||
} from '#/ageAssurance/util'
|
||||
import {type Geolocation, useGeolocation} from '#/geolocation'
|
||||
import {type app} from '#/lexicons'
|
||||
import {device} from '#/storage'
|
||||
|
||||
/**
|
||||
@@ -47,8 +45,8 @@ function computeAgeAssuranceState({
|
||||
}: {
|
||||
hasSession: boolean
|
||||
geolocation: Geolocation
|
||||
config?: AppBskyAgeassuranceDefs.Config
|
||||
state?: AppBskyAgeassuranceDefs.State
|
||||
config?: app.bsky.ageassurance.defs.Config
|
||||
state?: app.bsky.ageassurance.defs.State
|
||||
metadata?: AgeAssuranceMetadata
|
||||
deviceSignals?: AgeRange.AgeRangeResponse
|
||||
}) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type * as AgeRange from 'expo-age-range'
|
||||
import {type computeAgeAssuranceRegionAccess} from '@atproto/api'
|
||||
import {type computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
|
||||
|
||||
import {logger} from '#/ageAssurance/logger'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useCallback} from 'react'
|
||||
import {computeAgeAssuranceRegionAccess} from '@atproto/api'
|
||||
import {computeAgeAssuranceRegionAccess} from '@bsky.app/sdk/utils'
|
||||
|
||||
import {useAgeAssuranceServerDataContext} from '#/ageAssurance/data'
|
||||
import {logger} from '#/ageAssurance/logger'
|
||||
|
||||
@@ -1,31 +1,47 @@
|
||||
import {getAgeAssuranceRegionConfig} from '@atproto/api'
|
||||
|
||||
import {getAgeAssuranceRegionConfigForGeolocation} from '#/ageAssurance/util'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
jest.mock('#/ageAssurance/data')
|
||||
jest.mock('@atproto/api', () => ({
|
||||
...jest.requireActual('@atproto/api'),
|
||||
getAgeAssuranceRegionConfig: jest.fn(),
|
||||
}))
|
||||
|
||||
/*
|
||||
* Platform-based region filtering itself is implemented and tested in
|
||||
* `@atproto/api` (see `getAgeAssuranceRegionConfig`). What we own - and test
|
||||
* here - is that region resolution passes the current platform through. The
|
||||
* jest preset is `jest-expo/ios`, so `AGE_ASSURANCE_PLATFORM` resolves to
|
||||
* `ios` in these tests.
|
||||
* Platform scoping is applied locally in `util.ts` (the SDK region matcher
|
||||
* takes no platform filter). The jest preset is `jest-expo/ios`, so
|
||||
* `AGE_ASSURANCE_PLATFORM` resolves to `ios` in these tests.
|
||||
*/
|
||||
describe('getAgeAssuranceRegionConfigForGeolocation', () => {
|
||||
it('passes the current platform to the SDK region matcher', () => {
|
||||
const config = {regions: []}
|
||||
getAgeAssuranceRegionConfigForGeolocation(config, {
|
||||
countryCode: 'US',
|
||||
regionCode: 'TX',
|
||||
})
|
||||
expect(getAgeAssuranceRegionConfig).toHaveBeenCalledWith(config, {
|
||||
countryCode: 'US',
|
||||
regionCode: 'TX',
|
||||
platform: 'ios',
|
||||
})
|
||||
const region = (
|
||||
countryCode: string,
|
||||
regionCode?: string,
|
||||
platforms?: app.bsky.ageassurance.defs.ConfigRegion['platforms'],
|
||||
): app.bsky.ageassurance.defs.ConfigRegion => ({
|
||||
countryCode,
|
||||
regionCode,
|
||||
platforms,
|
||||
minAccessAge: 13,
|
||||
rules: [],
|
||||
})
|
||||
|
||||
it('skips regions for other platforms and continues matching', () => {
|
||||
const web = region('US', undefined, ['web'])
|
||||
const ios = region('US', undefined, ['ios'])
|
||||
|
||||
expect(
|
||||
getAgeAssuranceRegionConfigForGeolocation(
|
||||
{regions: [web, ios]},
|
||||
{countryCode: 'US', regionCode: undefined},
|
||||
),
|
||||
).toBe(ios)
|
||||
})
|
||||
|
||||
it('matches a region-specific config before a later country config', () => {
|
||||
const texas = region('US', 'TX')
|
||||
const us = region('US')
|
||||
|
||||
expect(
|
||||
getAgeAssuranceRegionConfigForGeolocation(
|
||||
{regions: [texas, us]},
|
||||
{countryCode: 'US', regionCode: 'TX'},
|
||||
),
|
||||
).toBe(texas)
|
||||
})
|
||||
})
|
||||
|
||||
+42
-17
@@ -1,11 +1,10 @@
|
||||
import {useMemo} from 'react'
|
||||
import type * as AgeRange from 'expo-age-range'
|
||||
import {type ModerationPrefs} from '@bsky.app/sdk/moderation'
|
||||
import {
|
||||
AppBskyAgeassuranceDefs,
|
||||
computeAgeAssuranceRegionAccess,
|
||||
getAgeAssuranceRegionConfig,
|
||||
} from '@atproto/api'
|
||||
import {type ModerationPrefs} from '@bsky.app/sdk/moderation'
|
||||
} from '@bsky.app/sdk/utils'
|
||||
|
||||
import {getAge} from '#/lib/strings/time'
|
||||
import {regionName} from '#/locale/helpers'
|
||||
@@ -25,6 +24,8 @@ import {
|
||||
} from '#/ageAssurance/types'
|
||||
import {type Geolocation, useGeolocation} from '#/geolocation'
|
||||
import {USRegionNameToRegionCode} from '#/geolocation/util'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
/**
|
||||
* Resolves a geolocation to its matched age assurance region config, or
|
||||
@@ -41,13 +42,31 @@ import {USRegionNameToRegionCode} from '#/geolocation/util'
|
||||
* risk desyncing the write and read keys and silently losing grants.
|
||||
*/
|
||||
export function getAgeAssuranceRegionConfigForGeolocation(
|
||||
config: AppBskyAgeassuranceDefs.Config,
|
||||
config: app.bsky.ageassurance.defs.Config,
|
||||
geolocation: Geolocation,
|
||||
): AppBskyAgeassuranceDefs.ConfigRegion | undefined {
|
||||
return getAgeAssuranceRegionConfig(config, {
|
||||
): app.bsky.ageassurance.defs.ConfigRegion | undefined {
|
||||
/*
|
||||
* The SDK's region matcher takes no `platform` filter, so platform scoping
|
||||
* is applied here: regions restricted to other platforms are dropped before
|
||||
* matching. Once the SDK accepts a platform, this whole function body
|
||||
* collapses to:
|
||||
*
|
||||
* return getAgeAssuranceRegionConfig(config, {
|
||||
* countryCode: geolocation.countryCode ?? '',
|
||||
* regionCode: geolocation.regionCode,
|
||||
* platform: AGE_ASSURANCE_PLATFORM,
|
||||
* })
|
||||
*/
|
||||
const scoped: app.bsky.ageassurance.defs.Config = {
|
||||
...config,
|
||||
regions: config.regions.filter(
|
||||
region =>
|
||||
!region.platforms || region.platforms.includes(AGE_ASSURANCE_PLATFORM),
|
||||
),
|
||||
}
|
||||
return getAgeAssuranceRegionConfig(scoped, {
|
||||
countryCode: geolocation.countryCode ?? '',
|
||||
regionCode: geolocation.regionCode,
|
||||
platform: AGE_ASSURANCE_PLATFORM,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -59,9 +78,9 @@ export function getAgeAssuranceRegionConfigForGeolocation(
|
||||
* which can return undefined if the geolocation does not match any AA region.
|
||||
*/
|
||||
export function getAgeAssuranceRegionConfigWithFallback(
|
||||
config: AppBskyAgeassuranceDefs.Config,
|
||||
config: app.bsky.ageassurance.defs.Config,
|
||||
geolocation: Geolocation,
|
||||
): AppBskyAgeassuranceDefs.ConfigRegion {
|
||||
): app.bsky.ageassurance.defs.ConfigRegion {
|
||||
return (
|
||||
getAgeAssuranceRegionConfigForGeolocation(config, geolocation) ||
|
||||
FALLBACK_REGION_CONFIG
|
||||
@@ -74,9 +93,9 @@ export function getAgeAssuranceRegionConfigWithFallback(
|
||||
* historical KWS-only behavior).
|
||||
*/
|
||||
export function getRegionAdditionalVerificationMethods(
|
||||
region: AppBskyAgeassuranceDefs.ConfigRegion,
|
||||
region: app.bsky.ageassurance.defs.ConfigRegion,
|
||||
): NonNullable<
|
||||
AppBskyAgeassuranceDefs.ConfigRegion['additionalVerificationMethods']
|
||||
app.bsky.ageassurance.defs.ConfigRegion['additionalVerificationMethods']
|
||||
> {
|
||||
return region.additionalVerificationMethods ?? []
|
||||
}
|
||||
@@ -86,7 +105,7 @@ export function getRegionAdditionalVerificationMethods(
|
||||
* age APIs (Apple Declared Age Range / Google Play Age Signals).
|
||||
*/
|
||||
export function regionAllowsDeviceVerification(
|
||||
region: AppBskyAgeassuranceDefs.ConfigRegion,
|
||||
region: app.bsky.ageassurance.defs.ConfigRegion,
|
||||
): boolean {
|
||||
return getRegionAdditionalVerificationMethods(region).includes('device')
|
||||
}
|
||||
@@ -122,7 +141,7 @@ export function createRegionKey(region: {
|
||||
* usable data.
|
||||
*/
|
||||
export function getAgeAssuranceDataFromDeviceSignals(
|
||||
region: AppBskyAgeassuranceDefs.ConfigRegion,
|
||||
region: app.bsky.ageassurance.defs.ConfigRegion,
|
||||
deviceSignals: AgeRange.AgeRangeResponse | undefined,
|
||||
): {
|
||||
assuredAge?: number
|
||||
@@ -183,7 +202,7 @@ export function canBirthdateUpdateIncreaseAccess({
|
||||
metadata,
|
||||
deviceSignals,
|
||||
}: {
|
||||
region: AppBskyAgeassuranceDefs.ConfigRegion
|
||||
region: app.bsky.ageassurance.defs.ConfigRegion
|
||||
metadata?: AgeAssuranceMetadata
|
||||
deviceSignals?: AgeRange.AgeRangeResponse
|
||||
}): boolean {
|
||||
@@ -212,8 +231,14 @@ export function canBirthdateUpdateIncreaseAccess({
|
||||
const thresholds = new Set<number>([region.minAccessAge])
|
||||
for (const rule of region.rules) {
|
||||
if (
|
||||
AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredOverAge(rule) ||
|
||||
AppBskyAgeassuranceDefs.isConfigRegionRuleIfDeclaredUnderAge(rule)
|
||||
bsky.isType(
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredOverAge,
|
||||
rule,
|
||||
) ||
|
||||
bsky.isType(
|
||||
app.bsky.ageassurance.defs.configRegionRuleIfDeclaredUnderAge,
|
||||
rule,
|
||||
)
|
||||
) {
|
||||
thresholds.add(rule.age)
|
||||
}
|
||||
@@ -303,7 +328,7 @@ export function computeAgeAssuranceFlags({
|
||||
deviceSignals,
|
||||
}: {
|
||||
state: AgeAssuranceState
|
||||
regionConfig: AppBskyAgeassuranceDefs.ConfigRegion
|
||||
regionConfig: app.bsky.ageassurance.defs.ConfigRegion
|
||||
metadata?: AgeAssuranceMetadata
|
||||
deviceSignals?: AgeRange.AgeRangeResponse
|
||||
}): AgeAssuranceFlags {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {Fragment, 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'
|
||||
@@ -19,6 +18,7 @@ import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/
|
||||
import {ProfileBadges} from '#/components/ProfileBadges'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function AccountList({
|
||||
onSelectAccount,
|
||||
@@ -107,7 +107,7 @@ function AccountItem({
|
||||
isCurrentAccount,
|
||||
isPendingAccount,
|
||||
}: {
|
||||
profile?: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile?: app.bsky.actor.defs.ProfileViewDetailed
|
||||
account: SessionAccount
|
||||
onSelect: (account: SessionAccount) => void
|
||||
isCurrentAccount: boolean
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import {useCallback, useMemo} from 'react'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {keepPreviousData, useQuery} from '@tanstack/react-query'
|
||||
|
||||
import {isJustAMute, moduiContainsHideableOffense} from '#/lib/moderation'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences'
|
||||
|
||||
@@ -8,8 +8,8 @@ import Animated, {
|
||||
withDelay,
|
||||
withTiming,
|
||||
} from 'react-native-reanimated'
|
||||
import {moderateProfile} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useSession} from '#/state/session'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {View} from 'react-native'
|
||||
import {moderateProfile} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {logger} from '#/logger'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useProfilesQuery} from '#/state/queries/profile'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {type Insets, View} from 'react-native'
|
||||
import {type ComAtprotoLabelDefs} from '@atproto/api'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
@@ -8,11 +7,12 @@ import {Button} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {Bot_Filled as RobotIcon} from '#/components/icons/Bot'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type com} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function isBotAccount(profile: {
|
||||
did: string
|
||||
labels?: ComAtprotoLabelDefs.Label[]
|
||||
labels?: com.atproto.label.defs.Label[]
|
||||
}): boolean {
|
||||
return (
|
||||
profile.labels?.some(l => l.val === 'bot' && l.src === profile.did) ?? false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useCallback, useEffect, useMemo} from 'react'
|
||||
import {type GestureResponderEvent, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs, type AppBskyGraphDefs, AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {RichText as RichTextApi} from '@bsky.app/sdk/richtext'
|
||||
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
@@ -31,11 +31,12 @@ import {RichText, type RichTextProps} from '#/components/RichText'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useActiveLiveEventFeedUris} from '#/features/liveEvents/context'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from './icons/Trash'
|
||||
|
||||
type Props = {
|
||||
view: AppBskyFeedDefs.GeneratorView
|
||||
view: app.bsky.feed.defs.GeneratorView
|
||||
onPress?: () => void
|
||||
}
|
||||
|
||||
@@ -254,7 +255,7 @@ export function SaveButton({
|
||||
pin,
|
||||
...props
|
||||
}: {
|
||||
view: AppBskyFeedDefs.GeneratorView | AppBskyGraphDefs.ListView
|
||||
view: app.bsky.feed.defs.GeneratorView | app.bsky.graph.defs.ListView
|
||||
pin?: boolean
|
||||
text?: boolean
|
||||
} & Partial<ButtonProps>) {
|
||||
@@ -269,7 +270,7 @@ function SaveButtonInner({
|
||||
text = true,
|
||||
...buttonProps
|
||||
}: {
|
||||
view: AppBskyFeedDefs.GeneratorView | AppBskyGraphDefs.ListView
|
||||
view: app.bsky.feed.defs.GeneratorView | app.bsky.graph.defs.ListView
|
||||
pin?: boolean
|
||||
text?: boolean
|
||||
} & Partial<ButtonProps>) {
|
||||
@@ -379,7 +380,7 @@ function SaveButtonInner({
|
||||
export function createProfileFeedHref({
|
||||
feed,
|
||||
}: {
|
||||
feed: AppBskyFeedDefs.GeneratorView
|
||||
feed: app.bsky.feed.defs.GeneratorView
|
||||
}) {
|
||||
const urip = new AtUri(feed.uri)
|
||||
const handleOrDid = feed.creator.handle || feed.creator.did
|
||||
|
||||
@@ -7,7 +7,6 @@ import Animated, {
|
||||
LayoutAnimationConfig,
|
||||
LinearTransition,
|
||||
} from 'react-native-reanimated'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
@@ -40,6 +39,7 @@ import {ProgressGuideList} from '#/components/ProgressGuide/List'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type Metrics, useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {FollowDialogWithoutGuide} from './ProgressGuide/FollowDialog'
|
||||
|
||||
@@ -569,7 +569,7 @@ export function SuggestedFeeds() {
|
||||
const {gtMobile} = useBreakpoints()
|
||||
|
||||
const feeds = useMemo(() => {
|
||||
const items: AppBskyFeedDefs.GeneratorView[] = []
|
||||
const items: app.bsky.feed.defs.GeneratorView[] = []
|
||||
|
||||
if (!data) return items
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import {useRef} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Link, type LinkProps} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
const AVI_SIZE = 30
|
||||
@@ -24,7 +23,7 @@ const AVI_BORDER = 1
|
||||
* `count` includes blocked users and `followers` does not.
|
||||
*/
|
||||
export function shouldShowKnownFollowers(
|
||||
knownFollowers?: AppBskyActorDefs.KnownFollowers,
|
||||
knownFollowers?: app.bsky.actor.defs.KnownFollowers,
|
||||
) {
|
||||
return knownFollowers && knownFollowers.followers.length > 0
|
||||
}
|
||||
@@ -42,7 +41,9 @@ export function KnownFollowers({
|
||||
minimal?: boolean
|
||||
showIfEmpty?: boolean
|
||||
}) {
|
||||
const cache = useRef<Map<string, AppBskyActorDefs.KnownFollowers>>(new Map())
|
||||
const cache = useRef<Map<string, app.bsky.actor.defs.KnownFollowers>>(
|
||||
new Map(),
|
||||
)
|
||||
|
||||
/*
|
||||
* Results for `knownFollowers` are not sorted consistently, so when
|
||||
@@ -83,7 +84,7 @@ function KnownFollowersInner({
|
||||
}: {
|
||||
profile: bsky.profile.AnyProfileView
|
||||
moderationOpts: ModerationOpts
|
||||
cachedKnownFollowers: AppBskyActorDefs.KnownFollowers
|
||||
cachedKnownFollowers: app.bsky.actor.defs.KnownFollowers
|
||||
onLinkPress?: LinkProps['onPress']
|
||||
minimal?: boolean
|
||||
showIfEmpty?: boolean
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {type AppBskyFeedGetLikes as GetLikes} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -11,8 +10,15 @@ import {useResolveUriQuery} from '#/state/queries/resolve-uri'
|
||||
import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
|
||||
import {List} from '#/view/com/util/List'
|
||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
function renderItem({item, index}: {item: GetLikes.Like; index: number}) {
|
||||
function renderItem({
|
||||
item,
|
||||
index,
|
||||
}: {
|
||||
item: app.bsky.feed.getLikes.Like
|
||||
index: number
|
||||
}) {
|
||||
return (
|
||||
<ProfileCardWithFollowBtn
|
||||
key={item.actor.did}
|
||||
@@ -22,7 +28,7 @@ function renderItem({item, index}: {item: GetLikes.Like; index: number}) {
|
||||
)
|
||||
}
|
||||
|
||||
function keyExtractor(item: GetLikes.Like) {
|
||||
function keyExtractor(item: app.bsky.feed.getLikes.Like) {
|
||||
return item.actor.did
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {useEffect, useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyGraphDefs, AtUri} from '@atproto/api'
|
||||
import {type ModerationUI} from '@bsky.app/sdk/moderation'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {moderateUserList, type ModerationUI} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {moderateUserList} from '#/lib/moderation/subjects'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {precacheList} from '#/state/queries/feed'
|
||||
@@ -23,6 +22,7 @@ import {
|
||||
import {Link as InternalLink, type LinkProps} from '#/components/Link'
|
||||
import * as Hider from '#/components/moderation/Hider'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
/*
|
||||
@@ -44,7 +44,7 @@ const CURATELIST = 'app.bsky.graph.defs#curatelist'
|
||||
const MODLIST = 'app.bsky.graph.defs#modlist'
|
||||
|
||||
type Props = {
|
||||
view: AppBskyGraphDefs.ListView
|
||||
view: app.bsky.graph.defs.ListView
|
||||
showPinButton?: boolean
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ export function TitleAndByline({
|
||||
}: {
|
||||
title: string
|
||||
creator?: bsky.profile.AnyProfileView
|
||||
purpose?: AppBskyGraphDefs.ListView['purpose']
|
||||
purpose?: app.bsky.graph.defs.ListView['purpose']
|
||||
modUi?: ModerationUI
|
||||
}) {
|
||||
const t = useTheme()
|
||||
@@ -157,7 +157,7 @@ export function TitleAndByline({
|
||||
export function createProfileListHref({
|
||||
list,
|
||||
}: {
|
||||
list: AppBskyGraphDefs.ListView
|
||||
list: app.bsky.graph.defs.ListView
|
||||
}) {
|
||||
const urip = new AtUri(list.uri)
|
||||
const handleOrDid = list.creator.handle || list.creator.did
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {
|
||||
AppBskyEmbedGallery,
|
||||
type AppBskyEmbedImages,
|
||||
type AppBskyFeedDefs,
|
||||
} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {shareImageModal} from '#/lib/media/manip'
|
||||
@@ -17,6 +12,7 @@ import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||
import * as PeekMenu from '#/components/PeekMenu'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
/**
|
||||
@@ -27,7 +23,7 @@ export function Embed({
|
||||
style,
|
||||
peekable = false,
|
||||
}: {
|
||||
embed: AppBskyFeedDefs.PostView['embed']
|
||||
embed: app.bsky.feed.defs.PostView['embed']
|
||||
style?: StyleProp<ViewStyle>
|
||||
peekable?: boolean
|
||||
}) {
|
||||
@@ -59,9 +55,9 @@ export function Embed({
|
||||
const tiles: React.ReactNode[] = []
|
||||
for (const item of e.view.items) {
|
||||
if (tiles.length >= 4) break
|
||||
if (!AppBskyEmbedGallery.isViewImage(item)) continue
|
||||
if (!bsky.isType(app.bsky.embed.gallery.viewImage, item)) continue
|
||||
if (peekable) {
|
||||
const image: AppBskyEmbedImages.ViewImage = {
|
||||
const image: app.bsky.embed.images.ViewImage = {
|
||||
thumb: item.thumbnail,
|
||||
fullsize: item.fullsize,
|
||||
alt: item.alt,
|
||||
@@ -107,7 +103,17 @@ export function Embed({
|
||||
// ignore any unknowns
|
||||
e.media.view !== null
|
||||
) {
|
||||
return <Embed embed={e.media.view} style={style} />
|
||||
/*
|
||||
* Every media arm's view is a `$Typed<...>` of a def that `PostView.embed`
|
||||
* also admits, but TS will not narrow the parsed union back into the raw
|
||||
* embed union, so the arm is re-asserted here.
|
||||
*/
|
||||
return (
|
||||
<Embed
|
||||
embed={e.media.view as app.bsky.feed.defs.PostView['embed']}
|
||||
style={style}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -202,7 +208,7 @@ export function VideoItem({
|
||||
)
|
||||
}
|
||||
|
||||
function PeekableImageItem({image}: {image: AppBskyEmbedImages.ViewImage}) {
|
||||
function PeekableImageItem({image}: {image: app.bsky.embed.images.ViewImage}) {
|
||||
const {t: l} = useLingui()
|
||||
const saveImage = useSaveImageToMediaLibrary()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {moderateProfile} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -8,7 +8,6 @@ import {differenceInSeconds} from 'date-fns'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -20,12 +19,13 @@ import {Newskie} from '#/components/icons/Newskie'
|
||||
import * as StarterPackCard from '#/components/StarterPack/StarterPackCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function NewskieDialog({
|
||||
profile,
|
||||
disabled,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
disabled?: boolean
|
||||
}) {
|
||||
const t = useTheme()
|
||||
@@ -75,7 +75,7 @@ function DialogInner({
|
||||
createdAt,
|
||||
now,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
createdAt: string
|
||||
now: number
|
||||
}) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {BSKY_LABELER_DID} from '@atproto/api'
|
||||
import {api} from '@bsky.app/sdk'
|
||||
import {type ModerationCause} from '@bsky.app/sdk/moderation'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
@@ -67,7 +67,7 @@ export function Label({
|
||||
const desc = useModerationCauseDescription(cause)
|
||||
const isLabeler = Boolean(desc.sourceType && desc.sourceDid)
|
||||
const isBlueskyLabel =
|
||||
desc.sourceType === 'labeler' && desc.sourceDid === BSKY_LABELER_DID
|
||||
desc.sourceType === 'labeler' && desc.sourceDid === api.moderation.did
|
||||
const avi = size === 'lg' ? 16 : 12
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {type StyleProp, type ViewStyle} from 'react-native'
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
|
||||
import {atoms as a} from '#/alf'
|
||||
import * as ChatInvite from '#/components/dms/ChatInvite'
|
||||
import {ExternalEmbed} from '#/components/Post/Embed/ExternalEmbed'
|
||||
import {JoinRequestEmbedBody} from '#/components/Post/Embed/JoinRequestEmbed'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* Renders a chat invite link found in an `app.bsky.embed.external` embed (e.g.
|
||||
@@ -18,7 +18,7 @@ export function ChatInviteEmbed({
|
||||
style,
|
||||
}: {
|
||||
code: string
|
||||
link: AppBskyEmbedExternal.ViewExternal
|
||||
link: app.bsky.embed.external.ViewExternal
|
||||
onOpen?: () => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
@@ -34,7 +34,7 @@ function ChatInviteEmbedBody({
|
||||
onOpen,
|
||||
style,
|
||||
}: {
|
||||
link: AppBskyEmbedExternal.ViewExternal
|
||||
link: app.bsky.embed.external.ViewExternal
|
||||
onOpen?: () => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
Pressable,
|
||||
} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -17,12 +16,13 @@ import {EmbedConsentDialog} from '#/components/dialogs/EmbedConsent'
|
||||
import {Fill} from '#/components/Fill'
|
||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function ExternalGif({
|
||||
link,
|
||||
params,
|
||||
}: {
|
||||
link: AppBskyEmbedExternal.ViewExternal
|
||||
link: app.bsky.embed.external.ViewExternal
|
||||
params: EmbedPlayerParams
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
@@ -15,7 +15,6 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {WebView} from 'react-native-webview'
|
||||
import {scheduleOnRN} from 'react-native-worklets'
|
||||
import {Image} from 'expo-image'
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
@@ -34,6 +33,7 @@ import {Fill} from '#/components/Fill'
|
||||
import {KeepAwake} from '#/components/KeepAwake'
|
||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
interface ShouldStartLoadRequest {
|
||||
url: string
|
||||
@@ -122,7 +122,7 @@ export function ExternalPlayer({
|
||||
link,
|
||||
params,
|
||||
}: {
|
||||
link: AppBskyEmbedExternal.ViewExternal
|
||||
link: app.bsky.embed.external.ViewExternal
|
||||
params: EmbedPlayerParams
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useMemo} from 'react'
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -20,6 +19,7 @@ import {Earth_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
import {ExternalGif} from './ExternalGif'
|
||||
import {ExternalPlayer} from './ExternalPlayer'
|
||||
import {GifEmbed} from './Gif'
|
||||
@@ -30,7 +30,7 @@ export const ExternalEmbed = ({
|
||||
style,
|
||||
hideAlt,
|
||||
}: {
|
||||
link: AppBskyEmbedExternal.ViewExternal
|
||||
link: app.bsky.embed.external.ViewExternal
|
||||
onOpen?: () => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
hideAlt?: boolean
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useMemo} from 'react'
|
||||
import {moderateFeedGenerator} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {moderateFeedGenerator} from '#/lib/moderation/subjects'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as FeedCard from '#/components/FeedCard'
|
||||
|
||||
@@ -2,7 +2,6 @@ import {useRef} from 'react'
|
||||
import {InteractionManager, View} from 'react-native'
|
||||
import {type AnimatedRef} from 'react-native-reanimated'
|
||||
import {Image} from 'expo-image'
|
||||
import {AppBskyEmbedGallery, type AppBskyEmbedImages} from '@atproto/api'
|
||||
|
||||
import {atoms as a, tokens} from '#/alf'
|
||||
import {AutoSizedImage} from '#/components/images/AutoSizedImage'
|
||||
@@ -16,6 +15,8 @@ import {type Dimensions} from '#/components/Lightbox/types'
|
||||
import {ImageContextMenu} from '#/components/Post/Embed/ImageContextMenu'
|
||||
import {PostEmbedViewContext} from '#/components/Post/Embed/types'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {type EmbedType} from '#/types/bsky/post'
|
||||
import {type CommonProps} from './types'
|
||||
|
||||
@@ -29,14 +30,16 @@ export function ImageEmbed({
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
const {openLightbox} = useLightboxControls()
|
||||
const images: AppBskyEmbedImages.ViewImage[] =
|
||||
const images: app.bsky.embed.images.ViewImage[] =
|
||||
embed.type === 'gallery'
|
||||
? embed.view.items.filter(AppBskyEmbedGallery.isViewImage).map(item => ({
|
||||
thumb: item.thumbnail,
|
||||
fullsize: item.fullsize,
|
||||
alt: item.alt,
|
||||
aspectRatio: item.aspectRatio,
|
||||
}))
|
||||
? embed.view.items
|
||||
.filter(item => bsky.isType(app.bsky.embed.gallery.viewImage, item))
|
||||
.map(item => ({
|
||||
thumb: item.thumbnail,
|
||||
fullsize: item.fullsize,
|
||||
alt: item.alt,
|
||||
aspectRatio: item.aspectRatio,
|
||||
}))
|
||||
: embed.view.images
|
||||
const useExpandedLayout =
|
||||
embed.type === 'gallery'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {useMemo} from 'react'
|
||||
import {moderateUserList} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {moderateUserList} from '#/lib/moderation/subjects'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as ListCard from '#/components/ListCard'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Fragment, type ReactNode} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
|
||||
import {Context, useAlf, utils} from '#/alf'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* Overrides only the values needed for `secondary_inverted` buttons atm.
|
||||
@@ -12,7 +11,7 @@ export function StandardSiteThemeProvider({
|
||||
view,
|
||||
children,
|
||||
}: {
|
||||
view: AppBskyEmbedExternal.ViewExternal
|
||||
view: app.bsky.embed.external.ViewExternal
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
const alf = useAlf()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {plural} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
|
||||
import {Leaflet} from '#/components/icons/community/Leaflet'
|
||||
import {Offprint} from '#/components/icons/community/Offprint'
|
||||
import {Pckt} from '#/components/icons/community/Pckt'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export type StandardSitePublisher = {
|
||||
host: string
|
||||
@@ -25,7 +24,7 @@ function hostFromUri(uri: string | undefined): string | null {
|
||||
}
|
||||
|
||||
export function getStandardSitePublisherHost(
|
||||
view: AppBskyEmbedExternal.ViewExternal,
|
||||
view: app.bsky.embed.external.ViewExternal,
|
||||
): string | null {
|
||||
return hostFromUri(view.source?.uri)
|
||||
}
|
||||
@@ -40,7 +39,7 @@ function matchByHost(host: string | null): StandardSitePublisher | null {
|
||||
}
|
||||
|
||||
export function matchStandardSitePublisher(
|
||||
view: AppBskyEmbedExternal.ViewExternal,
|
||||
view: app.bsky.embed.external.ViewExternal,
|
||||
): StandardSitePublisher | null {
|
||||
return matchByHost(getStandardSitePublisherHost(view))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export type CommonProps = {
|
||||
view: AppBskyEmbedExternal.ViewExternal
|
||||
view: app.bsky.embed.external.ViewExternal
|
||||
}
|
||||
|
||||
export type PreviewProps = {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {type AppBskyEmbedExternal} from '@atproto/api'
|
||||
|
||||
import {type app} from '#/lexicons'
|
||||
import {isStandardSiteEmbed, isStandardSitePublicationEmbed} from './utils'
|
||||
|
||||
function makeView(
|
||||
partial: Record<string, unknown>,
|
||||
): AppBskyEmbedExternal.ViewExternal {
|
||||
): app.bsky.embed.external.ViewExternal {
|
||||
return {
|
||||
uri: 'https://example.com/post',
|
||||
title: 'title',
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import {
|
||||
type AppBskyEmbedExternal,
|
||||
AtUri,
|
||||
type ComAtprotoRepoStrongRef,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
|
||||
export function isStandardSiteDocumentUri(ref: ComAtprotoRepoStrongRef.Main) {
|
||||
import {type app, type com} from '#/lexicons'
|
||||
|
||||
export function isStandardSiteDocumentUri(
|
||||
ref: com.atproto.repo.strongRef.Main,
|
||||
) {
|
||||
return new AtUri(ref.uri).collection.startsWith('site.standard.document')
|
||||
}
|
||||
|
||||
export function isStandardSitePublicationUri(
|
||||
ref: ComAtprotoRepoStrongRef.Main,
|
||||
ref: com.atproto.repo.strongRef.Main,
|
||||
) {
|
||||
return new AtUri(ref.uri).collection.startsWith('site.standard.publication')
|
||||
}
|
||||
|
||||
export function isStandardSiteUri(ref: ComAtprotoRepoStrongRef.Main) {
|
||||
export function isStandardSiteUri(ref: com.atproto.repo.strongRef.Main) {
|
||||
return new AtUri(ref.uri).collection.startsWith('site.standard.')
|
||||
}
|
||||
|
||||
export function isStandardSiteEmbed(view: AppBskyEmbedExternal.ViewExternal) {
|
||||
export function isStandardSiteEmbed(
|
||||
view: app.bsky.embed.external.ViewExternal,
|
||||
) {
|
||||
return view.associatedRefs?.some(ref => isStandardSiteUri(ref))
|
||||
}
|
||||
|
||||
export function isStandardSitePublicationEmbed(
|
||||
view: AppBskyEmbedExternal.ViewExternal,
|
||||
view: app.bsky.embed.external.ViewExternal,
|
||||
) {
|
||||
return (
|
||||
view.associatedRefs?.some(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useImperativeHandle, useRef, useState} from 'react'
|
||||
import {Pressable, type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {BlueskyVideoView} from '@bsky.app/video'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
@@ -17,6 +16,7 @@ import {KeepAwake} from '#/components/KeepAwake'
|
||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||
import {useReportDialogMetadataContext} from '#/components/moderation/ReportDialog/ReportDialogMetadataContext'
|
||||
import {useVideoMuteState} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext'
|
||||
import {type app} from '#/lexicons'
|
||||
import {GifPresentationControls} from '../GifPresentationControls'
|
||||
import {TimeIndicator} from './TimeIndicator'
|
||||
|
||||
@@ -29,7 +29,7 @@ export function VideoEmbedInnerNative({
|
||||
onError,
|
||||
}: {
|
||||
ref: React.Ref<{togglePlayback: () => void}>
|
||||
embed: AppBskyEmbedVideo.View
|
||||
embed: app.bsky.embed.video.View
|
||||
setStatus: (status: 'playing' | 'paused') => void
|
||||
setIsLoading: (isLoading: boolean) => void
|
||||
setIsActive: (isActive: boolean) => void
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export type VideoEmbedInnerWebProps = {
|
||||
embed: AppBskyEmbedVideo.View
|
||||
embed: app.bsky.embed.video.View
|
||||
active: boolean
|
||||
setActive: () => void
|
||||
onScreen: boolean
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useCallback, useEffect, useRef, useState} from 'react'
|
||||
import {ActivityIndicator, View} from 'react-native'
|
||||
import {ImageBackground} from 'expo-image'
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -17,12 +16,13 @@ import {useThrottledValue} from '#/components/hooks/useThrottledValue'
|
||||
import {ConstrainedImage} from '#/components/images/AutoSizedImage'
|
||||
import {PlayButtonIcon} from '#/components/video/PlayButtonIcon'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {GifPresentationControls} from './GifPresentationControls'
|
||||
import {VideoEmbedInnerNative} from './VideoEmbedInner/VideoEmbedInnerNative'
|
||||
import * as VideoFallback from './VideoEmbedInner/VideoFallback'
|
||||
|
||||
interface Props {
|
||||
embed: AppBskyEmbedVideo.View
|
||||
embed: app.bsky.embed.video.View
|
||||
}
|
||||
|
||||
export function VideoEmbed({embed}: Props) {
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyEmbedVideo} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -25,6 +24,7 @@ import {
|
||||
} from '#/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoEmbedInnerWeb'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB_FIREFOX} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
import {useActiveVideoWeb} from './ActiveVideoWebContext'
|
||||
import * as VideoFallback from './VideoEmbedInner/VideoFallback'
|
||||
|
||||
@@ -37,7 +37,7 @@ const noop = () => {}
|
||||
*/
|
||||
const MIN_CARD_WIDTH = 280
|
||||
|
||||
export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) {
|
||||
export function VideoEmbed({embed}: {embed: app.bsky.embed.video.View}) {
|
||||
const t = useTheme()
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const {
|
||||
@@ -297,7 +297,7 @@ function VideoError({
|
||||
error,
|
||||
retry,
|
||||
}: {
|
||||
embed: AppBskyEmbedVideo.View
|
||||
embed: app.bsky.embed.video.View
|
||||
error: unknown
|
||||
retry: () => void
|
||||
}) {
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
import {useCallback, useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type $Typed,
|
||||
type AppBskyFeedDefs,
|
||||
AppBskyFeedPost,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {type $Typed} from '@atproto/lex'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {moderatePost} from '@bsky.app/sdk/moderation'
|
||||
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {moderatePost} from '#/lib/moderation/subjects'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
|
||||
import {getChatInviteCodeFromUrl} from '#/lib/strings/url-helpers'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {unstableCacheProfileView} from '#/state/queries/profile'
|
||||
@@ -30,6 +25,7 @@ import {isStandardSiteEmbed} from '#/components/Post/Embed/StandardSiteEmbed/uti
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Embed as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {
|
||||
type Embed as TEmbed,
|
||||
@@ -267,7 +263,7 @@ export function QuoteEmbed({
|
||||
linkDisabled?: boolean
|
||||
}) {
|
||||
const moderationOpts = useModerationOpts()
|
||||
const quote = useMemo<$Typed<AppBskyFeedDefs.PostView>>(
|
||||
const quote = useMemo<$Typed<app.bsky.feed.defs.PostView>>(
|
||||
() => ({
|
||||
...embed.view,
|
||||
$type: 'app.bsky.feed.defs#postView',
|
||||
@@ -287,16 +283,10 @@ export function QuoteEmbed({
|
||||
const itemTitle = `Post by ${quote.author.handle}`
|
||||
|
||||
const richText = useMemo(() => {
|
||||
if (
|
||||
!bsky.dangerousIsType<AppBskyFeedPost.Record>(
|
||||
quote.record,
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
)
|
||||
return undefined
|
||||
if (!bsky.isType(app.bsky.feed.post, quote.record)) return undefined
|
||||
const {text, facets} = quote.record
|
||||
return text.trim()
|
||||
? new RichTextAPI({text: text, facets: asSdkFacets(facets)})
|
||||
? new RichTextAPI({text: text, facets: facets})
|
||||
: undefined
|
||||
}, [quote.record])
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import {type StyleProp, type ViewStyle} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {type ModerationDecision} from '@bsky.app/sdk/moderation'
|
||||
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export enum PostEmbedViewContext {
|
||||
ThreadHighlighted = 'ThreadHighlighted',
|
||||
Feed = 'Feed',
|
||||
@@ -20,10 +21,10 @@ export type CommonProps = {
|
||||
* events (post:photoEmbed:*). When the embed has no owning post (e.g.
|
||||
* composer previews), leave this undefined and no events will be emitted.
|
||||
*/
|
||||
post?: AppBskyFeedDefs.PostView
|
||||
post?: app.bsky.feed.defs.PostView
|
||||
feedDescriptor?: string
|
||||
}
|
||||
|
||||
export type EmbedProps = CommonProps & {
|
||||
embed?: AppBskyFeedDefs.PostView['embed']
|
||||
embed?: app.bsky.feed.defs.PostView['embed']
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useCallback, useMemo} from 'react'
|
||||
import {Platform, type StyleProp, type TextStyle, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs, AppBskyFeedPost} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {HITSLOP_30} from '#/lib/constants'
|
||||
@@ -28,6 +27,7 @@ import * as Select from '#/components/Select'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const X_ICON_OFFSET = 16
|
||||
@@ -38,7 +38,7 @@ export function TranslatedPost({
|
||||
postTextStyle = a.text_md,
|
||||
}: {
|
||||
hideTranslateLink?: boolean
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
postTextStyle?: StyleProp<TextStyle>
|
||||
}) {
|
||||
const langPrefs = useLanguagePrefs()
|
||||
@@ -46,11 +46,8 @@ export function TranslatedPost({
|
||||
key: post.uri,
|
||||
})
|
||||
|
||||
const record = useMemo<AppBskyFeedPost.Record | undefined>(() => {
|
||||
return bsky.dangerousIsType<AppBskyFeedPost.Record>(
|
||||
post.record,
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
const record = useMemo<app.bsky.feed.post.Main | undefined>(() => {
|
||||
return bsky.isType(app.bsky.feed.post, post.record)
|
||||
? post.record
|
||||
: undefined
|
||||
}, [post])
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {memo} from 'react'
|
||||
import {type Insets} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -15,6 +14,7 @@ import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
|
||||
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
|
||||
import * as toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {PostControlButton, PostControlButtonIcon} from './PostControlButton'
|
||||
|
||||
export const BookmarkButton = memo(function BookmarkButton({
|
||||
@@ -23,7 +23,7 @@ export const BookmarkButton = memo(function BookmarkButton({
|
||||
logContext,
|
||||
hitSlop,
|
||||
}: {
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
big?: boolean
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
hitSlop?: Insets
|
||||
|
||||
@@ -6,12 +6,7 @@ import {
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedPost,
|
||||
type AppBskyFeedThreadgate,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {plural} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
@@ -97,6 +92,7 @@ import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_INTERNAL} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
let PostMenuItems = ({
|
||||
post,
|
||||
@@ -110,17 +106,17 @@ let PostMenuItems = ({
|
||||
forceGoogleTranslate,
|
||||
}: {
|
||||
testID: string
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
postFeedContext: string | undefined
|
||||
postReqId: string | undefined
|
||||
record: AppBskyFeedPost.Record
|
||||
record: app.bsky.feed.post.Main
|
||||
richText: RichTextAPI
|
||||
style?: StyleProp<ViewStyle>
|
||||
hitSlop?: PressableProps['hitSlop']
|
||||
size?: 'lg' | 'md' | 'sm'
|
||||
timestamp: string
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
onShowLess?: (interaction: app.bsky.feed.defs.Interaction) => void
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
forceGoogleTranslate: boolean
|
||||
}): React.ReactNode => {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import {memo, useMemo, useState} from 'react'
|
||||
import {type Insets} from 'react-native'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedPost,
|
||||
type AppBskyFeedThreadgate,
|
||||
} from '@atproto/api'
|
||||
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
@@ -13,6 +8,7 @@ import {EventStopper} from '#/view/com/util/EventStopper'
|
||||
import {DotGrid3x1_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useMenuControl} from '#/components/Menu'
|
||||
import {type app} from '#/lexicons'
|
||||
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
|
||||
import {PostMenuItems} from './PostMenuItems'
|
||||
|
||||
@@ -32,15 +28,15 @@ let PostMenuButton = ({
|
||||
forceGoogleTranslate,
|
||||
}: {
|
||||
testID: string
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
postFeedContext: string | undefined
|
||||
postReqId: string | undefined
|
||||
big?: boolean
|
||||
record: AppBskyFeedPost.Record
|
||||
record: app.bsky.feed.post.Main
|
||||
richText: RichTextAPI
|
||||
timestamp: string
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
onShowLess?: (interaction: app.bsky.feed.defs.Interaction) => void
|
||||
hitSlop?: Insets
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
forceGoogleTranslate: boolean
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {ScrollView, View} from 'react-native'
|
||||
import {type ChatBskyActorDefs} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -8,7 +7,6 @@ import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {isBlockedOrBlocking, isMuted} from '#/lib/moderation/blocked-and-muted'
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
@@ -23,6 +21,7 @@ import {type ConvoWithDetails, parseConvoView} from '#/components/dms/util'
|
||||
import {ProfileBadges} from '#/components/ProfileBadges'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type chat} from '#/lexicons'
|
||||
|
||||
export function RecentChats({
|
||||
postUri,
|
||||
@@ -114,7 +113,7 @@ function RecentChatItem({
|
||||
onPress: () => void
|
||||
moderationOpts: ModerationOpts
|
||||
convo: ConvoWithDetails
|
||||
primaryMember: ChatBskyActorDefs.ProfileViewBasic
|
||||
primaryMember: chat.bsky.actor.defs.ProfileViewBasic
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {memo, useMemo} from 'react'
|
||||
import * as ExpoClipboard from 'expo-clipboard'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
import {type PressableProps, type StyleProp, type ViewStyle} from 'react-native'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedPost,
|
||||
type AppBskyFeedThreadgate,
|
||||
} from '@atproto/api'
|
||||
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
|
||||
import {type Shadow} from '#/state/cache/post-shadow'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export interface ShareMenuItemsProps {
|
||||
testID: string
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
record: AppBskyFeedPost.Record
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
record: app.bsky.feed.post.Main
|
||||
richText: RichTextAPI
|
||||
style?: StyleProp<ViewStyle>
|
||||
hitSlop?: PressableProps['hitSlop']
|
||||
size?: 'lg' | 'md' | 'sm'
|
||||
timestamp: string
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
onShare: () => void
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {memo, useMemo} from 'react'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import {memo, useMemo, useState} from 'react'
|
||||
import {type Insets} from 'react-native'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedPost,
|
||||
type AppBskyFeedThreadgate,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -21,6 +16,7 @@ import {ArrowShareRight_Stroke2_Corner2_Rounded as ArrowShareRightIcon} from '#/
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {useMenuControl} from '#/components/Menu'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {PostControlButton, PostControlButtonIcon} from '../PostControlButton'
|
||||
import {ShareMenuItems} from './ShareMenuItems'
|
||||
|
||||
@@ -37,12 +33,12 @@ let ShareMenuButton = ({
|
||||
logContext,
|
||||
}: {
|
||||
testID: string
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
big?: boolean
|
||||
record: AppBskyFeedPost.Record
|
||||
record: app.bsky.feed.post.Main
|
||||
richText: RichTextAPI
|
||||
timestamp: string
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
onShare: () => void
|
||||
hitSlop?: Insets
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import {memo, useMemo, useState} from 'react'
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyFeedPost,
|
||||
type AppBskyFeedThreadgate,
|
||||
} from '@atproto/api'
|
||||
import {type RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {plural} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
@@ -29,6 +24,7 @@ import {useFormatPostStatCount} from '#/components/PostControls/util'
|
||||
import * as Skele from '#/components/Skeleton'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import {BookmarkButton} from './BookmarkButton'
|
||||
import {
|
||||
PostControlButton,
|
||||
@@ -57,8 +53,8 @@ let PostControls = ({
|
||||
forceGoogleTranslate = false,
|
||||
}: {
|
||||
big?: boolean
|
||||
post: Shadow<AppBskyFeedDefs.PostView>
|
||||
record: AppBskyFeedPost.Record
|
||||
post: Shadow<app.bsky.feed.defs.PostView>
|
||||
record: app.bsky.feed.post.Main
|
||||
richText: RichTextAPI
|
||||
feedContext?: string | undefined
|
||||
reqId?: string | undefined
|
||||
@@ -66,8 +62,8 @@ let PostControls = ({
|
||||
onPressReply: () => void
|
||||
onPostReply?: (postUri: string | undefined) => void
|
||||
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
|
||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
|
||||
threadgateRecord?: app.bsky.feed.threadgate.Main
|
||||
onShowLess?: (interaction: app.bsky.feed.defs.Interaction) => void
|
||||
viaRepost?: {uri: string; cid: string}
|
||||
variant?: 'compact' | 'normal' | 'large'
|
||||
forceGoogleTranslate?: boolean
|
||||
|
||||
@@ -6,12 +6,11 @@ import {
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {RichText as RichTextApi} from '@bsky.app/sdk/richtext'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {getModerationCauseKey} from '#/lib/moderation'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {forceLTR} from '#/lib/strings/bidi'
|
||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import {memo, useCallback, useEffect, useMemo, useReducer, useRef} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom'
|
||||
import {msg, plural} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {getModerationCauseKey} from '#/lib/moderation'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
@@ -40,6 +38,7 @@ import {Text} from '#/components/Typography'
|
||||
import {IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {LiveStatus} from '#/features/liveNow/components/LiveStatusDialog'
|
||||
import {type app} from '#/lexicons'
|
||||
import {type ProfileHoverCardProps} from './types'
|
||||
|
||||
const floatingMiddlewares = [
|
||||
@@ -416,7 +415,7 @@ function Inner({
|
||||
moderationOpts,
|
||||
hide,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
moderationOpts: ModerationOpts
|
||||
hide: () => void
|
||||
}) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {forwardRef, useCallback, useImperativeHandle, useState} from 'react'
|
||||
import {type ListRenderItemInfo, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
|
||||
import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset'
|
||||
import {List, type ListRef} from '#/view/com/util/List'
|
||||
@@ -8,13 +7,14 @@ import {type SectionRef} from '#/screens/Profile/Sections/types'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as FeedCard from '#/components/FeedCard'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
function keyExtractor(item: AppBskyFeedDefs.GeneratorView) {
|
||||
function keyExtractor(item: app.bsky.feed.defs.GeneratorView) {
|
||||
return item.uri
|
||||
}
|
||||
|
||||
interface ProfilesListProps {
|
||||
feeds: AppBskyFeedDefs.GeneratorView[]
|
||||
feeds: app.bsky.feed.defs.GeneratorView[]
|
||||
headerHeight: number
|
||||
scrollElRef: ListRef
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export const FeedsList = forwardRef<SectionRef, ProfilesListProps>(
|
||||
const renderItem = ({
|
||||
item,
|
||||
index,
|
||||
}: ListRenderItemInfo<AppBskyFeedDefs.GeneratorView>) => {
|
||||
}: ListRenderItemInfo<app.bsky.feed.defs.GeneratorView>) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import {forwardRef, useCallback, useImperativeHandle, useState} from 'react'
|
||||
import {type ListRenderItemInfo, View} from 'react-native'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
type AppBskyGraphGetList,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {
|
||||
type InfiniteData,
|
||||
@@ -22,15 +18,16 @@ import {atoms as a, useTheme} from '#/alf'
|
||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||
import {Default as ProfileCard} from '#/components/ProfileCard'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
function keyExtractor(item: AppBskyActorDefs.ProfileView, index: number) {
|
||||
function keyExtractor(item: app.bsky.actor.defs.ProfileView, index: number) {
|
||||
return `${item.did}-${index}`
|
||||
}
|
||||
|
||||
interface ProfilesListProps {
|
||||
listUri: string
|
||||
listMembersQuery: UseInfiniteQueryResult<
|
||||
InfiniteData<AppBskyGraphGetList.OutputSchema>
|
||||
InfiniteData<app.bsky.graph.getList.$OutputBody>
|
||||
>
|
||||
moderationOpts: ModerationOpts
|
||||
headerHeight: number
|
||||
@@ -87,7 +84,7 @@ export const ProfilesList = forwardRef<SectionRef, ProfilesListProps>(
|
||||
const renderItem = ({
|
||||
item,
|
||||
index,
|
||||
}: ListRenderItemInfo<AppBskyActorDefs.ProfileView>) => {
|
||||
}: ListRenderItemInfo<app.bsky.actor.defs.ProfileView>) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -37,6 +36,7 @@ import * as Prompt from '#/components/Prompt'
|
||||
import {Default as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
interface SectionRef {
|
||||
scrollToTop: () => void
|
||||
@@ -57,7 +57,7 @@ interface ProfileFeedgensProps {
|
||||
emptyStateIcon?: React.ComponentType<any> | React.ReactElement
|
||||
}
|
||||
|
||||
function keyExtractor(item: AppBskyGraphDefs.StarterPackViewBasic) {
|
||||
function keyExtractor(item: app.bsky.graph.defs.StarterPackViewBasic) {
|
||||
return item.uri
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ export function ProfileStarterPacks({
|
||||
({
|
||||
item,
|
||||
index,
|
||||
}: ListRenderItemInfo<AppBskyGraphDefs.StarterPackViewBasic>) => {
|
||||
}: ListRenderItemInfo<app.bsky.graph.defs.StarterPackViewBasic>) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
||||
@@ -3,7 +3,6 @@ import {View} from 'react-native'
|
||||
// @ts-expect-error missing types
|
||||
import QRCode from 'react-native-qrcode-styled'
|
||||
import type ViewShot from 'react-native-view-shot'
|
||||
import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
@@ -12,6 +11,7 @@ import {atoms as a, useTheme} from '#/alf'
|
||||
import {LinearGradientBackground} from '#/components/LinearGradientBackground'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const LazyViewShot = lazy(
|
||||
@@ -24,18 +24,13 @@ export function QrCode({
|
||||
link,
|
||||
ref,
|
||||
}: {
|
||||
starterPack: AppBskyGraphDefs.StarterPackView
|
||||
starterPack: app.bsky.graph.defs.StarterPackView
|
||||
link: string
|
||||
ref: React.Ref<ViewShot>
|
||||
}) {
|
||||
const {record} = starterPack
|
||||
|
||||
if (
|
||||
!bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
||||
record,
|
||||
AppBskyGraphStarterpack.isRecord,
|
||||
)
|
||||
) {
|
||||
if (!bsky.isType(app.bsky.graph.starterpack, record)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import {View} from 'react-native'
|
||||
import type ViewShot from 'react-native-view-shot'
|
||||
import {requestPermissionsAsync, saveToLibraryAsync} from 'expo-media-library'
|
||||
import * as Sharing from 'expo-sharing'
|
||||
import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -21,6 +20,7 @@ import {QrCode} from '#/components/StarterPack/QrCode'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export function QrCodeDialog({
|
||||
@@ -28,7 +28,7 @@ export function QrCodeDialog({
|
||||
link,
|
||||
control,
|
||||
}: {
|
||||
starterPack: AppBskyGraphDefs.StarterPackView
|
||||
starterPack: app.bsky.graph.defs.StarterPackView
|
||||
link?: string
|
||||
control: DialogControlProps
|
||||
}) {
|
||||
@@ -87,12 +87,7 @@ export function QrCodeDialog({
|
||||
} else {
|
||||
setIsSaveProcessing(true)
|
||||
|
||||
if (
|
||||
!bsky.validate(
|
||||
starterPack.record,
|
||||
AppBskyGraphStarterpack.validateRecord,
|
||||
)
|
||||
) {
|
||||
if (!bsky.matches(app.bsky.graph.starterpack, starterPack.record)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -19,9 +18,10 @@ import {Loader} from '#/components/Loader'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE, IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
interface Props {
|
||||
starterPack: AppBskyGraphDefs.StarterPackView
|
||||
starterPack: app.bsky.graph.defs.StarterPackView
|
||||
link?: string
|
||||
imageLoaded?: boolean
|
||||
qrDialogControl: DialogControlProps
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {AppBskyGraphStarterpack, AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
type LinkProps as BaseLinkProps,
|
||||
} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export function Default({
|
||||
@@ -62,12 +63,7 @@ export function Card({
|
||||
const t = useTheme()
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
if (
|
||||
!bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
||||
record,
|
||||
AppBskyGraphStarterpack.isRecord,
|
||||
)
|
||||
) {
|
||||
if (!bsky.isType(app.bsky.graph.starterpack, record)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -127,10 +123,7 @@ export function useStarterPackLink({
|
||||
|
||||
return {
|
||||
to: `/starter-pack/${handleOrDid}/${rkey}`,
|
||||
label: bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
||||
view.record,
|
||||
AppBskyGraphStarterpack.isRecord,
|
||||
)
|
||||
label: bsky.isType(app.bsky.graph.starterpack, view.record)
|
||||
? _(msg`Navigate to ${view.record.name}`)
|
||||
: _(msg`Navigate to starter pack`),
|
||||
precache,
|
||||
@@ -154,12 +147,7 @@ export function Link({
|
||||
return {rkey, handleOrDid: creator.handle || creator.did}
|
||||
}, [starterPack])
|
||||
|
||||
if (
|
||||
!bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
||||
record,
|
||||
AppBskyGraphStarterpack.isRecord,
|
||||
)
|
||||
) {
|
||||
if (!bsky.isType(app.bsky.graph.starterpack, record)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useRef} from 'react'
|
||||
import {type ListRenderItemInfo} from 'react-native'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs, type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -22,9 +21,10 @@ import {
|
||||
} from '#/components/StarterPack/Wizard/WizardListCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
function keyExtractor(
|
||||
item: AppBskyActorDefs.ProfileViewBasic | AppBskyFeedDefs.GeneratorView,
|
||||
item: app.bsky.actor.defs.ProfileViewBasic | app.bsky.feed.defs.GeneratorView,
|
||||
index: number,
|
||||
) {
|
||||
return `${item.did}-${index}`
|
||||
@@ -41,7 +41,7 @@ export function WizardEditListDialog({
|
||||
state: WizardState
|
||||
dispatch: (action: WizardAction) => void
|
||||
moderationOpts: ModerationOpts
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import {Keyboard, View} from 'react-native'
|
||||
import {type AppBskyActorDefs, type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {type ModerationOpts, type ModerationUI} from '@bsky.app/sdk/moderation'
|
||||
import {
|
||||
moderateFeedGenerator,
|
||||
moderateProfile,
|
||||
type ModerationOpts,
|
||||
type ModerationUI,
|
||||
} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
|
||||
import {moderateFeedGenerator, moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {useSession} from '#/state/session'
|
||||
@@ -21,6 +24,7 @@ import * as Toggle from '#/components/forms/Toggle'
|
||||
import {Checkbox} from '#/components/forms/Toggle'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
function WizardListCard({
|
||||
@@ -36,8 +40,8 @@ function WizardListCard({
|
||||
}: {
|
||||
type: 'user' | 'algo'
|
||||
btnType: 'checkbox' | 'remove'
|
||||
profile?: AppBskyActorDefs.ProfileViewBasic
|
||||
feed?: AppBskyFeedDefs.GeneratorView
|
||||
profile?: app.bsky.actor.defs.ProfileViewBasic
|
||||
feed?: app.bsky.feed.defs.GeneratorView
|
||||
displayName: string
|
||||
subtitle: string
|
||||
onPress: () => void
|
||||
@@ -178,7 +182,7 @@ export function WizardFeedCard({
|
||||
moderationOpts,
|
||||
}: {
|
||||
btnType: 'checkbox' | 'remove'
|
||||
generator: AppBskyFeedDefs.GeneratorView
|
||||
generator: app.bsky.feed.defs.GeneratorView
|
||||
state: WizardState
|
||||
dispatch: (action: WizardAction) => void
|
||||
moderationOpts: ModerationOpts
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useEffect, useMemo} from 'react'
|
||||
import {type AppBskyUnspeccedDefs, type AtUri} from '@atproto/api'
|
||||
import {type AtUri} from '@atproto/syntax'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
@@ -9,6 +9,7 @@ import {useCallOnce} from '#/lib/once'
|
||||
import {native} from '#/alf'
|
||||
import {Link as InternalLink, type LinkProps} from '#/components/Link'
|
||||
import {type Metrics, useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function TrendingTopicLink({
|
||||
topic: raw,
|
||||
@@ -18,7 +19,7 @@ export function TrendingTopicLink({
|
||||
children,
|
||||
...rest
|
||||
}: {
|
||||
topic: AppBskyUnspeccedDefs.TrendView
|
||||
topic: app.bsky.unspecced.defs.TrendView
|
||||
metricContext: Metrics['trendingTopic:seen']['context']
|
||||
rank: number
|
||||
recId?: string
|
||||
@@ -75,7 +76,7 @@ type ParsedTrendingTopic =
|
||||
}
|
||||
|
||||
export function useTopic(
|
||||
raw: AppBskyUnspeccedDefs.TrendView,
|
||||
raw: app.bsky.unspecced.defs.TrendView,
|
||||
): ParsedTrendingTopic {
|
||||
const {t: l} = useLingui()
|
||||
return useMemo(() => {
|
||||
|
||||
@@ -2,12 +2,6 @@ import {useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {LinearGradient} from 'expo-linear-gradient'
|
||||
import {
|
||||
type AppBskyActorDefs,
|
||||
AppBskyEmbedVideo,
|
||||
type AppBskyFeedDefs,
|
||||
AppBskyFeedPost,
|
||||
} from '@atproto/api'
|
||||
import {type ModerationDecision} from '@bsky.app/sdk/moderation'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
@@ -26,6 +20,7 @@ import {Link} from '#/components/Link'
|
||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||
import * as Hider from '#/components/moderation/Hider'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
function getBlackColor(t: ReturnType<typeof useTheme>) {
|
||||
@@ -42,7 +37,7 @@ export function VideoPostCard({
|
||||
moderation,
|
||||
onInteract,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
sourceContext: VideoFeedSourceContext
|
||||
moderation: ModerationDecision
|
||||
/**
|
||||
@@ -75,13 +70,10 @@ export function VideoPostCard({
|
||||
* Filtering should be done at a higher level, such as `PostFeed` or
|
||||
* `PostFeedVideoGridRow`, but we need to protect here as well.
|
||||
*/
|
||||
if (!AppBskyEmbedVideo.isView(embed)) return null
|
||||
if (!bsky.isType(app.bsky.embed.video.view, embed)) return null
|
||||
|
||||
const author = post.author
|
||||
const text = bsky.dangerousIsType<AppBskyFeedPost.Record>(
|
||||
post.record,
|
||||
AppBskyFeedPost.isRecord,
|
||||
)
|
||||
const text = bsky.isType(app.bsky.feed.post, post.record)
|
||||
? post.record?.text
|
||||
: ''
|
||||
const likeCount = post?.likeCount ?? 0
|
||||
@@ -275,7 +267,7 @@ export function VideoPostCardPlaceholder() {
|
||||
export function VideoPostCardTextPlaceholder({
|
||||
author,
|
||||
}: {
|
||||
author?: AppBskyActorDefs.ProfileViewBasic
|
||||
author?: app.bsky.actor.defs.ProfileViewBasic
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
@@ -355,7 +347,7 @@ export function CompactVideoPostCard({
|
||||
moderation,
|
||||
onInteract,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
sourceContext: VideoFeedSourceContext
|
||||
moderation: ModerationDecision
|
||||
/**
|
||||
@@ -386,7 +378,7 @@ export function CompactVideoPostCard({
|
||||
* Filtering should be done at a higher level, such as `PostFeed` or
|
||||
* `PostFeedVideoGridRow`, but we need to protect here as well.
|
||||
*/
|
||||
if (!AppBskyEmbedVideo.isView(embed)) return null
|
||||
if (!bsky.isType(app.bsky.embed.video.view, embed)) return null
|
||||
|
||||
const likeCount = post?.likeCount ?? 0
|
||||
const showLikeCount = false
|
||||
|
||||
@@ -6,12 +6,7 @@ import {
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {
|
||||
type AppBskyFeedDefs,
|
||||
AppBskyFeedPost,
|
||||
type AppBskyGraphDefs,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -38,10 +33,11 @@ import {InlineLinkText} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
interface WhoCanReplyProps {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
isThreadAuthor: boolean
|
||||
style?: StyleProp<ViewStyle>
|
||||
}
|
||||
@@ -58,10 +54,7 @@ export function WhoCanReply({post, isThreadAuthor, style}: WhoCanReplyProps) {
|
||||
* unexpectedly, we should check to make sure it's for sure the root URI.
|
||||
*/
|
||||
const rootUri =
|
||||
bsky.dangerousIsType<AppBskyFeedPost.Record>(
|
||||
post.record,
|
||||
AppBskyFeedPost.isRecord,
|
||||
) && post.record.reply?.root
|
||||
bsky.isType(app.bsky.feed.post, post.record) && post.record.reply?.root
|
||||
? post.record.reply.root.uri
|
||||
: post.uri
|
||||
const settings = useMemo(() => {
|
||||
@@ -209,7 +202,7 @@ function WhoCanReplyDialog({
|
||||
embeddingDisabled,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
settings: ThreadgateAllowUISetting[]
|
||||
embeddingDisabled: boolean
|
||||
}) {
|
||||
@@ -255,7 +248,7 @@ function Rules({
|
||||
settings,
|
||||
embeddingDisabled,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
post: app.bsky.feed.defs.PostView
|
||||
settings: ThreadgateAllowUISetting[]
|
||||
embeddingDisabled: boolean
|
||||
}) {
|
||||
@@ -313,8 +306,8 @@ function Rule({
|
||||
lists,
|
||||
}: {
|
||||
rule: ThreadgateAllowUISetting
|
||||
post: AppBskyFeedDefs.PostView
|
||||
lists: AppBskyGraphDefs.ListViewBasic[] | undefined
|
||||
post: app.bsky.feed.defs.PostView
|
||||
lists: app.bsky.graph.defs.ListViewBasic[] | undefined
|
||||
}) {
|
||||
if (rule.type === 'mention') {
|
||||
return <Trans>mentioned users</Trans>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyNotificationDefs, type Un$Typed} from '@atproto/api'
|
||||
import {type DidString} from '@atproto/syntax'
|
||||
import {type Un$Typed} from '@atproto/lex'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -118,11 +117,10 @@ function DialogInner({
|
||||
error,
|
||||
} = useMutation({
|
||||
mutationFn: async (
|
||||
activitySubscription: Un$Typed<AppBskyNotificationDefs.ActivitySubscription>,
|
||||
activitySubscription: Un$Typed<app.bsky.notification.defs.ActivitySubscription>,
|
||||
) => {
|
||||
await client.call(app.bsky.notification.putActivitySubscription, {
|
||||
// the profile view carries an already-resolved did
|
||||
subject: profile.did as DidString,
|
||||
subject: profile.did,
|
||||
activitySubscription,
|
||||
})
|
||||
},
|
||||
@@ -307,8 +305,8 @@ function DialogInner({
|
||||
}
|
||||
|
||||
function parseActivitySubscription(
|
||||
sub?: AppBskyNotificationDefs.ActivitySubscription,
|
||||
): Un$Typed<AppBskyNotificationDefs.ActivitySubscription> {
|
||||
sub?: app.bsky.notification.defs.ActivitySubscription,
|
||||
): Un$Typed<app.bsky.notification.defs.ActivitySubscription> {
|
||||
if (!sub) return {post: false, reply: false}
|
||||
const {post, reply} = sub
|
||||
return {post, reply}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {ToolsOzoneReportDefs} from '@atproto/api'
|
||||
import {type DidString} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -18,7 +17,7 @@ import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {logger} from '#/ageAssurance'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {com} from '#/lexicons'
|
||||
import {com, tools} from '#/lexicons'
|
||||
|
||||
export function AgeAssuranceAppealDialog({
|
||||
control,
|
||||
@@ -60,7 +59,7 @@ function Inner({control}: {control: Dialog.DialogControlProps}) {
|
||||
await client.call(
|
||||
com.atproto.moderation.createReport,
|
||||
{
|
||||
reasonType: ToolsOzoneReportDefs.REASONAPPEAL,
|
||||
reasonType: tools.ozone.report.defs.reasonAppeal.value,
|
||||
subject: {
|
||||
$type: 'com.atproto.admin.defs#repoRef',
|
||||
// the persisted account did is already resolved
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {type AppBskyContactDefs} from '@atproto/api'
|
||||
|
||||
import {type CountryCode} from '#/lib/international-telephone-codes'
|
||||
import {type app} from '#/lexicons'
|
||||
import {normalizePhoneNumber} from './phone-number'
|
||||
import {type Contact, type Match} from './state'
|
||||
|
||||
@@ -70,7 +69,7 @@ export function normalizeContactBook(
|
||||
|
||||
export function filterMatchedNumbers(
|
||||
contacts: Contact[],
|
||||
results: AppBskyContactDefs.MatchAndContactIndex[],
|
||||
results: app.bsky.contact.defs.MatchAndContactIndex[],
|
||||
mapping: Map<number, Contact['id']>,
|
||||
) {
|
||||
const filteredIds = new Set<Contact['id']>()
|
||||
@@ -87,7 +86,7 @@ export function filterMatchedNumbers(
|
||||
|
||||
export function getMatchedContacts(
|
||||
contacts: Contact[],
|
||||
results: AppBskyContactDefs.MatchAndContactIndex[],
|
||||
results: app.bsky.contact.defs.MatchAndContactIndex[],
|
||||
mapping: Map<number, Contact['id']>,
|
||||
): Array<Match> {
|
||||
const contactsById = new Map(contacts.map(c => [c.id, c]))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {memo, useEffect, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyActorDefs, type AppBskyFeedPost, AtUri} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
@@ -20,15 +20,16 @@ import {
|
||||
} from '#/components/icons/Chevron'
|
||||
import {CodeBrackets_Stroke2_Corner0_Rounded as CodeBracketsIcon} from '#/components/icons/CodeBrackets'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export type ColorModeValues = 'system' | 'light' | 'dark'
|
||||
|
||||
type EmbedDialogProps = {
|
||||
control: Dialog.DialogControlProps
|
||||
postAuthor: AppBskyActorDefs.ProfileViewBasic
|
||||
postAuthor: app.bsky.actor.defs.ProfileViewBasic
|
||||
postCid: string
|
||||
postUri: string
|
||||
record: AppBskyFeedPost.Record
|
||||
record: app.bsky.feed.post.Main
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {LayoutAnimation, Text as NestedText, View} from 'react-native'
|
||||
import {type AppBskyFeedDefs} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/syntax'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -133,10 +132,10 @@ export type PostInteractionSettingsDialogProps = {
|
||||
*/
|
||||
rootPostUri: string
|
||||
/**
|
||||
* Optional initial {@link AppBskyFeedDefs.ThreadgateView} to use if we
|
||||
* Optional initial {@link app.bsky.feed.defs.ThreadgateView} to use if we
|
||||
* happen to have one before opening the settings dialog.
|
||||
*/
|
||||
initialThreadgateView?: AppBskyFeedDefs.ThreadgateView
|
||||
initialThreadgateView?: app.bsky.feed.defs.ThreadgateView
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,11 +7,10 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import {TextInput, View} from 'react-native'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import {useCallback} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type AppBskyGraphGetStarterPacksWithMembership,
|
||||
AppBskyGraphStarterpack,
|
||||
} from '@atproto/api'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
@@ -33,10 +29,11 @@ import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {app} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
type StarterPackWithMembership =
|
||||
AppBskyGraphGetStarterPacksWithMembership.StarterPackWithMembership
|
||||
app.bsky.graph.getStarterPacksWithMembership.StarterPackWithMembership
|
||||
|
||||
export type StarterPackDialogProps = {
|
||||
control: Dialog.DialogControlProps
|
||||
@@ -324,12 +321,7 @@ function StarterPackItem({
|
||||
|
||||
const {record} = starterPack
|
||||
|
||||
if (
|
||||
!bsky.dangerousIsType<AppBskyGraphStarterpack.Record>(
|
||||
record,
|
||||
AppBskyGraphStarterpack.isRecord,
|
||||
)
|
||||
) {
|
||||
if (!bsky.isType(app.bsky.graph.starterpack, record)) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyGraphDefs, type AppBskyGraphStarterpack} from '@atproto/api'
|
||||
import {TID} from '@atproto/common-web'
|
||||
import {type $Typed} from '@atproto/lex'
|
||||
import {
|
||||
@@ -37,7 +36,7 @@ export function CreateListFromStarterPackDialog({
|
||||
starterPack,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
starterPack: AppBskyGraphDefs.StarterPackView
|
||||
starterPack: app.bsky.graph.defs.StarterPackView
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
@@ -50,7 +49,7 @@ export function CreateListFromStarterPackDialog({
|
||||
const createDialogControl = Dialog.useDialogControl()
|
||||
const loadingDialogControl = Dialog.useDialogControl()
|
||||
|
||||
const record = starterPack.record as AppBskyGraphStarterpack.Record
|
||||
const record = starterPack.record as app.bsky.graph.starterpack.Main
|
||||
|
||||
const onPressCreate = () => {
|
||||
control.close(() => createDialogControl.open())
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useCallback, useEffect, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -8,7 +7,7 @@ import {Plural, Trans} from '@lingui/react/macro'
|
||||
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {isOverMaxGraphemeCount} from '#/lib/strings/helpers'
|
||||
import {asSdkFacets, richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {shortenLinks, stripInvalidMentions} from '#/lib/strings/rich-text-manip'
|
||||
import {logger} from '#/logger'
|
||||
import {type ImageMeta} from '#/state/gallery'
|
||||
@@ -28,6 +27,7 @@ import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
const DISPLAY_NAME_MAX_GRAPHEMES = 64
|
||||
const DESCRIPTION_MAX_GRAPHEMES = 300
|
||||
@@ -46,8 +46,8 @@ export function CreateOrEditListDialog({
|
||||
initialValues,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
list?: AppBskyGraphDefs.ListView
|
||||
purpose?: AppBskyGraphDefs.ListPurpose
|
||||
list?: app.bsky.graph.defs.ListView
|
||||
purpose?: app.bsky.graph.defs.ListPurpose
|
||||
onSave?: (uri: string) => void
|
||||
initialValues?: InitialListValues
|
||||
}) {
|
||||
@@ -114,8 +114,8 @@ function DialogInner({
|
||||
onPressCancel,
|
||||
initialValues,
|
||||
}: {
|
||||
list?: AppBskyGraphDefs.ListView
|
||||
purpose?: AppBskyGraphDefs.ListPurpose
|
||||
list?: app.bsky.graph.defs.ListView
|
||||
purpose?: app.bsky.graph.defs.ListPurpose
|
||||
onSave?: (uri: string) => void
|
||||
setDirty: (dirty: boolean) => void
|
||||
onPressCancel: () => void
|
||||
@@ -169,7 +169,7 @@ function DialogInner({
|
||||
// We want to be working with a blank state here, so let's get the
|
||||
// serialized version and turn it back into a RichText
|
||||
const serialized = richTextToString(
|
||||
new RichTextAPI({text, facets: asSdkFacets(facets)}),
|
||||
new RichTextAPI({text, facets: facets}),
|
||||
false,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {useCallback, useMemo} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {type AppBskyGraphDefs} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {msg} from '@lingui/core/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
@@ -23,6 +22,7 @@ import {
|
||||
import {Loader} from '#/components/Loader'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {type app} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function ListAddRemoveUsersDialog({
|
||||
@@ -31,7 +31,7 @@ export function ListAddRemoveUsersDialog({
|
||||
onChange,
|
||||
}: {
|
||||
control: Dialog.DialogControlProps
|
||||
list: AppBskyGraphDefs.ListView
|
||||
list: app.bsky.graph.defs.ListView
|
||||
onChange?: (
|
||||
type: 'add' | 'remove',
|
||||
profile: bsky.profile.AnyProfileView,
|
||||
@@ -52,7 +52,7 @@ function DialogInner({
|
||||
list,
|
||||
onChange,
|
||||
}: {
|
||||
list: AppBskyGraphDefs.ListView
|
||||
list: app.bsky.graph.defs.ListView
|
||||
onChange?: (
|
||||
type: 'add' | 'remove',
|
||||
profile: bsky.profile.AnyProfileView,
|
||||
@@ -89,7 +89,7 @@ function DialogInner({
|
||||
* Returns undefined for pending, false for not a member, and string for a member (the URI of the membership record)
|
||||
*/
|
||||
function getMembership(
|
||||
listMembers: AppBskyGraphDefs.ListItemView[] | undefined,
|
||||
listMembers: app.bsky.graph.defs.ListItemView[] | undefined,
|
||||
actorDid: string,
|
||||
): string | false | undefined {
|
||||
if (!listMembers) {
|
||||
@@ -107,8 +107,8 @@ function UserResult({
|
||||
moderationOpts,
|
||||
}: {
|
||||
profile: bsky.profile.AnyProfileView
|
||||
list: AppBskyGraphDefs.ListView
|
||||
listMembers: AppBskyGraphDefs.ListItemView[] | undefined
|
||||
list: app.bsky.graph.defs.ListView
|
||||
listMembers: app.bsky.graph.defs.ListItemView[] | undefined
|
||||
onChange?: (
|
||||
type: 'add' | 'remove',
|
||||
profile: bsky.profile.AnyProfileView,
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
|
||||
import {logger} from '#/logger'
|
||||
import {STALE} from '#/state/queries'
|
||||
@@ -30,6 +29,7 @@ import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
|
||||
import {type EnabledCheckProps} from '#/components/dialogs/nuxs/utils'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {useGeolocation} from '#/geolocation'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
type Context = {
|
||||
activeNux: Nux | undefined
|
||||
@@ -93,7 +93,7 @@ function Inner({
|
||||
preferences,
|
||||
}: {
|
||||
currentAccount: SessionAccount
|
||||
currentProfile: AppBskyActorDefs.ProfileViewDetailed
|
||||
currentProfile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
preferences: UsePreferencesQueryResponse
|
||||
}) {
|
||||
const ax = useAnalytics()
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
|
||||
import {type UsePreferencesQueryResponse} from '#/state/queries/preferences'
|
||||
import {type SessionAccount} from '#/state/session'
|
||||
import {type AnalyticsContextType} from '#/analytics'
|
||||
import {type Geolocation} from '#/geolocation'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export type EnabledCheckProps = {
|
||||
features: AnalyticsContextType['features']
|
||||
currentAccount: SessionAccount
|
||||
currentProfile: AppBskyActorDefs.ProfileViewDetailed
|
||||
currentProfile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
preferences: UsePreferencesQueryResponse
|
||||
geolocation: Geolocation
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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 {MessageContextMenu} from '#/components/dms/MessageContextMenu'
|
||||
import {useMessageReplies} from '#/components/dms/MessageReplies'
|
||||
import {SwipeToReply} from '#/components/dms/SwipeToReply'
|
||||
import {type chat} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function ActionsWrapper({
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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'
|
||||
@@ -14,6 +13,7 @@ import {MessageContextMenu} from '#/components/dms/MessageContextMenu'
|
||||
import {DotGrid3x1_Stroke2_Corner0_Rounded as DotsHorizontalIcon} from '#/components/icons/DotGrid'
|
||||
import {EmojiSmile_Stroke2_Corner0_Rounded as EmojiSmileIcon} from '#/components/icons/Emoji'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {type chat} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||
import {
|
||||
@@ -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,6 +1,5 @@
|
||||
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'
|
||||
|
||||
@@ -19,6 +18,7 @@ import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
type ReportDialogParams = {
|
||||
convoId: string
|
||||
@@ -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>()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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'
|
||||
|
||||
@@ -19,6 +18,7 @@ import {Loader} from '#/components/Loader'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
type ReportDialogParams = {
|
||||
convoId: string
|
||||
@@ -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>()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {View} from 'react-native'
|
||||
import {ChatBskyGroupDefs} from '@atproto/api'
|
||||
import {Plural, Trans} from '@lingui/react/macro'
|
||||
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
@@ -10,6 +9,8 @@ import {AvatarBubbles} from '#/components/AvatarBubbles'
|
||||
import {InlineLinkText} from '#/components/Link'
|
||||
import {ProfileBadges} from '#/components/ProfileBadges'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {chat} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {useChatInvite} from './Context'
|
||||
|
||||
/**
|
||||
@@ -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, '@')
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {setStringAsync} from 'expo-clipboard'
|
||||
import {ChatBskyGroupDefs} from '@atproto/api'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
@@ -18,6 +17,8 @@ import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||
import {RaisingHand4Finger_Stroke2_Corner2_Rounded as HandIcon} from '#/components/icons/RaisingHand'
|
||||
import {useIntentDialogs} from '#/components/intents/IntentDialogs'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {chat} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {
|
||||
type ChatInviteAction,
|
||||
ChatInviteProvider,
|
||||
@@ -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
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {useCallback, useEffect} from 'react'
|
||||
import {type ScrollView, View} from 'react-native'
|
||||
import Animated, {useAnimatedRef, useSharedValue} from 'react-native-reanimated'
|
||||
import {moderateProfile} from '@bsky.app/sdk/moderation'
|
||||
import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {HITSLOP_10} from '#/lib/constants'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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'
|
||||
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
|
||||
import {type TriggerProps} from '#/components/Menu/types'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type chat} from '#/lexicons'
|
||||
import {EmojiPopup} from './EmojiPopup'
|
||||
import {hasAlreadyReacted, hasReachedReactionLimit} from './util'
|
||||
|
||||
@@ -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,6 +1,5 @@
|
||||
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'
|
||||
|
||||
@@ -10,6 +9,7 @@ import * as EmojiPicker from '#/components/EmojiPicker'
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {type chat} from '#/lexicons'
|
||||
import {hasAlreadyReacted, hasReachedReactionLimit} from './util'
|
||||
|
||||
export function EmojiReactionPicker({
|
||||
@@ -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()
|
||||
|
||||
@@ -7,12 +7,11 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import {LayoutAnimation, type TextInput, View} from 'react-native'
|
||||
import {type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {moderateProfile, type ModerationOpts} from '@bsky.app/sdk/moderation'
|
||||
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {MAX_GROUP_NAME_GRAPHEME_LENGTH} from '#/lib/constants'
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {isOverMaxGraphemeCount} from '#/lib/strings/helpers'
|
||||
|
||||
@@ -2,7 +2,6 @@ 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'
|
||||
@@ -10,7 +9,7 @@ import {useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {EMOJI_REACTION_LIMIT} from '#/lib/constants'
|
||||
import {useGoogleTranslate} from '#/lib/hooks/useGoogleTranslate'
|
||||
import {asSdkFacets, richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useConvoActive} from '#/state/messages/convo'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
@@ -28,6 +27,7 @@ import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Tra
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {type chat} from '#/lexicons'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
import {EmojiReactionPicker} from './EmojiReactionPicker'
|
||||
import {canReact, hasReachedReactionLimit} from './util'
|
||||
@@ -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']
|
||||
@@ -86,7 +86,7 @@ export let MessageContextMenu = ({
|
||||
const str = richTextToString(
|
||||
new RichText({
|
||||
text: message.text,
|
||||
facets: asSdkFacets(message.facets),
|
||||
facets: message.facets,
|
||||
}),
|
||||
true,
|
||||
)
|
||||
|
||||
@@ -22,12 +22,7 @@ import Animated, {
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
} from 'react-native-reanimated'
|
||||
import {
|
||||
AppBskyEmbedRecord,
|
||||
type ChatBskyActorDefs,
|
||||
ChatBskyConvoDefs,
|
||||
ChatBskyEmbedJoinLink,
|
||||
} from '@atproto/api'
|
||||
import {moderateProfile} from '@bsky.app/sdk/moderation'
|
||||
import {RichText as RichTextAPI} from '@bsky.app/sdk/richtext'
|
||||
import {plural} from '@lingui/core/macro'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
@@ -35,9 +30,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {isBlockedOrBlocking} from '#/lib/moderation/blocked-and-muted'
|
||||
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||
import {moderateProfile} from '#/lib/moderation/subjects'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {asSdkFacets} from '#/lib/strings/rich-text-helpers'
|
||||
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {type Shadow} from '#/state/cache/types'
|
||||
import {type ConvoItem} from '#/state/messages/convo/types'
|
||||
@@ -59,6 +52,8 @@ import * as ProfileCard from '#/components/ProfileCard'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {app, chat} from '#/lexicons'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {DateDivider} from './DateDivider'
|
||||
import {MessageItemEmbed} from './MessageItemEmbed'
|
||||
import {MessageItemInviteEmbed} from './MessageItemInviteEmbed'
|
||||
@@ -77,16 +72,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 +96,7 @@ function isWithinClusterBoundary({
|
||||
direction,
|
||||
}: {
|
||||
isPending: boolean
|
||||
message: ChatBskyConvoDefs.MessageView
|
||||
message: chat.bsky.convo.defs.MessageView
|
||||
adjacentMessage: MessageItemNeighbor
|
||||
isFromSameSender: boolean
|
||||
direction: 'prev' | 'next'
|
||||
@@ -110,7 +108,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 +135,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 +153,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 +177,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 +212,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
|
||||
@@ -248,14 +256,14 @@ let MessageItem = ({
|
||||
|
||||
const rt = new RichTextAPI({
|
||||
text: message.text,
|
||||
facets: asSdkFacets(message.facets),
|
||||
facets: message.facets,
|
||||
})
|
||||
|
||||
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 +524,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 +536,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 +677,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 +787,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 +802,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 +876,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 +888,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 +919,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',
|
||||
|
||||
@@ -5,10 +5,11 @@ import Animated, {
|
||||
type SharedValue,
|
||||
useAnimatedStyle,
|
||||
} from 'react-native-reanimated'
|
||||
import {type $Typed, type AppBskyEmbedRecord} from '@atproto/api'
|
||||
import {type $Typed} from '@atproto/lex'
|
||||
|
||||
import {atoms as a, native, useTheme, web} from '#/alf'
|
||||
import {Embed, PostEmbedViewContext} from '#/components/Post/Embed'
|
||||
import {type app} from '#/lexicons'
|
||||
import {MessageContextProvider} from './MessageContext'
|
||||
|
||||
const BORDER_RADIUS = 20
|
||||
@@ -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,12 +5,13 @@ import Animated, {
|
||||
type SharedValue,
|
||||
useAnimatedStyle,
|
||||
} from 'react-native-reanimated'
|
||||
import {type $Typed, type ChatBskyEmbedJoinLink} from '@atproto/api'
|
||||
import {type $Typed} from '@atproto/lex'
|
||||
|
||||
import {useConvoActive} from '#/state/messages/convo'
|
||||
import {isKnownJoinLinkPreview} from '#/state/queries/join-links'
|
||||
import {atoms as a, native, useTheme, web} from '#/alf'
|
||||
import * as ChatInvite from '#/components/dms/ChatInvite'
|
||||
import {type chat} from '#/lexicons'
|
||||
import {MessageContextProvider} from './MessageContext'
|
||||
|
||||
const BORDER_RADIUS = 20
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,6 @@ 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'
|
||||
|
||||
@@ -20,15 +19,16 @@ import {ReportDialog} from '#/components/moderation/ReportDialog'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import {usePromptControl} from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {type chat} from '#/lexicons'
|
||||
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)
|
||||
},
|
||||
[],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
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'
|
||||
@@ -16,11 +15,12 @@ import {canBeMessaged} from '#/components/dms/util'
|
||||
import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {type app} from '#/lexicons'
|
||||
|
||||
export function MessageProfileButton({
|
||||
profile,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
profile: app.bsky.actor.defs.ProfileViewDetailed
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
|
||||
@@ -7,7 +7,8 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {type ChatBskyConvoDefs} from '@atproto/api'
|
||||
|
||||
import {type chat} from '#/lexicons'
|
||||
|
||||
/**
|
||||
* How long a message stays highlighted after scrolling to it, before the flash
|
||||
@@ -28,8 +29,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 +67,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 +76,7 @@ export function MessageRepliesProvider({
|
||||
null,
|
||||
)
|
||||
|
||||
const setReply = useCallback((message: ChatBskyConvoDefs.MessageView) => {
|
||||
const setReply = useCallback((message: chat.bsky.convo.defs.MessageView) => {
|
||||
setReplyTo(message)
|
||||
}, [])
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user