Move actor-status into liveNow
This commit is contained in:
@@ -4,7 +4,6 @@ import {type AppBskyActorDefs} from '@atproto/api'
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {isJwtExpired} from '#/lib/jwt'
|
import {isJwtExpired} from '#/lib/jwt'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
@@ -19,6 +18,7 @@ import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
|
|
||||||
export function AccountList({
|
export function AccountList({
|
||||||
onSelectAccount,
|
onSelectAccount,
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {getModerationCauseKey} from '#/lib/moderation'
|
import {getModerationCauseKey} from '#/lib/moderation'
|
||||||
import {forceLTR} from '#/lib/strings/bidi'
|
import {forceLTR} from '#/lib/strings/bidi'
|
||||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||||
@@ -47,6 +46,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
import {type Metrics} from '#/analytics'
|
import {type Metrics} from '#/analytics'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function Default({
|
export function Default({
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {msg, plural} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {getModerationCauseKey} from '#/lib/moderation'
|
import {getModerationCauseKey} from '#/lib/moderation'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
@@ -43,6 +42,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
import {IS_WEB_TOUCH_DEVICE} from '#/env'
|
import {IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {type ProfileHoverCardProps} from './types'
|
import {type ProfileHoverCardProps} from './types'
|
||||||
|
|
||||||
const floatingMiddlewares = [
|
const floatingMiddlewares = [
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo} from 'react'
|
||||||
|
import {
|
||||||
|
type $Typed,
|
||||||
|
type AppBskyActorDefs,
|
||||||
|
AppBskyEmbedExternal,
|
||||||
|
AtUri,
|
||||||
|
} from '@atproto/api'
|
||||||
|
import {isAfter, parseISO} from 'date-fns'
|
||||||
|
|
||||||
import {useAppConfig} from '#/state/appConfig'
|
import {useAppConfig} from '#/state/appConfig'
|
||||||
|
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
import {useTickEveryMinute} from '#/state/shell'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export const DEFAULT_ALLOWED_DOMAINS = [
|
export const DEFAULT_ALLOWED_DOMAINS = [
|
||||||
'twitch.tv',
|
'twitch.tv',
|
||||||
@@ -59,3 +69,82 @@ export function useLiveNowConfig(): LiveNowConfig {
|
|||||||
}
|
}
|
||||||
}, [ax, liveNow, currentAccount])
|
}, [ax, liveNow, currentAccount])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
||||||
|
const shadowed = useMaybeProfileShadow(actor)
|
||||||
|
const tick = useTickEveryMinute()
|
||||||
|
const config = useLiveNowConfig()
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
void tick // revalidate every minute
|
||||||
|
|
||||||
|
if (shadowed && 'status' in shadowed && shadowed.status) {
|
||||||
|
const isValid = isStatusValidForViewers(shadowed.status, config)
|
||||||
|
const isDisabled = shadowed.status.isDisabled || false
|
||||||
|
const isActive = isStatusStillActive(shadowed.status.expiresAt)
|
||||||
|
if (isValid && !isDisabled && isActive) {
|
||||||
|
return {
|
||||||
|
uri: shadowed.status.uri,
|
||||||
|
cid: shadowed.status.cid,
|
||||||
|
isDisabled: false,
|
||||||
|
isActive: true,
|
||||||
|
status: 'app.bsky.actor.status#live',
|
||||||
|
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
||||||
|
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
||||||
|
record: shadowed.status.record,
|
||||||
|
} satisfies AppBskyActorDefs.StatusView
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
uri: shadowed.status.uri,
|
||||||
|
cid: shadowed.status.cid,
|
||||||
|
isDisabled,
|
||||||
|
isActive: false,
|
||||||
|
status: 'app.bsky.actor.status#live',
|
||||||
|
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
||||||
|
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
||||||
|
record: shadowed.status.record,
|
||||||
|
} satisfies AppBskyActorDefs.StatusView
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
status: '',
|
||||||
|
isDisabled: false,
|
||||||
|
isActive: false,
|
||||||
|
record: {},
|
||||||
|
} satisfies AppBskyActorDefs.StatusView
|
||||||
|
}
|
||||||
|
}, [shadowed, config, tick])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStatusStillActive(timeStr: string | undefined) {
|
||||||
|
if (!timeStr) return false
|
||||||
|
const now = new Date()
|
||||||
|
const expiry = parseISO(timeStr)
|
||||||
|
|
||||||
|
return isAfter(expiry, now)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates whether the live status is valid for display in the app. Does NOT
|
||||||
|
* validate if the status is valid for the acting user e.g. as they go live.
|
||||||
|
*/
|
||||||
|
export function isStatusValidForViewers(
|
||||||
|
status: AppBskyActorDefs.StatusView,
|
||||||
|
config: LiveNowConfig,
|
||||||
|
) {
|
||||||
|
if (status.status !== 'app.bsky.actor.status#live') return false
|
||||||
|
if (!status.uri) return false // should not happen, just backwards compat
|
||||||
|
try {
|
||||||
|
const {host: liveDid} = new AtUri(status.uri)
|
||||||
|
if (AppBskyEmbedExternal.isView(status.embed)) {
|
||||||
|
const url = new URL(status.embed.external.uri)
|
||||||
|
const exception = config.allowedHostsExceptionsByDid.get(liveDid)
|
||||||
|
const isValidException = exception ? exception.has(url.hostname) : false
|
||||||
|
const isValidForAnyone = config.defaultAllowedHosts.has(url.hostname)
|
||||||
|
return isValidException || isValidForAnyone
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
import {useMemo} from 'react'
|
|
||||||
import {
|
|
||||||
type $Typed,
|
|
||||||
type AppBskyActorDefs,
|
|
||||||
AppBskyEmbedExternal,
|
|
||||||
AtUri,
|
|
||||||
} from '@atproto/api'
|
|
||||||
import {isAfter, parseISO} from 'date-fns'
|
|
||||||
|
|
||||||
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
|
||||||
import {useTickEveryMinute} from '#/state/shell'
|
|
||||||
import {type LiveNowConfig, useLiveNowConfig} from '#/features/liveNow'
|
|
||||||
import type * as bsky from '#/types/bsky'
|
|
||||||
|
|
||||||
export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
|
||||||
const shadowed = useMaybeProfileShadow(actor)
|
|
||||||
const tick = useTickEveryMinute()
|
|
||||||
const config = useLiveNowConfig()
|
|
||||||
|
|
||||||
return useMemo(() => {
|
|
||||||
void tick // revalidate every minute
|
|
||||||
|
|
||||||
if (shadowed && 'status' in shadowed && shadowed.status) {
|
|
||||||
const isValid = isStatusValidForViewers(shadowed.status, config)
|
|
||||||
const isDisabled = shadowed.status.isDisabled || false
|
|
||||||
const isActive = isStatusStillActive(shadowed.status.expiresAt)
|
|
||||||
if (isValid && !isDisabled && isActive) {
|
|
||||||
return {
|
|
||||||
uri: shadowed.status.uri,
|
|
||||||
cid: shadowed.status.cid,
|
|
||||||
isDisabled: false,
|
|
||||||
isActive: true,
|
|
||||||
status: 'app.bsky.actor.status#live',
|
|
||||||
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
|
||||||
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
|
||||||
record: shadowed.status.record,
|
|
||||||
} satisfies AppBskyActorDefs.StatusView
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
uri: shadowed.status.uri,
|
|
||||||
cid: shadowed.status.cid,
|
|
||||||
isDisabled,
|
|
||||||
isActive: false,
|
|
||||||
status: 'app.bsky.actor.status#live',
|
|
||||||
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
|
||||||
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
|
||||||
record: shadowed.status.record,
|
|
||||||
} satisfies AppBskyActorDefs.StatusView
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
status: '',
|
|
||||||
isDisabled: false,
|
|
||||||
isActive: false,
|
|
||||||
record: {},
|
|
||||||
} satisfies AppBskyActorDefs.StatusView
|
|
||||||
}
|
|
||||||
}, [shadowed, config, tick])
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isStatusStillActive(timeStr: string | undefined) {
|
|
||||||
if (!timeStr) return false
|
|
||||||
const now = new Date()
|
|
||||||
const expiry = parseISO(timeStr)
|
|
||||||
|
|
||||||
return isAfter(expiry, now)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates whether the live status is valid for display in the app. Does NOT
|
|
||||||
* validate if the status is valid for the acting user e.g. as they go live.
|
|
||||||
*/
|
|
||||||
export function isStatusValidForViewers(
|
|
||||||
status: AppBskyActorDefs.StatusView,
|
|
||||||
config: LiveNowConfig,
|
|
||||||
) {
|
|
||||||
if (status.status !== 'app.bsky.actor.status#live') return false
|
|
||||||
if (!status.uri) return false // should not happen, just backwards compat
|
|
||||||
try {
|
|
||||||
const {host: liveDid} = new AtUri(status.uri)
|
|
||||||
if (AppBskyEmbedExternal.isView(status.embed)) {
|
|
||||||
const url = new URL(status.embed.external.uri)
|
|
||||||
const exception = config.allowedHostsExceptionsByDid.get(liveDid)
|
|
||||||
const isValidException = exception ? exception.has(url.hostname) : false
|
|
||||||
const isValidForAnyone = config.defaultAllowedHosts.has(url.hostname)
|
|
||||||
return isValidException || isValidForAnyone
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import {msg, Plural, Trans} from '@lingui/macro'
|
import {msg, Plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {useTranslate} from '#/lib/hooks/useTranslate'
|
import {useTranslate} from '#/lib/hooks/useTranslate'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
@@ -60,6 +59,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||||
import {WhoCanReply} from '#/components/WhoCanReply'
|
import {WhoCanReply} from '#/components/WhoCanReply'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export function ThreadItemAnchor({
|
export function ThreadItemAnchor({
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans} from '@lingui/macro'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {MAX_POST_LINES} from '#/lib/constants'
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
@@ -44,6 +43,7 @@ import {RichText} from '#/components/RichText'
|
|||||||
import * as Skele from '#/components/Skeleton'
|
import * as Skele from '#/components/Skeleton'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
|
|
||||||
export type ThreadItemPostProps = {
|
export type ThreadItemPostProps = {
|
||||||
item: Extract<ThreadItem, {type: 'threadPost'}>
|
item: Extract<ThreadItem, {type: 'threadPost'}>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
@@ -39,6 +38,7 @@ import * as Toast from '#/components/Toast'
|
|||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {GermButton} from '../components/GermButton'
|
import {GermButton} from '../components/GermButton'
|
||||||
import {EditProfileDialog} from './EditProfileDialog'
|
import {EditProfileDialog} from './EditProfileDialog'
|
||||||
import {ProfileHeaderHandle} from './Handle'
|
import {ProfileHeaderHandle} from './Handle'
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {BACK_HITSLOP} from '#/lib/constants'
|
import {BACK_HITSLOP} from '#/lib/constants'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
@@ -35,6 +34,7 @@ import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
|||||||
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS} from '#/env'
|
import {IS_IOS} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {GrowableAvatar} from './GrowableAvatar'
|
import {GrowableAvatar} from './GrowableAvatar'
|
||||||
import {GrowableBanner} from './GrowableBanner'
|
import {GrowableBanner} from './GrowableBanner'
|
||||||
import {StatusBarShadow} from './StatusBarShadow'
|
import {StatusBarShadow} from './StatusBarShadow'
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {HELP_DESK_URL} from '#/lib/constants'
|
import {HELP_DESK_URL} from '#/lib/constants'
|
||||||
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||||
import {useApplyPullRequestOTAUpdate} from '#/lib/hooks/useOTAUpdates'
|
import {useApplyPullRequestOTAUpdate} from '#/lib/hooks/useOTAUpdates'
|
||||||
@@ -70,6 +69,7 @@ import {
|
|||||||
} from '#/components/verification/VerificationCheckButton'
|
} from '#/components/verification/VerificationCheckButton'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_INTERNAL, IS_IOS, IS_NATIVE} from '#/env'
|
import {IS_INTERNAL, IS_IOS, IS_NATIVE} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {device, useStorage} from '#/storage'
|
import {device, useStorage} from '#/storage'
|
||||||
import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged'
|
import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged'
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import {msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {isStatusStillActive, isStatusValidForViewers} from '#/lib/actor-status'
|
|
||||||
import {DISCOVER_FEED_URI, KNOWN_SHUTDOWN_FEEDS} from '#/lib/constants'
|
import {DISCOVER_FEED_URI, KNOWN_SHUTDOWN_FEEDS} from '#/lib/constants'
|
||||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||||
@@ -70,7 +69,11 @@ import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interst
|
|||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
||||||
import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner'
|
import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner'
|
||||||
import {useLiveNowConfig} from '#/features/liveNow'
|
import {
|
||||||
|
isStatusStillActive,
|
||||||
|
isStatusValidForViewers,
|
||||||
|
useLiveNowConfig,
|
||||||
|
} from '#/features/liveNow'
|
||||||
import {ComposerPrompt} from '../feeds/ComposerPrompt'
|
import {ComposerPrompt} from '../feeds/ComposerPrompt'
|
||||||
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
|
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
|
||||||
import {FeedShutdownMsg} from './FeedShutdownMsg'
|
import {FeedShutdownMsg} from './FeedShutdownMsg'
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {type ReasonFeedSource} from '#/lib/api/feed/types'
|
import {type ReasonFeedSource} from '#/lib/api/feed/types'
|
||||||
import {MAX_POST_LINES} from '#/lib/constants'
|
import {MAX_POST_LINES} from '#/lib/constants'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
@@ -48,6 +47,7 @@ import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
|||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {SubtleHover} from '#/components/SubtleHover'
|
import {SubtleHover} from '#/components/SubtleHover'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import * as bsky from '#/types/bsky'
|
import * as bsky from '#/types/bsky'
|
||||||
import {PostFeedReason} from './PostFeedReason'
|
import {PostFeedReason} from './PostFeedReason'
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {type NavigationProp} from '#/lib/routes/types'
|
import {type NavigationProp} from '#/lib/routes/types'
|
||||||
@@ -60,7 +59,7 @@ import {VerificationCreatePrompt} from '#/components/verification/VerificationCr
|
|||||||
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
import {useLiveNowConfig} from '#/features/liveNow'
|
import {useActorStatus, useLiveNowConfig} from '#/features/liveNow'
|
||||||
import {Dot} from '#/features/nuxs/components/Dot'
|
import {Dot} from '#/features/nuxs/components/Dot'
|
||||||
import {Gradient} from '#/features/nuxs/components/Gradient'
|
import {Gradient} from '#/features/nuxs/components/Gradient'
|
||||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {forceLTR} from '#/lib/strings/bidi'
|
import {forceLTR} from '#/lib/strings/bidi'
|
||||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||||
@@ -21,6 +20,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
import {IS_ANDROID} from '#/env'
|
import {IS_ANDROID} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {TimeElapsed} from './TimeElapsed'
|
import {TimeElapsed} from './TimeElapsed'
|
||||||
import {PreviewableUserAvatar} from './UserAvatar'
|
import {PreviewableUserAvatar} from './UserAvatar'
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {msg, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
import {
|
import {
|
||||||
useCameraPermission,
|
useCameraPermission,
|
||||||
@@ -54,6 +53,7 @@ import * as Menu from '#/components/Menu'
|
|||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
import {useAnalytics} from '#/analytics'
|
import {useAnalytics} from '#/analytics'
|
||||||
import {IS_ANDROID, IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
import {IS_ANDROID, IS_NATIVE, IS_WEB, IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import type * as bsky from '#/types/bsky'
|
import type * as bsky from '#/types/bsky'
|
||||||
|
|
||||||
export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
|
export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {msg, Plural, plural, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {StackActions, useNavigation} from '@react-navigation/native'
|
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
||||||
import {type PressableScale} from '#/lib/custom-animations/PressableScale'
|
import {type PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||||
import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
|
import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
|
||||||
@@ -57,6 +56,7 @@ import {Text} from '#/components/Typography'
|
|||||||
import {useSimpleVerificationState} from '#/components/verification'
|
import {useSimpleVerificationState} from '#/components/verification'
|
||||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||||
import {IS_WEB} from '#/env'
|
import {IS_WEB} from '#/env'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
|
|
||||||
const iconWidth = 26
|
const iconWidth = 26
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {type BottomTabBarProps} from '@react-navigation/bottom-tabs'
|
import {type BottomTabBarProps} from '@react-navigation/bottom-tabs'
|
||||||
import {StackActions} from '@react-navigation/native'
|
import {StackActions} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||||
import {BOTTOM_BAR_AVI} from '#/lib/demo'
|
import {BOTTOM_BAR_AVI} from '#/lib/demo'
|
||||||
import {useHaptics} from '#/lib/haptics'
|
import {useHaptics} from '#/lib/haptics'
|
||||||
@@ -49,6 +48,7 @@ import {
|
|||||||
Message_Stroke2_Corner0_Rounded_Filled as MessageFilled,
|
Message_Stroke2_Corner0_Rounded_Filled as MessageFilled,
|
||||||
} from '#/components/icons/Message'
|
} from '#/components/icons/Message'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {useDemoMode} from '#/storage/hooks/demo-mode'
|
import {useDemoMode} from '#/storage/hooks/demo-mode'
|
||||||
import {styles} from './BottomBarStyles'
|
import {styles} from './BottomBarStyles'
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {msg, plural, Trans} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation, useNavigationState} from '@react-navigation/native'
|
import {useNavigation, useNavigationState} from '@react-navigation/native'
|
||||||
|
|
||||||
import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
@@ -74,6 +73,7 @@ import {CENTER_COLUMN_OFFSET} from '#/components/Layout'
|
|||||||
import * as Menu from '#/components/Menu'
|
import * as Menu from '#/components/Menu'
|
||||||
import * as Prompt from '#/components/Prompt'
|
import * as Prompt from '#/components/Prompt'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {useActorStatus} from '#/features/liveNow'
|
||||||
import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
|
import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
|
||||||
import {router} from '../../../routes'
|
import {router} from '../../../routes'
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user