Re-enable ESLint rules and fix violations
Re-enable 17 ESLint rules that were disabled during the ESLint v9 migration, and fix all violations across the codebase. ## Rules re-enabled: - prefer-const (91 auto-fixed) - no-var (4 auto-fixed) - no-empty (13 fixed) - no-irregular-whitespace (7 fixed) - no-unsafe-optional-chaining (25 fixed) - no-prototype-builtins (5 fixed) - @typescript-eslint/no-unused-expressions (6 fixed) - @typescript-eslint/no-non-null-asserted-optional-chain (3 fixed) - @typescript-eslint/no-wrapper-object-types (1 fixed) - @typescript-eslint/no-unsafe-function-type (1 fixed) - no-async-promise-executor (3 fixed) - prefer-rest-params (3 fixed) - no-case-declarations (3 fixed) - no-useless-escape (2 fixed) - no-sparse-arrays (1 fixed) - no-fallthrough (1 fixed) - no-control-regex (1 disabled - intentional) ## Rules kept disabled (too many violations): - @typescript-eslint/no-explicit-any (276) - @typescript-eslint/ban-ts-comment (126) - @typescript-eslint/no-empty-object-type (150) - no-empty-pattern (56 - many intentional)
This commit is contained in:
+2
-20
@@ -180,34 +180,16 @@ export default tseslint.config(
|
|||||||
{prefer: 'type-imports', fixStyle: 'inline-type-imports'},
|
{prefer: 'type-imports', fixStyle: 'inline-type-imports'},
|
||||||
],
|
],
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
// Maintain previous behavior - these are stricter in typescript-eslint v8
|
// Keep disabled - too many violations to fix now
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
'@typescript-eslint/ban-ts-comment': 'off',
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
'@typescript-eslint/no-empty-object-type': 'off',
|
'@typescript-eslint/no-empty-object-type': 'off',
|
||||||
'@typescript-eslint/no-unused-expressions': 'off',
|
|
||||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
|
|
||||||
'@typescript-eslint/no-wrapper-object-types': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
||||||
|
|
||||||
// Import rules
|
// Import rules
|
||||||
'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
|
'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
|
||||||
|
|
||||||
// Turn off rules that weren't enforced in previous config
|
// Keep disabled - many are intentional empty destructuring patterns
|
||||||
'no-empty-pattern': 'off',
|
'no-empty-pattern': 'off',
|
||||||
'no-async-promise-executor': 'off',
|
|
||||||
'no-constant-binary-expression': 'warn',
|
|
||||||
'prefer-const': 'off',
|
|
||||||
'no-empty': 'off',
|
|
||||||
'no-unsafe-optional-chaining': 'off',
|
|
||||||
'no-prototype-builtins': 'off',
|
|
||||||
'no-var': 'off',
|
|
||||||
'prefer-rest-params': 'off',
|
|
||||||
'no-case-declarations': 'off',
|
|
||||||
'no-irregular-whitespace': 'off',
|
|
||||||
'no-useless-escape': 'off',
|
|
||||||
'no-sparse-arrays': 'off',
|
|
||||||
'no-fallthrough': 'off',
|
|
||||||
'no-control-regex': 'off',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -111,13 +111,12 @@ export async function prefetchConfig() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
configPrefetchPromise = new Promise(async resolve => {
|
configPrefetchPromise = (async () => {
|
||||||
await cacheHydrationPromise
|
await cacheHydrationPromise
|
||||||
const cached = getConfigFromCache()
|
const cached = getConfigFromCache()
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
logger.debug(`prefetchAgeAssuranceConfig: using cache`)
|
logger.debug(`prefetchAgeAssuranceConfig: using cache`)
|
||||||
resolve()
|
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
logger.debug(`prefetchAgeAssuranceConfig: resolving...`)
|
logger.debug(`prefetchAgeAssuranceConfig: resolving...`)
|
||||||
@@ -130,11 +129,9 @@ export async function prefetchConfig() {
|
|||||||
logger.warn(`prefetchAgeAssuranceConfig: failed`, {
|
logger.warn(`prefetchAgeAssuranceConfig: failed`, {
|
||||||
safeMessage: e.message,
|
safeMessage: e.message,
|
||||||
})
|
})
|
||||||
} finally {
|
|
||||||
resolve()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})()
|
||||||
}
|
}
|
||||||
export async function refetchConfig() {
|
export async function refetchConfig() {
|
||||||
logger.debug(`refetchConfig: fetching...`)
|
logger.debug(`refetchConfig: fetching...`)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {type OtherRequiredData} from '#/ageAssurance/data'
|
|||||||
import {IS_DEV, IS_E2E} from '#/env'
|
import {IS_DEV, IS_E2E} from '#/env'
|
||||||
import {type Geolocation} from '#/geolocation'
|
import {type Geolocation} from '#/geolocation'
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-constant-binary-expression -- intentional debug toggle
|
||||||
export const enabled = (IS_DEV && false) || IS_E2E
|
export const enabled = (IS_DEV && false) || IS_E2E
|
||||||
|
|
||||||
export const geolocation: Geolocation | undefined = enabled
|
export const geolocation: Geolocation | undefined = enabled
|
||||||
|
|||||||
@@ -81,7 +81,11 @@ export function Outer({
|
|||||||
|
|
||||||
const handleBackgroundPress = React.useCallback(
|
const handleBackgroundPress = React.useCallback(
|
||||||
async (e: GestureResponderEvent) => {
|
async (e: GestureResponderEvent) => {
|
||||||
webOptions?.onBackgroundPress ? webOptions.onBackgroundPress(e) : close()
|
if (webOptions?.onBackgroundPress) {
|
||||||
|
webOptions.onBackgroundPress(e)
|
||||||
|
} else {
|
||||||
|
close()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[webOptions, close],
|
[webOptions, close],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ function DialogInner({guide}: {guide?: Follow10ProgressGuide}) {
|
|||||||
const results = hasSearchText
|
const results = hasSearchText
|
||||||
? searchResults?.pages.flatMap(p => p.actors)
|
? searchResults?.pages.flatMap(p => p.actors)
|
||||||
: suggestions?.actors
|
: suggestions?.actors
|
||||||
let _items: Item[] = []
|
const _items: Item[] = []
|
||||||
|
|
||||||
if (isFetchingSuggestions || isFetchingSearchResults) {
|
if (isFetchingSuggestions || isFetchingSearchResults) {
|
||||||
const placeholders: Item[] = Array(10)
|
const placeholders: Item[] = Array(10)
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ function Bubble({
|
|||||||
left -= left + cw - maxLeft
|
left -= left + cw - maxLeft
|
||||||
}
|
}
|
||||||
|
|
||||||
let tipLeft =
|
const tipLeft =
|
||||||
targetMeasurements.x -
|
targetMeasurements.x -
|
||||||
left +
|
left +
|
||||||
targetMeasurements.width / 2 -
|
targetMeasurements.width / 2 -
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ async function createProfileRecord(
|
|||||||
imageUri && imageMime ? uploadBlob(agent, imageUri, imageMime) : undefined
|
imageUri && imageMime ? uploadBlob(agent, imageUri, imageMime) : undefined
|
||||||
|
|
||||||
await agent.upsertProfile(async existing => {
|
await agent.upsertProfile(async existing => {
|
||||||
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
const next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
||||||
|
|
||||||
if (blobPromise) {
|
if (blobPromise) {
|
||||||
const res = await blobPromise
|
const res = await blobPromise
|
||||||
|
|||||||
@@ -185,7 +185,9 @@ export function Update(_props: ScreenProps<ScreenID.Update>) {
|
|||||||
try {
|
try {
|
||||||
// fire off a confirmation email immediately
|
// fire off a confirmation email immediately
|
||||||
await requestEmailVerification()
|
await requestEmailVerification()
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('EmailDialog: update email failed', {safeMessage: e})
|
logger.error('EmailDialog: update email failed', {safeMessage: e})
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ function DialogInner({
|
|||||||
} = useRemoveLiveStatusMutation()
|
} = useRemoveLiveStatusMutation()
|
||||||
|
|
||||||
const {minutesUntilExpiry, expiryDateTime} = useMemo(() => {
|
const {minutesUntilExpiry, expiryDateTime} = useMemo(() => {
|
||||||
tick!
|
void tick // revalidate every minute
|
||||||
|
|
||||||
const expiry = new Date(status.expiresAt ?? new Date())
|
const expiry = new Date(status.expiresAt ?? new Date())
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ function DialogInner({profile}: {profile: bsky.profile.AnyProfileView}) {
|
|||||||
|
|
||||||
const time = useCallback(
|
const time = useCallback(
|
||||||
(offset: number) => {
|
(offset: number) => {
|
||||||
tick!
|
void tick // revalidate every minute
|
||||||
|
|
||||||
const date = new Date()
|
const date = new Date()
|
||||||
date.setMinutes(date.getMinutes() + offset)
|
date.setMinutes(date.getMinutes() + offset)
|
||||||
|
|||||||
@@ -211,8 +211,8 @@ function Inner(props: ReportDialogProps) {
|
|||||||
logger.metric(
|
logger.metric(
|
||||||
'reportDialog:success',
|
'reportDialog:success',
|
||||||
{
|
{
|
||||||
reason: state.selectedOption?.reason!,
|
reason: state.selectedOption?.reason ?? '',
|
||||||
labeler: state.selectedLabeler?.creator.handle!,
|
labeler: state.selectedLabeler?.creator.handle ?? '',
|
||||||
details: !!state.details,
|
details: !!state.details,
|
||||||
},
|
},
|
||||||
{statsig: false},
|
{statsig: false},
|
||||||
@@ -719,7 +719,7 @@ function CategoryCard({
|
|||||||
{option.title}
|
{option.title}
|
||||||
</Text>
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
style={[a.text_sm, , a.leading_snug, t.atoms.text_contrast_medium]}>
|
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||||
{option.description}
|
{option.description}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export async function resolve() {
|
|||||||
* THIS PROMISE SHOULD NEVER `reject()`! We want the app to proceed with
|
* THIS PROMISE SHOULD NEVER `reject()`! We want the app to proceed with
|
||||||
* startup, even if geolocation resolution fails.
|
* startup, even if geolocation resolution fails.
|
||||||
*/
|
*/
|
||||||
geolocationServicePromise = new Promise(async resolve => {
|
geolocationServicePromise = (async () => {
|
||||||
let success = false
|
let success = false
|
||||||
|
|
||||||
function cacheResponseOrThrow(response: Geolocation | undefined) {
|
function cacheResponseOrThrow(response: Geolocation | undefined) {
|
||||||
@@ -111,10 +111,10 @@ export async function resolve() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
} finally {
|
|
||||||
resolve({success})
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
return {success}
|
||||||
|
})()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export const USRegionNameToRegionCode: {
|
|||||||
export function normalizeDeviceLocation(
|
export function normalizeDeviceLocation(
|
||||||
location: LocationGeocodedAddress,
|
location: LocationGeocodedAddress,
|
||||||
): Geolocation {
|
): Geolocation {
|
||||||
let {isoCountryCode, region} = location
|
const {isoCountryCode, region} = location
|
||||||
let regionCode: string | undefined = region ?? undefined
|
let regionCode: string | undefined = region ?? undefined
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
|||||||
const config = useLiveNowConfig()
|
const config = useLiveNowConfig()
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
tick! // revalidate every minute
|
void tick // revalidate every minute
|
||||||
|
|
||||||
if (shadowed && 'status' in shadowed && shadowed.status) {
|
if (shadowed && 'status' in shadowed && shadowed.status) {
|
||||||
const isValid = validateStatus(shadowed.did, shadowed.status, config)
|
const isValid = validateStatus(shadowed.did, shadowed.status, config)
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ export class FeedViewPostsSlice {
|
|||||||
|
|
||||||
getAuthors(): AuthorContext {
|
getAuthors(): AuthorContext {
|
||||||
const feedPost = this._feedPost
|
const feedPost = this._feedPost
|
||||||
let author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author
|
const author: AppBskyActorDefs.ProfileViewBasic = feedPost.post.author
|
||||||
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
let parentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
let grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
let grandparentAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
let rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
let rootAuthor: AppBskyActorDefs.ProfileViewBasic | undefined
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ async function loggedOutFetch({
|
|||||||
limit: number
|
limit: number
|
||||||
cursor?: string
|
cursor?: string
|
||||||
}) {
|
}) {
|
||||||
let contentLangs = getAppLanguageAsContentLanguage()
|
const contentLangs = getAppLanguageAsContentLanguage()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copied from our root `Agent` class
|
* Copied from our root `Agent` class
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export class MergeFeedAPI implements FeedAPI {
|
|||||||
// assemble a response by sampling from feeds with content
|
// assemble a response by sampling from feeds with content
|
||||||
const posts: AppBskyFeedDefs.FeedViewPost[] = []
|
const posts: AppBskyFeedDefs.FeedViewPost[] = []
|
||||||
while (posts.length < limit) {
|
while (posts.length < limit) {
|
||||||
let slice = this.sampleItem()
|
const slice = this.sampleItem()
|
||||||
if (slice[0]) {
|
if (slice[0]) {
|
||||||
posts.push(slice[0])
|
posts.push(slice[0])
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export async function post(
|
|||||||
const writes: $Typed<ComAtprotoRepoApplyWrites.Create>[] = []
|
const writes: $Typed<ComAtprotoRepoApplyWrites.Create>[] = []
|
||||||
const uris: string[] = []
|
const uris: string[] = []
|
||||||
|
|
||||||
let now = new Date()
|
const now = new Date()
|
||||||
let tid: TID | undefined
|
let tid: TID | undefined
|
||||||
|
|
||||||
for (let i = 0; i < thread.posts.length; i++) {
|
for (let i = 0; i < thread.posts.length; i++) {
|
||||||
|
|||||||
@@ -229,5 +229,7 @@ export async function imageToThumb(
|
|||||||
if (img) {
|
if (img) {
|
||||||
return await createComposerImage(img)
|
return await createComposerImage(img)
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function isPlainArray(value: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
||||||
export function isPlainObject(o: any): o is Object {
|
export function isPlainObject(o: any): o is object {
|
||||||
if (!hasObjectPrototype(o)) {
|
if (!hasObjectPrototype(o)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ export function isPlainObject(o: any): o is Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If constructor does not have an Object-specific method
|
// If constructor does not have an Object-specific method
|
||||||
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
if (!Object.prototype.hasOwnProperty.call(prot, 'isPrototypeOf')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {getCurrentRoute} from '#/lib/routes/helpers'
|
|||||||
|
|
||||||
export function useNavigationTabState() {
|
export function useNavigationTabState() {
|
||||||
return useNavigationState(state => {
|
return useNavigationState(state => {
|
||||||
let currentRoute = state ? getCurrentRoute(state).name : 'Home'
|
const currentRoute = state ? getCurrentRoute(state).name : 'Home'
|
||||||
return {
|
return {
|
||||||
isAtHome: currentRoute === 'Home',
|
isAtHome: currentRoute === 'Home',
|
||||||
isAtSearch: currentRoute === 'Search',
|
isAtSearch: currentRoute === 'Search',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {useCallback, useInsertionEffect, useRef} from 'react'
|
|||||||
//
|
//
|
||||||
// Also, you should avoid calling the returned function during rendering
|
// Also, you should avoid calling the returned function during rendering
|
||||||
// since the values captured by it are going to lag behind.
|
// since the values captured by it are going to lag behind.
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- generic utility needs Function type
|
||||||
export function useNonReactiveCallback<T extends Function>(fn: T): T {
|
export function useNonReactiveCallback<T extends Function>(fn: T): T {
|
||||||
const ref = useRef(fn)
|
const ref = useRef(fn)
|
||||||
useInsertionEffect(() => {
|
useInsertionEffect(() => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function useTabFocusEffect(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// check if inside
|
// check if inside
|
||||||
let v = getTabState(state, tabName) !== TabState.Outside
|
const v = getTabState(state, tabName) !== TabState.Outside
|
||||||
if (v !== isInside) {
|
if (v !== isInside) {
|
||||||
// fire
|
// fire
|
||||||
setIsInside(v)
|
setIsInside(v)
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export async function saveImageToMediaLibrary(_opts: {uri: string}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getImageDim(path: string): Promise<Dimensions> {
|
export async function getImageDim(path: string): Promise<Dimensions> {
|
||||||
var img = document.createElement('img')
|
const img = document.createElement('img')
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
img.onload = resolve
|
img.onload = resolve
|
||||||
img.onerror = reject
|
img.onerror = reject
|
||||||
@@ -139,8 +139,8 @@ function createResizedImage(
|
|||||||
} else if (mode === 'contain') {
|
} else if (mode === 'contain') {
|
||||||
scale = img.width > img.height ? width / img.width : height / img.height
|
scale = img.width > img.height ? width / img.width : height / img.height
|
||||||
}
|
}
|
||||||
let w = img.width * scale
|
const w = img.width * scale
|
||||||
let h = img.height * scale
|
const h = img.height * scale
|
||||||
|
|
||||||
canvas.width = w
|
canvas.width = w
|
||||||
canvas.height = h
|
canvas.height = h
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export class Router<T extends Record<string, any>> {
|
|||||||
|
|
||||||
function createRoute(pattern: string): Route {
|
function createRoute(pattern: string): Route {
|
||||||
const pathParamNames: Set<string> = new Set()
|
const pathParamNames: Set<string> = new Set()
|
||||||
let matcherReInternal = pattern.replace(/:([\w]+)/g, (_m, name) => {
|
const matcherReInternal = pattern.replace(/:([\w]+)/g, (_m, name) => {
|
||||||
pathParamNames.add(name)
|
pathParamNames.add(name)
|
||||||
return `(?<${name}>[^/]+)`
|
return `(?<${name}>[^/]+)`
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ function toStringRecord<E extends keyof MetricEvents>(
|
|||||||
metadata: MetricEvents[E] & FlatJSONRecord,
|
metadata: MetricEvents[E] & FlatJSONRecord,
|
||||||
): Record<string, string> {
|
): Record<string, string> {
|
||||||
const record: Record<string, string> = {}
|
const record: Record<string, string> = {}
|
||||||
for (let key in metadata) {
|
for (const key in metadata) {
|
||||||
if (metadata.hasOwnProperty(key)) {
|
if (Object.hasOwn(metadata, key)) {
|
||||||
if (typeof metadata[key] === 'string') {
|
if (typeof metadata[key] === 'string') {
|
||||||
record[key] = metadata[key]
|
record[key] = metadata[key]
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {type ModerationUI} from '@atproto/api'
|
|||||||
// \u2611 = ☑
|
// \u2611 = ☑
|
||||||
const CHECK_MARKS_RE = /[\u2705\u2713\u2714\u2611]/gu
|
const CHECK_MARKS_RE = /[\u2705\u2713\u2714\u2611]/gu
|
||||||
const CONTROL_CHARS_RE =
|
const CONTROL_CHARS_RE =
|
||||||
|
// eslint-disable-next-line no-control-regex -- intentionally matching control characters for sanitization
|
||||||
/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g
|
/[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g
|
||||||
const MULTIPLE_SPACES_RE = /[\s][\s\u200B]+/g
|
const MULTIPLE_SPACES_RE = /[\s][\s\u200B]+/g
|
||||||
|
|
||||||
|
|||||||
@@ -426,7 +426,7 @@ export function parseEmbedPlayerFromUrl(
|
|||||||
// link shortened flickr path
|
// link shortened flickr path
|
||||||
if (urlp.hostname === 'flic.kr') {
|
if (urlp.hostname === 'flic.kr') {
|
||||||
const b58alph = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
|
const b58alph = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
|
||||||
let [__, type, idBase58Enc] = urlp.pathname.split('/')
|
const [__, type, idBase58Enc] = urlp.pathname.split('/')
|
||||||
let id = 0n
|
let id = 0n
|
||||||
for (const char of idBase58Enc) {
|
for (const char of idBase58Enc) {
|
||||||
const nextIdx = b58alph.indexOf(char)
|
const nextIdx = b58alph.indexOf(char)
|
||||||
@@ -439,7 +439,7 @@ export function parseEmbedPlayerFromUrl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'go':
|
case 'go': {
|
||||||
const formattedGroupId = `${id}`
|
const formattedGroupId = `${id}`
|
||||||
return {
|
return {
|
||||||
type: 'flickr_album',
|
type: 'flickr_album',
|
||||||
@@ -449,6 +449,7 @@ export function parseEmbedPlayerFromUrl(
|
|||||||
-2,
|
-2,
|
||||||
)}@N${formattedGroupId.slice(-2)}`,
|
)}@N${formattedGroupId.slice(-2)}`,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
case 's':
|
case 's':
|
||||||
return {
|
return {
|
||||||
type: 'flickr_album',
|
type: 'flickr_album',
|
||||||
@@ -537,13 +538,13 @@ export function parseTenorGif(urlp: URL):
|
|||||||
return {success: false}
|
return {success: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
let [__, id, filename] = urlp.pathname.split('/')
|
const [, initialId, initialFilename] = urlp.pathname.split('/')
|
||||||
|
|
||||||
if (!id || !filename) {
|
if (!initialId || !initialFilename) {
|
||||||
return {success: false}
|
return {success: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!id.includes('AAAAC')) {
|
if (!initialId.includes('AAAAC')) {
|
||||||
return {success: false}
|
return {success: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,16 +560,19 @@ export function parseTenorGif(urlp: URL):
|
|||||||
width: Number(w),
|
width: Number(w),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id: string
|
||||||
|
let filename: string
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
if (isSafari) {
|
if (isSafari) {
|
||||||
id = id.replace('AAAAC', 'AAAP1')
|
id = initialId.replace('AAAAC', 'AAAP1')
|
||||||
filename = filename.replace('.gif', '.mp4')
|
filename = initialFilename.replace('.gif', '.mp4')
|
||||||
} else {
|
} else {
|
||||||
id = id.replace('AAAAC', 'AAAP3')
|
id = initialId.replace('AAAAC', 'AAAP3')
|
||||||
filename = filename.replace('.gif', '.webm')
|
filename = initialFilename.replace('.gif', '.webm')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
id = id.replace('AAAAC', 'AAAAM')
|
id = initialId.replace('AAAAC', 'AAAAM')
|
||||||
|
filename = initialFilename
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export function getMentionAt(
|
|||||||
text: string,
|
text: string,
|
||||||
cursorPos: number,
|
cursorPos: number,
|
||||||
): FoundMention | undefined {
|
): FoundMention | undefined {
|
||||||
let re = /(^|\s)@([a-z0-9.-]*)/gi
|
const re = /(^|\s)@([a-z0-9.-]*)/gi
|
||||||
let match
|
let match
|
||||||
while ((match = re.exec(text))) {
|
while ((match = re.exec(text))) {
|
||||||
const spaceOffset = match[1].length
|
const spaceOffset = match[1].length
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ export function niceDate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAge(birthDate: Date): number {
|
export function getAge(birthDate: Date): number {
|
||||||
var today = new Date()
|
const today = new Date()
|
||||||
var age = today.getFullYear() - birthDate.getFullYear()
|
let age = today.getFullYear() - birthDate.getFullYear()
|
||||||
var m = today.getMonth() - birthDate.getMonth()
|
const m = today.getMonth() - birthDate.getMonth()
|
||||||
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
||||||
age--
|
age--
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ const TRUSTED_REGEX = new RegExp(
|
|||||||
|
|
||||||
export function isValidDomain(str: string): boolean {
|
export function isValidDomain(str: string): boolean {
|
||||||
return !!TLDs.find(tld => {
|
return !!TLDs.find(tld => {
|
||||||
let i = str.lastIndexOf(tld)
|
const i = str.lastIndexOf(tld)
|
||||||
if (i === -1) {
|
if (i === -1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,9 @@ export function isBskyPostUrl(url: string): boolean {
|
|||||||
return /profile\/(?<name>[^/]+)\/post\/(?<rkey>[^/]+)/i.test(
|
return /profile\/(?<name>[^/]+)\/post\/(?<rkey>[^/]+)/i.test(
|
||||||
urlp.pathname,
|
urlp.pathname,
|
||||||
)
|
)
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -135,7 +137,9 @@ export function isBskyCustomFeedUrl(url: string): boolean {
|
|||||||
return /profile\/(?<name>[^/]+)\/feed\/(?<rkey>[^/]+)/i.test(
|
return /profile\/(?<name>[^/]+)\/feed\/(?<rkey>[^/]+)/i.test(
|
||||||
urlp.pathname,
|
urlp.pathname,
|
||||||
)
|
)
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -291,10 +295,14 @@ export function labelToDomain(label: string): string | undefined {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new URL(label).hostname.toLowerCase()
|
return new URL(label).hostname.toLowerCase()
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return new URL('https://' + label).hostname.toLowerCase()
|
return new URL('https://' + label).hostname.toLowerCase()
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +314,7 @@ export function isPossiblyAUrl(str: string): boolean {
|
|||||||
if (str.startsWith('https://')) {
|
if (str.startsWith('https://')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
const [firstWord] = str.split(/[\s\/]/)
|
const [firstWord] = str.split(/[\s/]/)
|
||||||
return isValidDomain(firstWord)
|
return isValidDomain(firstWord)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
// This is a hack to get it showing as a redbox on the web so we catch it early.
|
// This is a hack to get it showing as a redbox on the web so we catch it early.
|
||||||
const realConsoleError = console.error
|
const realConsoleError = console.error
|
||||||
const thrownErrors = new WeakSet()
|
const thrownErrors = new WeakSet()
|
||||||
console.error = function consoleErrorWrapper(msgOrError) {
|
console.error = function consoleErrorWrapper(
|
||||||
|
...args: Parameters<typeof console.error>
|
||||||
|
) {
|
||||||
|
const msgOrError = args[0]
|
||||||
if (
|
if (
|
||||||
typeof msgOrError === 'string' &&
|
typeof msgOrError === 'string' &&
|
||||||
msgOrError.startsWith('Unexpected text node')
|
msgOrError.startsWith('Unexpected text node')
|
||||||
@@ -28,7 +31,7 @@ if (process.env.NODE_ENV !== 'production') {
|
|||||||
thrownErrors.add(err)
|
thrownErrors.add(err)
|
||||||
throw err
|
throw err
|
||||||
} else if (!thrownErrors.has(msgOrError)) {
|
} else if (!thrownErrors.has(msgOrError)) {
|
||||||
return realConsoleError.apply(this, arguments as any)
|
return realConsoleError.apply(this, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,9 @@ function BookmarksInner() {
|
|||||||
if (isFetchingNextPage || !hasNextPage || error) return
|
if (isFetchingNextPage || !hasNextPage || error) return
|
||||||
try {
|
try {
|
||||||
await fetchNextPage()
|
await fetchNextPage()
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])
|
||||||
|
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function NoFeedsPinned({
|
|||||||
const addRecommendedFeeds = React.useCallback(async () => {
|
const addRecommendedFeeds = React.useCallback(async () => {
|
||||||
let skippedTimeline = false
|
let skippedTimeline = false
|
||||||
let skippedDiscover = false
|
let skippedDiscover = false
|
||||||
let remainingSavedFeeds = []
|
const remainingSavedFeeds = []
|
||||||
|
|
||||||
// remove first instance of both timeline and discover, since we're going to overwrite them
|
// remove first instance of both timeline and discover, since we're going to overwrite them
|
||||||
for (const savedFeed of preferences.savedFeeds) {
|
for (const savedFeed of preferences.savedFeeds) {
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ export function MessageInputEmbed({
|
|||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'success':
|
case 'success': {
|
||||||
const itemUrip = new AtUri(post.uri)
|
const itemUrip = new AtUri(post.uri)
|
||||||
const itemHref = makeProfileLink(post.author, 'post', itemUrip.rkey)
|
const itemHref = makeProfileLink(post.author, 'post', itemUrip.rkey)
|
||||||
|
|
||||||
@@ -203,6 +203,7 @@ export function MessageInputEmbed({
|
|||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export function StepFinished() {
|
|||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
await agent.upsertProfile(async existing => {
|
await agent.upsertProfile(async existing => {
|
||||||
let next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
const next: Un$Typed<AppBskyActorProfile.Record> = existing ?? {}
|
||||||
|
|
||||||
if (blobPromise) {
|
if (blobPromise) {
|
||||||
const res = await blobPromise
|
const res = await blobPromise
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export function StarterPackCard({
|
|||||||
setIsFollowingAll(true)
|
setIsFollowingAll(true)
|
||||||
setIsProcessing(false)
|
setIsProcessing(false)
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
for (let did of dids) {
|
for (const did of dids) {
|
||||||
updateProfileShadow(queryClient, did, {
|
updateProfileShadow(queryClient, did, {
|
||||||
followingUri: followUris.get(did),
|
followingUri: followUris.get(did),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ export function Explore({
|
|||||||
if (suggestedUsers.actors.length > 0 && moderationOpts) {
|
if (suggestedUsers.actors.length > 0 && moderationOpts) {
|
||||||
// Currently the responses contain duplicate items.
|
// Currently the responses contain duplicate items.
|
||||||
// Needs to be fixed on backend, but let's dedupe to be safe.
|
// Needs to be fixed on backend, but let's dedupe to be safe.
|
||||||
let seen = new Set()
|
const seen = new Set()
|
||||||
const profileItems: ExploreScreenItems[] = []
|
const profileItems: ExploreScreenItems[] = []
|
||||||
for (const actor of suggestedUsers.actors) {
|
for (const actor of suggestedUsers.actors) {
|
||||||
// checking for following still necessary if search data is used
|
// checking for following still necessary if search data is used
|
||||||
@@ -439,7 +439,7 @@ export function Explore({
|
|||||||
|
|
||||||
if (useFullExperience) {
|
if (useFullExperience) {
|
||||||
if (suggestedFeeds && preferences) {
|
if (suggestedFeeds && preferences) {
|
||||||
let seen = new Set()
|
const seen = new Set()
|
||||||
const feedItems: ExploreScreenItems[] = []
|
const feedItems: ExploreScreenItems[] = []
|
||||||
for (const feed of suggestedFeeds.feeds) {
|
for (const feed of suggestedFeeds.feeds) {
|
||||||
if (!seen.has(feed.uri)) {
|
if (!seen.has(feed.uri)) {
|
||||||
@@ -527,7 +527,7 @@ export function Explore({
|
|||||||
if (feeds && preferences) {
|
if (feeds && preferences) {
|
||||||
// Currently the responses contain duplicate items.
|
// Currently the responses contain duplicate items.
|
||||||
// Needs to be fixed on backend, but let's dedupe to be safe.
|
// Needs to be fixed on backend, but let's dedupe to be safe.
|
||||||
let seen = new Set()
|
const seen = new Set()
|
||||||
const feedItems: ExploreScreenItems[] = []
|
const feedItems: ExploreScreenItems[] = []
|
||||||
for (const page of feeds.pages) {
|
for (const page of feeds.pages) {
|
||||||
for (const feed of page.feeds) {
|
for (const feed of page.feeds) {
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ let SearchScreenPostResults = ({
|
|||||||
return results?.pages.flatMap(page => page.posts) || []
|
return results?.pages.flatMap(page => page.posts) || []
|
||||||
}, [results])
|
}, [results])
|
||||||
const items = useMemo(() => {
|
const items = useMemo(() => {
|
||||||
let temp: SearchResultSlice[] = []
|
const temp: SearchResultSlice[] = []
|
||||||
|
|
||||||
const seenUris = new Set()
|
const seenUris = new Set()
|
||||||
for (const post of posts) {
|
for (const post of posts) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function parseSearchQuery(rawQuery: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find remaining params in base
|
// find remaining params in base
|
||||||
const rawParams = base.match(/[a-z]+:[a-z-\.@\d:"]+/gi) || []
|
const rawParams = base.match(/[a-z]+:[a-z-.@\d:"]+/gi) || []
|
||||||
|
|
||||||
for (const param of rawParams) {
|
for (const param of rawParams) {
|
||||||
base = base.replace(param, '')
|
base = base.replace(param, '')
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function is18(date: Date) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function reducer(s: SignupState, a: SignupAction): SignupState {
|
export function reducer(s: SignupState, a: SignupAction): SignupState {
|
||||||
let next = {...s}
|
const next = {...s}
|
||||||
|
|
||||||
switch (a.type) {
|
switch (a.type) {
|
||||||
case 'prev': {
|
case 'prev': {
|
||||||
@@ -330,11 +330,11 @@ export function useSubmitSignup() {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Must happen last so that if the user has multiple tabs open and
|
* Must happen last so that if the user has multiple tabs open and
|
||||||
* createAccount fails, one tab is not stuck in onboarding — Eric
|
* createAccount fails, one tab is not stuck in onboarding — Eric
|
||||||
*/
|
*/
|
||||||
onboardingDispatch({type: 'start'})
|
onboardingDispatch({type: 'start'})
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
let errMsg = e.toString()
|
const errMsg = e.toString()
|
||||||
if (e instanceof ComAtprotoServerCreateAccount.InvalidInviteCodeError) {
|
if (e instanceof ComAtprotoServerCreateAccount.InvalidInviteCodeError) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'setError',
|
type: 'setError',
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ function Header({
|
|||||||
|
|
||||||
setIsProcessing(false)
|
setIsProcessing(false)
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
for (let did of dids) {
|
for (const did of dids) {
|
||||||
updateProfileShadow(queryClient, did, {
|
updateProfileShadow(queryClient, did, {
|
||||||
followingUri: followUris.get(did),
|
followingUri: followUris.get(did),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -74,8 +74,9 @@ export function Header({
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'author':
|
case 'author':
|
||||||
// TODO
|
// falls through
|
||||||
default: {
|
default: {
|
||||||
|
// TODO: implement author header
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+8
-8
@@ -158,7 +158,7 @@ export function updatePostShadow(
|
|||||||
value: Partial<PostShadow>,
|
value: Partial<PostShadow>,
|
||||||
) {
|
) {
|
||||||
const cachedPosts = findPostsInCache(queryClient, uri)
|
const cachedPosts = findPostsInCache(queryClient, uri)
|
||||||
for (let post of cachedPosts) {
|
for (const post of cachedPosts) {
|
||||||
shadows.set(post, {...shadows.get(post), ...value})
|
shadows.set(post, {...shadows.get(post), ...value})
|
||||||
}
|
}
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
@@ -170,28 +170,28 @@ function* findPostsInCache(
|
|||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
uri: string,
|
uri: string,
|
||||||
): Generator<AppBskyFeedDefs.PostView, void> {
|
): Generator<AppBskyFeedDefs.PostView, void> {
|
||||||
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInNotifsQueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInThreadV2QueryData(queryClient, uri)) {
|
for (const post of findAllPostsInThreadV2QueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInSearchQueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInQuoteQueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInExploreFeedPreviewsQueryData(
|
for (const post of findAllPostsInExploreFeedPreviewsQueryData(
|
||||||
queryClient,
|
queryClient,
|
||||||
uri,
|
uri,
|
||||||
)) {
|
)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInBookmarksQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInBookmarksQueryData(queryClient, uri)) {
|
||||||
yield post
|
yield post
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -195,7 +195,7 @@ export function updateProfileShadow(
|
|||||||
value: Partial<ProfileShadow>,
|
value: Partial<ProfileShadow>,
|
||||||
) {
|
) {
|
||||||
const cachedProfiles = findProfilesInCache(queryClient, did)
|
const cachedProfiles = findProfilesInCache(queryClient, did)
|
||||||
for (let profile of cachedProfiles) {
|
for (const profile of cachedProfiles) {
|
||||||
shadows.set(profile, {...shadows.get(profile), ...value})
|
shadows.set(profile, {...shadows.get(profile), ...value})
|
||||||
}
|
}
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ function sendOrAggregateInteractionsForStats(
|
|||||||
interactions: AppBskyFeedDefs.Interaction[],
|
interactions: AppBskyFeedDefs.Interaction[],
|
||||||
feed: string,
|
feed: string,
|
||||||
) {
|
) {
|
||||||
for (let interaction of interactions) {
|
for (const interaction of interactions) {
|
||||||
switch (interaction.event) {
|
switch (interaction.event) {
|
||||||
// Pressing "Show more" / "Show less" is relatively uncommon so we won't aggregate them.
|
// Pressing "Show more" / "Show less" is relatively uncommon so we won't aggregate them.
|
||||||
// This lets us send the feed context together with them.
|
// This lets us send the feed context together with them.
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const closeLightbox = useNonReactiveCallback(() => {
|
const closeLightbox = useNonReactiveCallback(() => {
|
||||||
let wasActive = !!activeLightbox
|
const wasActive = !!activeLightbox
|
||||||
setActiveLightbox(null)
|
setActiveLightbox(null)
|
||||||
return wasActive
|
return wasActive
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export class Convo {
|
|||||||
this.convoId = params.convoId
|
this.convoId = params.convoId
|
||||||
this.agent = params.agent
|
this.agent = params.agent
|
||||||
this.events = params.events
|
this.events = params.events
|
||||||
this.senderUserDid = params.agent.session?.did!
|
this.senderUserDid = params.agent.session?.did ?? ''
|
||||||
|
|
||||||
if (params.placeholderData) {
|
if (params.placeholderData) {
|
||||||
this.setupPlaceholderData(params.placeholderData)
|
this.setupPlaceholderData(params.placeholderData)
|
||||||
@@ -557,11 +557,7 @@ export class Convo {
|
|||||||
async fetchConvo() {
|
async fetchConvo() {
|
||||||
if (this.pendingFetchConvo) return this.pendingFetchConvo
|
if (this.pendingFetchConvo) return this.pendingFetchConvo
|
||||||
|
|
||||||
this.pendingFetchConvo = new Promise<{
|
this.pendingFetchConvo = (async () => {
|
||||||
convo: ChatBskyConvoDefs.ConvoView
|
|
||||||
sender: ChatBskyActorDefs.ProfileViewBasic | undefined
|
|
||||||
recipients: ChatBskyActorDefs.ProfileViewBasic[]
|
|
||||||
}>(async (resolve, reject) => {
|
|
||||||
try {
|
try {
|
||||||
const response = await networkRetry(2, () => {
|
const response = await networkRetry(2, () => {
|
||||||
return this.agent.api.chat.bsky.convo.getConvo(
|
return this.agent.api.chat.bsky.convo.getConvo(
|
||||||
@@ -574,17 +570,15 @@ export class Convo {
|
|||||||
|
|
||||||
const convo = response.data.convo
|
const convo = response.data.convo
|
||||||
|
|
||||||
resolve({
|
return {
|
||||||
convo,
|
convo,
|
||||||
sender: convo.members.find(m => m.did === this.senderUserDid),
|
sender: convo.members.find(m => m.did === this.senderUserDid),
|
||||||
recipients: convo.members.filter(m => m.did !== this.senderUserDid),
|
recipients: convo.members.filter(m => m.did !== this.senderUserDid),
|
||||||
})
|
}
|
||||||
} catch (e) {
|
|
||||||
reject(e)
|
|
||||||
} finally {
|
} finally {
|
||||||
this.pendingFetchConvo = undefined
|
this.pendingFetchConvo = undefined
|
||||||
}
|
}
|
||||||
})
|
})()
|
||||||
|
|
||||||
return this.pendingFetchConvo
|
return this.pendingFetchConvo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,7 +352,7 @@ export class MessagesEventBus {
|
|||||||
const {logs: events} = response.data
|
const {logs: events} = response.data
|
||||||
|
|
||||||
let needsEmit = false
|
let needsEmit = false
|
||||||
let batch: ChatBskyConvoGetLog.OutputSchema['logs'] = []
|
const batch: ChatBskyConvoGetLog.OutputSchema['logs'] = []
|
||||||
|
|
||||||
for (const ev of events) {
|
for (const ev of events) {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const closeModal = useNonReactiveCallback(() => {
|
const closeModal = useNonReactiveCallback(() => {
|
||||||
let wasActive = activeModals.length > 0
|
const wasActive = activeModals.length > 0
|
||||||
setActiveModals(modals => {
|
setActiveModals(modals => {
|
||||||
return modals.slice(0, -1)
|
return modals.slice(0, -1)
|
||||||
})
|
})
|
||||||
@@ -68,7 +68,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const closeAllModals = useNonReactiveCallback(() => {
|
const closeAllModals = useNonReactiveCallback(() => {
|
||||||
let wasActive = activeModals.length > 0
|
const wasActive = activeModals.length > 0
|
||||||
setActiveModals([])
|
setActiveModals([])
|
||||||
return wasActive
|
return wasActive
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ function computeSuggestions({
|
|||||||
searched?: AppBskyActorDefs.ProfileViewBasic[]
|
searched?: AppBskyActorDefs.ProfileViewBasic[]
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
}) {
|
}) {
|
||||||
let items: AppBskyActorDefs.ProfileViewBasic[] = []
|
const items: AppBskyActorDefs.ProfileViewBasic[] = []
|
||||||
for (const item of searched) {
|
for (const item of searched) {
|
||||||
if (!items.find(item2 => item2.handle === item.handle)) {
|
if (!items.find(item2 => item2.handle === item.handle)) {
|
||||||
items.push(item)
|
items.push(item)
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ export function* findAllPostsInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const bookmark of page.bookmarks) {
|
for (const bookmark of page.bookmarks) {
|
||||||
if (
|
if (
|
||||||
!bsky.dangerousIsType<AppBskyFeedDefs.PostView>(
|
!bsky.dangerousIsType<AppBskyFeedDefs.PostView>(
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ export function* findAllPostsInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.posts) {
|
for (const item of page.posts) {
|
||||||
if (didOrHandleUriMatches(atUri, item.post)) {
|
if (didOrHandleUriMatches(atUri, item.post)) {
|
||||||
yield item.post
|
yield item.post
|
||||||
@@ -420,7 +420,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.posts) {
|
for (const item of page.posts) {
|
||||||
if (item.post.author.did === did) {
|
if (item.post.author.did === did) {
|
||||||
yield item.post.author
|
yield item.post.author
|
||||||
|
|||||||
@@ -439,7 +439,7 @@ export function usePinnedFeedsInfos() {
|
|||||||
return [PWI_DISCOVER_FEED_STUB]
|
return [PWI_DISCOVER_FEED_STUB]
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolved = new Map<string, FeedSourceInfo>()
|
const resolved = new Map<string, FeedSourceInfo>()
|
||||||
|
|
||||||
// Get all feeds. We can do this in a batch.
|
// Get all feeds. We can do this in a batch.
|
||||||
const pinnedFeeds = pinnedItems.filter(feed => feed.type === 'feed')
|
const pinnedFeeds = pinnedItems.filter(feed => feed.type === 'feed')
|
||||||
@@ -476,7 +476,7 @@ export function usePinnedFeedsInfos() {
|
|||||||
|
|
||||||
// order the feeds/lists in the order they were pinned
|
// order the feeds/lists in the order they were pinned
|
||||||
const result: SavedFeedSourceInfo[] = []
|
const result: SavedFeedSourceInfo[] = []
|
||||||
for (let pinnedItem of pinnedItems) {
|
for (const pinnedItem of pinnedItems) {
|
||||||
const feedInfo = resolved.get(pinnedItem.value)
|
const feedInfo = resolved.get(pinnedItem.value)
|
||||||
if (feedInfo) {
|
if (feedInfo) {
|
||||||
result.push({
|
result.push({
|
||||||
@@ -590,7 +590,7 @@ export function useSavedFeeds() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const result: SavedFeedItem[] = []
|
const result: SavedFeedItem[] = []
|
||||||
for (let savedItem of savedItems) {
|
for (const savedItem of savedItems) {
|
||||||
if (savedItem.type === 'timeline') {
|
if (savedItem.type === 'timeline') {
|
||||||
result.push({
|
result.push({
|
||||||
type: 'timeline',
|
type: 'timeline',
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const match of page.matches) {
|
for (const match of page.matches) {
|
||||||
if (match.did === did) {
|
if (match.did === did) {
|
||||||
yield match
|
yield match
|
||||||
|
|||||||
@@ -120,7 +120,9 @@ export async function checkHandleAvailability(
|
|||||||
logger.metric('signup:handleTaken', {typeahead}, {statsig: true})
|
logger.metric('signup:handleTaken', {typeahead}, {statsig: true})
|
||||||
return {available: false} as const
|
return {available: false} as const
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
logger.metric('signup:handleAvailable', {typeahead}, {statsig: true})
|
logger.metric('signup:handleAvailable', {typeahead}, {statsig: true})
|
||||||
return {available: true} as const
|
return {available: true} as const
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const follow of page.followers) {
|
for (const follow of page.followers) {
|
||||||
if (follow.did === did) {
|
if (follow.did === did) {
|
||||||
yield follow
|
yield follow
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
if (page.list.creator.did === did) {
|
if (page.list.creator.did === did) {
|
||||||
yield page.list.creator
|
yield page.list.creator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const block of page.blocks) {
|
for (const block of page.blocks) {
|
||||||
if (block.did === did) {
|
if (block.did === did) {
|
||||||
yield block
|
yield block
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export function useMyListsQuery(filter: MyListsFilter) {
|
|||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
queryKey: RQKEY(filter),
|
queryKey: RQKEY(filter),
|
||||||
async queryFn() {
|
async queryFn() {
|
||||||
let lists: AppBskyGraphDefs.ListView[] = []
|
const lists: AppBskyGraphDefs.ListView[] = []
|
||||||
const promises = [
|
const promises = [
|
||||||
accumulate(cursor =>
|
accumulate(cursor =>
|
||||||
agent.app.bsky.graph
|
agent.app.bsky.graph
|
||||||
@@ -66,7 +66,7 @@ export function useMyListsQuery(filter: MyListsFilter) {
|
|||||||
}
|
}
|
||||||
const resultset = await Promise.all(promises)
|
const resultset = await Promise.all(promises)
|
||||||
for (const res of resultset) {
|
for (const res of resultset) {
|
||||||
for (let list of res) {
|
for (const list of res) {
|
||||||
if (
|
if (
|
||||||
filter === 'curate' &&
|
filter === 'curate' &&
|
||||||
list.purpose !== 'app.bsky.graph.defs#curatelist'
|
list.purpose !== 'app.bsky.graph.defs#curatelist'
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const mute of page.mutes) {
|
for (const mute of page.mutes) {
|
||||||
if (mute.did === did) {
|
if (mute.did === did) {
|
||||||
yield mute
|
yield mute
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ export function useNotificationFeedQuery(opts: {
|
|||||||
|
|
||||||
// Keep track of the last run and whether we can reuse
|
// Keep track of the last run and whether we can reuse
|
||||||
// some already selected pages from there.
|
// some already selected pages from there.
|
||||||
let reusedPages = []
|
const reusedPages = []
|
||||||
if (lastRun.current) {
|
if (lastRun.current) {
|
||||||
const {
|
const {
|
||||||
data: lastData,
|
data: lastData,
|
||||||
@@ -141,8 +141,8 @@ export function useNotificationFeedQuery(opts: {
|
|||||||
result: lastResult,
|
result: lastResult,
|
||||||
} = lastRun.current
|
} = lastRun.current
|
||||||
let canReuse = true
|
let canReuse = true
|
||||||
for (let key in selectArgs) {
|
for (const key in selectArgs) {
|
||||||
if (selectArgs.hasOwnProperty(key)) {
|
if (Object.hasOwn(selectArgs, key)) {
|
||||||
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
||||||
// Can't do reuse anything if any input has changed.
|
// Can't do reuse anything if any input has changed.
|
||||||
canReuse = false
|
canReuse = false
|
||||||
@@ -287,7 +287,7 @@ export function* findAllPostsInQueryData(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.items) {
|
for (const item of page.items) {
|
||||||
if (item.type !== 'starterpack-joined') {
|
if (item.type !== 'starterpack-joined') {
|
||||||
if (item.subject && didOrHandleUriMatches(atUri, item.subject)) {
|
if (item.subject && didOrHandleUriMatches(atUri, item.subject)) {
|
||||||
@@ -317,7 +317,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.items) {
|
for (const item of page.items) {
|
||||||
if (
|
if (
|
||||||
(item.type === 'follow' || item.type === 'contact-match') &&
|
(item.type === 'follow' || item.type === 'contact-match') &&
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export async function fetchPage({
|
|||||||
)
|
)
|
||||||
|
|
||||||
// group notifications which are essentially similar (follows, likes on a post)
|
// group notifications which are essentially similar (follows, likes on a post)
|
||||||
let notifsGrouped = groupNotifications(notifs)
|
const notifsGrouped = groupNotifications(notifs)
|
||||||
|
|
||||||
// we fetch subjects of notifications (usually posts) now instead of lazily
|
// we fetch subjects of notifications (usually posts) now instead of lazily
|
||||||
// in the UI to avoid relayouts
|
// in the UI to avoid relayouts
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ export function usePostFeedQuery(
|
|||||||
|
|
||||||
// Keep track of the last run and whether we can reuse
|
// Keep track of the last run and whether we can reuse
|
||||||
// some already selected pages from there.
|
// some already selected pages from there.
|
||||||
let reusedPages = []
|
const reusedPages = []
|
||||||
if (lastRun.current) {
|
if (lastRun.current) {
|
||||||
const {
|
const {
|
||||||
data: lastData,
|
data: lastData,
|
||||||
@@ -252,8 +252,8 @@ export function usePostFeedQuery(
|
|||||||
result: lastResult,
|
result: lastResult,
|
||||||
} = lastRun.current
|
} = lastRun.current
|
||||||
let canReuse = true
|
let canReuse = true
|
||||||
for (let key in selectArgs) {
|
for (const key in selectArgs) {
|
||||||
if (selectArgs.hasOwnProperty(key)) {
|
if (Object.hasOwn(selectArgs, key)) {
|
||||||
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
||||||
// Can't do reuse anything if any input has changed.
|
// Can't do reuse anything if any input has changed.
|
||||||
canReuse = false
|
canReuse = false
|
||||||
@@ -510,7 +510,7 @@ export function* findAllPostsInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.feed) {
|
for (const item of page.feed) {
|
||||||
if (didOrHandleUriMatches(atUri, item.post)) {
|
if (didOrHandleUriMatches(atUri, item.post)) {
|
||||||
yield item.post
|
yield item.post
|
||||||
@@ -563,7 +563,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.feed) {
|
for (const item of page.feed) {
|
||||||
if (item.post.author.did === did) {
|
if (item.post.author.did === did) {
|
||||||
yield item.post.author
|
yield item.post.author
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const like of page.likes) {
|
for (const like of page.likes) {
|
||||||
if (like.actor.did === did) {
|
if (like.actor.did === did) {
|
||||||
yield like.actor
|
yield like.actor
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const item of page.posts) {
|
for (const item of page.posts) {
|
||||||
if (item.author.did === did) {
|
if (item.author.did === did) {
|
||||||
yield item.author
|
yield item.author
|
||||||
@@ -108,7 +108,7 @@ export function* findAllPostsInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const post of page.posts) {
|
for (const post of page.posts) {
|
||||||
if (didOrHandleUriMatches(atUri, post)) {
|
if (didOrHandleUriMatches(atUri, post)) {
|
||||||
yield post
|
yield post
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const repostedBy of page.repostedBy) {
|
for (const repostedBy of page.repostedBy) {
|
||||||
if (repostedBy.did === did) {
|
if (repostedBy.did === did) {
|
||||||
yield repostedBy
|
yield repostedBy
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const follower of page.followers) {
|
for (const follower of page.followers) {
|
||||||
if (follower.did === did) {
|
if (follower.did === did) {
|
||||||
yield follower
|
yield follower
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const follow of page.follows) {
|
for (const follow of page.follows) {
|
||||||
if (follow.did === did) {
|
if (follow.did === did) {
|
||||||
yield follow
|
yield follow
|
||||||
|
|||||||
@@ -621,7 +621,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData) {
|
if (!queryData) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (let profile of queryData.profiles) {
|
for (const profile of queryData.profiles) {
|
||||||
if (profile.did === did) {
|
if (profile.did === did) {
|
||||||
yield profile
|
yield profile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export function useSearchPostsQuery({
|
|||||||
|
|
||||||
// Keep track of the last run and whether we can reuse
|
// Keep track of the last run and whether we can reuse
|
||||||
// some already selected pages from there.
|
// some already selected pages from there.
|
||||||
let reusedPages = []
|
const reusedPages = []
|
||||||
if (lastRun.current) {
|
if (lastRun.current) {
|
||||||
const {
|
const {
|
||||||
data: lastData,
|
data: lastData,
|
||||||
@@ -95,8 +95,8 @@ export function useSearchPostsQuery({
|
|||||||
result: lastResult,
|
result: lastResult,
|
||||||
} = lastRun.current
|
} = lastRun.current
|
||||||
let canReuse = true
|
let canReuse = true
|
||||||
for (let key in selectArgs) {
|
for (const key in selectArgs) {
|
||||||
if (selectArgs.hasOwnProperty(key)) {
|
if (Object.hasOwn(selectArgs, key)) {
|
||||||
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
if ((selectArgs as any)[key] !== (lastArgs as any)[key]) {
|
||||||
// Can't do reuse anything if any input has changed.
|
// Can't do reuse anything if any input has changed.
|
||||||
canReuse = false
|
canReuse = false
|
||||||
@@ -156,7 +156,7 @@ export function* findAllPostsInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const post of page.posts) {
|
for (const post of page.posts) {
|
||||||
if (didOrHandleUriMatches(atUri, post)) {
|
if (didOrHandleUriMatches(atUri, post)) {
|
||||||
yield post
|
yield post
|
||||||
@@ -184,7 +184,7 @@ export function* findAllProfilesInQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const post of page.posts) {
|
for (const post of page.posts) {
|
||||||
if (post.author.did === did) {
|
if (post.author.did === did) {
|
||||||
yield post.author
|
yield post.author
|
||||||
|
|||||||
@@ -119,8 +119,7 @@ export function useCreateStarterPackMutation({
|
|||||||
descriptionFacets = rt.facets
|
descriptionFacets = rt.facets
|
||||||
}
|
}
|
||||||
|
|
||||||
let listRes
|
const listRes = await createStarterPackList({
|
||||||
listRes = await createStarterPackList({
|
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
profiles,
|
profiles,
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ function* findAllProfilesInSuggestedFollowsQueryData(
|
|||||||
if (!queryData?.pages) {
|
if (!queryData?.pages) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (const page of queryData?.pages) {
|
for (const page of queryData.pages) {
|
||||||
for (const actor of page.actors) {
|
for (const actor of page.actors) {
|
||||||
if (actor.did === did) {
|
if (actor.did === did) {
|
||||||
yield actor
|
yield actor
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export function threadgateAllowUISettingToAllowRecordValue(
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
let allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
|
const allow: Exclude<AppBskyFeedThreadgate.Record['allow'], undefined> = []
|
||||||
|
|
||||||
if (!threadgate.find(v => v.type === 'nobody')) {
|
if (!threadgate.find(v => v.type === 'nobody')) {
|
||||||
for (const rule of threadgate) {
|
for (const rule of threadgate) {
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export function getThreadPlaceholder(
|
|||||||
uri: string,
|
uri: string,
|
||||||
): $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItem> | void {
|
): $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItem> | void {
|
||||||
let partial
|
let partial
|
||||||
for (let item of getThreadPlaceholderCandidates(queryClient, uri)) {
|
for (const item of getThreadPlaceholderCandidates(queryClient, uri)) {
|
||||||
/*
|
/*
|
||||||
* Currently, the backend doesn't send full post info in some cases (for
|
* Currently, the backend doesn't send full post info in some cases (for
|
||||||
* example, for quoted posts). We use missing `likeCount` as a way to
|
* example, for quoted posts). We use missing `likeCount` as a way to
|
||||||
@@ -246,19 +246,19 @@ export function* getThreadPlaceholderCandidates(
|
|||||||
* with >0 likes/reposts over a stale version with no metrics in order to
|
* with >0 likes/reposts over a stale version with no metrics in order to
|
||||||
* avoid a notification->post scroll jump.
|
* avoid a notification->post scroll jump.
|
||||||
*/
|
*/
|
||||||
for (let post of findAllPostsInNotifsQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInNotifsQueryData(queryClient, uri)) {
|
||||||
yield postViewToThreadPlaceholder(post)
|
yield postViewToThreadPlaceholder(post)
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInFeedQueryData(queryClient, uri)) {
|
||||||
yield postViewToThreadPlaceholder(post)
|
yield postViewToThreadPlaceholder(post)
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInQuoteQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInQuoteQueryData(queryClient, uri)) {
|
||||||
yield postViewToThreadPlaceholder(post)
|
yield postViewToThreadPlaceholder(post)
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInSearchQueryData(queryClient, uri)) {
|
for (const post of findAllPostsInSearchQueryData(queryClient, uri)) {
|
||||||
yield postViewToThreadPlaceholder(post)
|
yield postViewToThreadPlaceholder(post)
|
||||||
}
|
}
|
||||||
for (let post of findAllPostsInExploreFeedPreviewsQueryData(
|
for (const post of findAllPostsInExploreFeedPreviewsQueryData(
|
||||||
queryClient,
|
queryClient,
|
||||||
uri,
|
uri,
|
||||||
)) {
|
)) {
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ export type ThreadItem =
|
|||||||
* total number of replies, the reply index, etc.
|
* total number of replies, the reply index, etc.
|
||||||
*
|
*
|
||||||
* The idea here is that these values should be objectively true in all cases,
|
* The idea here is that these values should be objectively true in all cases,
|
||||||
* such that we can use them later — either individually on in composite — to
|
* such that we can use them later — either individually on in composite — to
|
||||||
* drive rendering behaviors.
|
* drive rendering behaviors.
|
||||||
*/
|
*/
|
||||||
export type TraversalMetadata = {
|
export type TraversalMetadata = {
|
||||||
|
|||||||
@@ -1673,7 +1673,7 @@ describe('session', () => {
|
|||||||
|
|
||||||
function run(initialState: State, actions: Action[]): State {
|
function run(initialState: State, actions: Action[]): State {
|
||||||
let state = initialState
|
let state = initialState
|
||||||
for (let action of actions) {
|
for (const action of actions) {
|
||||||
state = reducer(state, action)
|
state = reducer(state, action)
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ export class Agent extends BaseAgent {
|
|||||||
// WARN: In the factories above, we _manually set a proxy header_ for the agent after we do whatever it is we are supposed to do.
|
// WARN: In the factories above, we _manually set a proxy header_ for the agent after we do whatever it is we are supposed to do.
|
||||||
// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it
|
// Ideally, we wouldn't be doing this. However, since there is so much logic that requires making calls to the PDS right now, it
|
||||||
// feels safer to just let those run as-is and set the header afterward.
|
// feels safer to just let those run as-is and set the header afterward.
|
||||||
let realFetch = globalThis.fetch
|
const realFetch = globalThis.fetch
|
||||||
class BskyAppAgent extends BskyAgent {
|
class BskyAppAgent extends BskyAgent {
|
||||||
persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined =
|
persistSessionHandler: ((event: AtpSessionEvent) => void) | undefined =
|
||||||
undefined
|
undefined
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ export function addSessionDebugLog(log: Log) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let agentIds = new WeakMap<object, string>()
|
const agentIds = new WeakMap<object, string>()
|
||||||
let realmId = Math.random().toString(36).slice(2)
|
const realmId = Math.random().toString(36).slice(2)
|
||||||
let nextAgentId = 1
|
let nextAgentId = 1
|
||||||
|
|
||||||
function getAgentId(agent: object) {
|
function getAgentId(agent: object) {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const closeComposer = useNonReactiveCallback(() => {
|
const closeComposer = useNonReactiveCallback(() => {
|
||||||
let wasOpen = !!state
|
const wasOpen = !!state
|
||||||
if (wasOpen) {
|
if (wasOpen) {
|
||||||
setState(undefined)
|
setState(undefined)
|
||||||
purgeTemporaryImageFiles()
|
purgeTemporaryImageFiles()
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
try {
|
try {
|
||||||
sessionStorage.setItem('lastSelectedHomeFeed', feed)
|
sessionStorage.setItem('lastSelectedHomeFeed', feed)
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
persisted.write('lastSelectedHomeFeed', feed)
|
persisted.write('lastSelectedHomeFeed', feed)
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const consumedSources = new Map<string, PostSource>()
|
|||||||
export function setUnstablePostSource(key: string, source: PostSource) {
|
export function setUnstablePostSource(key: string, source: PostSource) {
|
||||||
assertValidDevOnly(
|
assertValidDevOnly(
|
||||||
key,
|
key,
|
||||||
`setUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
`setUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
||||||
)
|
)
|
||||||
logger.debug('set', {key, source})
|
logger.debug('set', {key, source})
|
||||||
transientSources.set(key, source)
|
transientSources.set(key, source)
|
||||||
@@ -53,7 +53,7 @@ export function useUnstablePostSource(key: string) {
|
|||||||
const [source] = useState(() => {
|
const [source] = useState(() => {
|
||||||
assertValidDevOnly(
|
assertValidDevOnly(
|
||||||
key,
|
key,
|
||||||
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} — be sure to use buildPostSourceKey when setting the source`,
|
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} — be sure to use buildPostSourceKey when setting the source`,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
const source = consumedSources.get(id) || transientSources.get(key)
|
const source = consumedSources.get(id) || transientSources.get(key)
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ export const ComposePost = ({
|
|||||||
} finally {
|
} finally {
|
||||||
if (postUri) {
|
if (postUri) {
|
||||||
let index = 0
|
let index = 0
|
||||||
for (let post of thread.posts) {
|
for (const post of thread.posts) {
|
||||||
logEvent('post:create', {
|
logEvent('post:create', {
|
||||||
imageCount:
|
imageCount:
|
||||||
post.embed.media?.type === 'images'
|
post.embed.media?.type === 'images'
|
||||||
@@ -619,7 +619,7 @@ export const ComposePost = ({
|
|||||||
if (publishOnUpload) {
|
if (publishOnUpload) {
|
||||||
let erroredVideos = 0
|
let erroredVideos = 0
|
||||||
let uploadingVideos = 0
|
let uploadingVideos = 0
|
||||||
for (let post of thread.posts) {
|
for (const post of thread.posts) {
|
||||||
if (post.embed.media?.type === 'video') {
|
if (post.embed.media?.type === 'video') {
|
||||||
const video = post.embed.media.video
|
const video = post.embed.media.video
|
||||||
if (video.status === 'error') {
|
if (video.status === 'error') {
|
||||||
@@ -812,7 +812,7 @@ export const ComposePost = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let ComposerPost = React.memo(function ComposerPost({
|
const ComposerPost = React.memo(function ComposerPost({
|
||||||
post,
|
post,
|
||||||
dispatch,
|
dispatch,
|
||||||
textInput,
|
textInput,
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ export function SelectMediaButton({
|
|||||||
msg`You can only select one GIF at a time.`,
|
msg`You can only select one GIF at a time.`,
|
||||||
),
|
),
|
||||||
[SelectedAssetError.FileTooBig]: _(
|
[SelectedAssetError.FileTooBig]: _(
|
||||||
msg`One or more of your selected files are too large. Maximum size is 100 MB.`,
|
msg`One or more of your selected files are too large. Maximum size is 100 MB.`,
|
||||||
),
|
),
|
||||||
}[error]
|
}[error]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export function composerReducer(
|
|||||||
const indexToRemove = state.thread.posts.findIndex(
|
const indexToRemove = state.thread.posts.findIndex(
|
||||||
p => p.id === action.postId,
|
p => p.id === action.postId,
|
||||||
)
|
)
|
||||||
let nextPosts = [...state.thread.posts]
|
const nextPosts = [...state.thread.posts]
|
||||||
if (indexToRemove !== -1) {
|
if (indexToRemove !== -1) {
|
||||||
const postToRemove = state.thread.posts[indexToRemove]
|
const postToRemove = state.thread.posts[indexToRemove]
|
||||||
if (postToRemove.embed.media?.type === 'video') {
|
if (postToRemove.embed.media?.type === 'video') {
|
||||||
|
|||||||
@@ -392,7 +392,7 @@ function getCompressErrorMessage(e: unknown, _: I18n['_']): string | null {
|
|||||||
}
|
}
|
||||||
if (e instanceof VideoTooLargeError) {
|
if (e instanceof VideoTooLargeError) {
|
||||||
return _(
|
return _(
|
||||||
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
|
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
logger.error('Error compressing video', {safeMessage: e})
|
logger.error('Error compressing video', {safeMessage: e})
|
||||||
@@ -431,7 +431,7 @@ function getUploadErrorMessage(e: unknown, _: I18n['_']): string | null {
|
|||||||
)
|
)
|
||||||
case 'file size (100000001 bytes) is larger than the maximum allowed size (100000000 bytes)':
|
case 'file size (100000001 bytes) is larger than the maximum allowed size (100000000 bytes)':
|
||||||
return _(
|
return _(
|
||||||
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
|
msg`The selected video is larger than 100 MB. Please try again with a smaller file.`,
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return e.message
|
return e.message
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ function iterateUris(str: string, cb: (from: number, to: number) => void) {
|
|||||||
}
|
}
|
||||||
uri = `https://${uri}`
|
uri = `https://${uri}`
|
||||||
}
|
}
|
||||||
let from = str.indexOf(match[2], match.index)
|
const from = str.indexOf(match[2], match.index)
|
||||||
let to = from + match[2].length
|
let to = from + match[2].length
|
||||||
// strip ending puncuation
|
// strip ending puncuation
|
||||||
if (/[.,;!?]$/.test(uri)) {
|
if (/[.,;!?]$/.test(uri)) {
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export function useWebPreloadEmoji({immediate}: {immediate?: boolean} = {}) {
|
|||||||
try {
|
try {
|
||||||
const data = (await import('./EmojiPickerData.json')).default
|
const data = (await import('./EmojiPickerData.json')).default
|
||||||
init({data})
|
init({data})
|
||||||
} catch (e) {}
|
} catch (e) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
if (immediate) preload()
|
if (immediate) preload()
|
||||||
return preload
|
return preload
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export function ProfileFeedgens({
|
|||||||
} else if (isEmpty) {
|
} else if (isEmpty) {
|
||||||
items = items.concat([EMPTY])
|
items = items.concat([EMPTY])
|
||||||
} else if (data?.pages) {
|
} else if (data?.pages) {
|
||||||
for (const page of data?.pages) {
|
for (const page of data.pages) {
|
||||||
items = items.concat(page.feeds)
|
items = items.concat(page.feeds)
|
||||||
}
|
}
|
||||||
} else if (isError && !isEmpty) {
|
} else if (isError && !isEmpty) {
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ const ImageItem = ({
|
|||||||
.onEnd(() => {
|
.onEnd(() => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Commit just the pinch.
|
// Commit just the pinch.
|
||||||
let t = createTransform()
|
const t = createTransform()
|
||||||
prependPinch(
|
prependPinch(
|
||||||
t,
|
t,
|
||||||
pinchScale.get(),
|
pinchScale.get(),
|
||||||
@@ -220,7 +220,7 @@ const ImageItem = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nextPanTranslation = {x: e.translationX, y: e.translationY}
|
const nextPanTranslation = {x: e.translationX, y: e.translationY}
|
||||||
let t = createTransform()
|
const t = createTransform()
|
||||||
prependPan(t, nextPanTranslation)
|
prependPan(t, nextPanTranslation)
|
||||||
prependPinch(
|
prependPinch(
|
||||||
t,
|
t,
|
||||||
@@ -239,7 +239,7 @@ const ImageItem = ({
|
|||||||
.onEnd(() => {
|
.onEnd(() => {
|
||||||
'worklet'
|
'worklet'
|
||||||
// Commit just the pan.
|
// Commit just the pan.
|
||||||
let t = createTransform()
|
const t = createTransform()
|
||||||
prependPan(t, panTranslation.get())
|
prependPan(t, panTranslation.get())
|
||||||
prependTransform(t, committedTransform.get())
|
prependTransform(t, committedTransform.get())
|
||||||
applyRounding(t)
|
applyRounding(t)
|
||||||
@@ -265,7 +265,7 @@ const ImageItem = ({
|
|||||||
const [, , committedScale] = readTransform(committedTransform.get())
|
const [, , committedScale] = readTransform(committedTransform.get())
|
||||||
if (committedScale !== 1) {
|
if (committedScale !== 1) {
|
||||||
// Go back to 1:1 using the identity vector.
|
// Go back to 1:1 using the identity vector.
|
||||||
let t = createTransform()
|
const t = createTransform()
|
||||||
committedTransform.set(withClampedSpring(t))
|
committedTransform.set(withClampedSpring(t))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -317,7 +317,7 @@ const ImageItem = ({
|
|||||||
const {scaleAndMoveTransform, isHidden} = transforms.get()
|
const {scaleAndMoveTransform, isHidden} = transforms.get()
|
||||||
// Apply the active adjustments on top of the committed transform before the gestures.
|
// Apply the active adjustments on top of the committed transform before the gestures.
|
||||||
// This is matrix multiplication, so operations are applied in the reverse order.
|
// This is matrix multiplication, so operations are applied in the reverse order.
|
||||||
let t = createTransform()
|
const t = createTransform()
|
||||||
prependPan(t, panTranslation.get())
|
prependPan(t, panTranslation.get())
|
||||||
prependPinch(t, pinchScale.get(), pinchOrigin.get(), pinchTranslation.get())
|
prependPinch(t, pinchScale.get(), pinchOrigin.get(), pinchTranslation.get())
|
||||||
prependTransform(t, committedTransform.get())
|
prependTransform(t, committedTransform.get())
|
||||||
|
|||||||
@@ -308,8 +308,8 @@ const getZoomRectAfterDoubleTap = (
|
|||||||
|
|
||||||
// Next, we'll be calculating the rectangle to "zoom into" in screen coordinates.
|
// Next, we'll be calculating the rectangle to "zoom into" in screen coordinates.
|
||||||
// We already know the zoom level, so this gives us the rectangle size.
|
// We already know the zoom level, so this gives us the rectangle size.
|
||||||
let rectWidth = screenSize.width / zoom
|
const rectWidth = screenSize.width / zoom
|
||||||
let rectHeight = screenSize.height / zoom
|
const rectHeight = screenSize.height / zoom
|
||||||
|
|
||||||
// Before we settle on the zoomed rect, figure out the safe area it has to be inside.
|
// Before we settle on the zoomed rect, figure out the safe area it has to be inside.
|
||||||
// We don't want to introduce new black bars or make existing black bars unbalanced.
|
// We don't want to introduce new black bars or make existing black bars unbalanced.
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export function ProfileLists({
|
|||||||
} else if (isEmpty) {
|
} else if (isEmpty) {
|
||||||
items = items.concat([EMPTY])
|
items = items.concat([EMPTY])
|
||||||
} else if (data?.pages) {
|
} else if (data?.pages) {
|
||||||
for (const page of data?.pages) {
|
for (const page of data.pages) {
|
||||||
items = items.concat(page.lists)
|
items = items.concat(page.lists)
|
||||||
}
|
}
|
||||||
} else if (isError && !isEmpty) {
|
} else if (isError && !isEmpty) {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export function NotificationFeed({
|
|||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
arr = arr.concat([EMPTY_FEED_ITEM])
|
arr = arr.concat([EMPTY_FEED_ITEM])
|
||||||
} else if (data) {
|
} else if (data) {
|
||||||
for (const page of data?.pages) {
|
for (const page of data.pages) {
|
||||||
arr = arr.concat(page.items)
|
arr = arr.concat(page.items)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export function Pager({
|
|||||||
// case we should preserve and restore scroll), or if it is somewhere below in the
|
// case we should preserve and restore scroll), or if it is somewhere below in the
|
||||||
// viewport (in which case a scroll jump would be jarring). We determine this by
|
// viewport (in which case a scroll jump would be jarring). We determine this by
|
||||||
// measuring where the "anchor" element is (which we place just above the tabbar).
|
// measuring where the "anchor" element is (which we place just above the tabbar).
|
||||||
let anchorTop = anchorRef.current
|
const anchorTop = anchorRef.current
|
||||||
? (anchorRef.current as Element).getBoundingClientRect().top
|
? (anchorRef.current as Element).getBoundingClientRect().top
|
||||||
: -scrollY // If there's no anchor, treat the top of the page as one.
|
: -scrollY // If there's no anchor, treat the top of the page as one.
|
||||||
const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
|
const isSticking = anchorTop <= 5 // This would be 0 if browser scrollTo() was reliable.
|
||||||
|
|||||||
@@ -333,14 +333,14 @@ let PostFeed = ({
|
|||||||
}, [enabled, isEmpty, disablePoll, checkForNew])
|
}, [enabled, isEmpty, disablePoll, checkForNew])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cleanup1: () => void | undefined, cleanup2: () => void | undefined
|
|
||||||
const subscription = AppState.addEventListener('change', nextAppState => {
|
const subscription = AppState.addEventListener('change', nextAppState => {
|
||||||
// check for new on app foreground
|
// check for new on app foreground
|
||||||
if (nextAppState === 'active') {
|
if (nextAppState === 'active') {
|
||||||
checkForNew()
|
checkForNew()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
cleanup1 = () => subscription.remove()
|
const cleanup1 = () => subscription.remove()
|
||||||
|
let cleanup2: (() => void) | undefined
|
||||||
if (pollInterval) {
|
if (pollInterval) {
|
||||||
// check for new on interval
|
// check for new on interval
|
||||||
const i = setInterval(() => {
|
const i = setInterval(() => {
|
||||||
@@ -349,7 +349,7 @@ let PostFeed = ({
|
|||||||
cleanup2 = () => clearInterval(i)
|
cleanup2 = () => clearInterval(i)
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
cleanup1?.()
|
cleanup1()
|
||||||
cleanup2?.()
|
cleanup2?.()
|
||||||
}
|
}
|
||||||
}, [pollInterval, checkForNew])
|
}, [pollInterval, checkForNew])
|
||||||
@@ -402,7 +402,7 @@ let PostFeed = ({
|
|||||||
feedKind = 'profile'
|
feedKind = 'profile'
|
||||||
}
|
}
|
||||||
|
|
||||||
let arr: FeedRow[] = []
|
const arr: FeedRow[] = []
|
||||||
if (KNOWN_SHUTDOWN_FEEDS.includes(feedUriOrActorDid)) {
|
if (KNOWN_SHUTDOWN_FEEDS.includes(feedUriOrActorDid)) {
|
||||||
arr.push({
|
arr.push({
|
||||||
type: 'feedShutdownMsg',
|
type: 'feedShutdownMsg',
|
||||||
@@ -481,7 +481,7 @@ let PostFeed = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const page of data?.pages) {
|
for (const page of data.pages) {
|
||||||
for (const slice of page.slices) {
|
for (const slice of page.slices) {
|
||||||
sliceIndex++
|
sliceIndex++
|
||||||
|
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ function useResizeObserver(
|
|||||||
}
|
}
|
||||||
const resizeObserver = new ResizeObserver(entries => {
|
const resizeObserver = new ResizeObserver(entries => {
|
||||||
batchedUpdates(() => {
|
batchedUpdates(() => {
|
||||||
for (let entry of entries) {
|
for (const entry of entries) {
|
||||||
const rect = entry.contentRect
|
const rect = entry.contentRect
|
||||||
handleResize(rect.width, rect.height)
|
handleResize(rect.width, rect.height)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,14 +179,18 @@ const emitter = new EventEmitter()
|
|||||||
|
|
||||||
if (isWeb) {
|
if (isWeb) {
|
||||||
const originalScroll = window.scroll
|
const originalScroll = window.scroll
|
||||||
|
|
||||||
window.scroll = function () {
|
window.scroll = function () {
|
||||||
emitter.emit('forced-scroll')
|
emitter.emit('forced-scroll')
|
||||||
|
// eslint-disable-next-line prefer-rest-params
|
||||||
return originalScroll.apply(this, arguments as any)
|
return originalScroll.apply(this, arguments as any)
|
||||||
}
|
}
|
||||||
|
|
||||||
const originalScrollTo = window.scrollTo
|
const originalScrollTo = window.scrollTo
|
||||||
|
|
||||||
window.scrollTo = function () {
|
window.scrollTo = function () {
|
||||||
emitter.emit('forced-scroll')
|
emitter.emit('forced-scroll')
|
||||||
|
// eslint-disable-next-line prefer-rest-params
|
||||||
return originalScrollTo.apply(this, arguments as any)
|
return originalScrollTo.apply(this, arguments as any)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,9 +153,13 @@ export function Button({
|
|||||||
async (event: GestureResponderEvent) => {
|
async (event: GestureResponderEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
withLoading && setIsLoading(true)
|
if (withLoading) {
|
||||||
|
setIsLoading(true)
|
||||||
|
}
|
||||||
await onPress?.(event)
|
await onPress?.(event)
|
||||||
withLoading && setIsLoading(false)
|
if (withLoading) {
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[onPress, withLoading],
|
[onPress, withLoading],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ export function ListsScreen({}: Props) {
|
|||||||
name: urip.hostname,
|
name: urip.hostname,
|
||||||
rkey: urip.rkey,
|
rkey: urip.rkey,
|
||||||
})
|
})
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[navigation],
|
[navigation],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ export function ModerationModlistsScreen({}: Props) {
|
|||||||
name: urip.hostname,
|
name: urip.hostname,
|
||||||
rkey: urip.rkey,
|
rkey: urip.rkey,
|
||||||
})
|
})
|
||||||
} catch {}
|
} catch {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[navigation],
|
[navigation],
|
||||||
)
|
)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user