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 {useLingui} from '@lingui/react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {isJwtExpired} from '#/lib/jwt'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
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 {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
|
||||
export function AccountList({
|
||||
onSelectAccount,
|
||||
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {getModerationCauseKey} from '#/lib/moderation'
|
||||
import {forceLTR} from '#/lib/strings/bidi'
|
||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||
@@ -47,6 +46,7 @@ import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {type Metrics} from '#/analytics'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function Default({
|
||||
|
||||
@@ -10,7 +10,6 @@ import {msg, plural} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {getModerationCauseKey} from '#/lib/moderation'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
@@ -43,6 +42,7 @@ import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {IS_WEB_TOUCH_DEVICE} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {type ProfileHoverCardProps} from './types'
|
||||
|
||||
const floatingMiddlewares = [
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
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 {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useTickEveryMinute} from '#/state/shell'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export const DEFAULT_ALLOWED_DOMAINS = [
|
||||
'twitch.tv',
|
||||
@@ -59,3 +69,82 @@ export function useLiveNowConfig(): LiveNowConfig {
|
||||
}
|
||||
}, [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 {useLingui} from '@lingui/react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {useTranslate} from '#/lib/hooks/useTranslate'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
@@ -60,6 +59,7 @@ import {Text} from '#/components/Typography'
|
||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||
import {WhoCanReply} from '#/components/WhoCanReply'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
export function ThreadItemAnchor({
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {MAX_POST_LINES} from '#/lib/constants'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
@@ -44,6 +43,7 @@ import {RichText} from '#/components/RichText'
|
||||
import * as Skele from '#/components/Skeleton'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
|
||||
export type ThreadItemPostProps = {
|
||||
item: Extract<ThreadItem, {type: 'threadPost'}>
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
@@ -39,6 +38,7 @@ import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {GermButton} from '../components/GermButton'
|
||||
import {EditProfileDialog} from './EditProfileDialog'
|
||||
import {ProfileHeaderHandle} from './Handle'
|
||||
|
||||
@@ -14,7 +14,6 @@ import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {BACK_HITSLOP} from '#/lib/constants'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
@@ -35,6 +34,7 @@ import {LabelsOnMe} from '#/components/moderation/LabelsOnMe'
|
||||
import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {GrowableAvatar} from './GrowableAvatar'
|
||||
import {GrowableBanner} from './GrowableBanner'
|
||||
import {StatusBarShadow} from './StatusBarShadow'
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {HELP_DESK_URL} from '#/lib/constants'
|
||||
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||
import {useApplyPullRequestOTAUpdate} from '#/lib/hooks/useOTAUpdates'
|
||||
@@ -70,6 +69,7 @@ import {
|
||||
} from '#/components/verification/VerificationCheckButton'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_INTERNAL, IS_IOS, IS_NATIVE} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {device, useStorage} from '#/storage'
|
||||
import {useActivitySubscriptionsNudged} from '#/storage/hooks/activity-subscriptions-nudged'
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {isStatusStillActive, isStatusValidForViewers} from '#/lib/actor-status'
|
||||
import {DISCOVER_FEED_URI, KNOWN_SHUTDOWN_FEEDS} from '#/lib/constants'
|
||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
@@ -70,7 +69,11 @@ import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interst
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env'
|
||||
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 {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
|
||||
import {FeedShutdownMsg} from './FeedShutdownMsg'
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {type ReasonFeedSource} from '#/lib/api/feed/types'
|
||||
import {MAX_POST_LINES} from '#/lib/constants'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
@@ -48,6 +47,7 @@ import {DiscoverDebug} from '#/components/PostControls/DiscoverDebug'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {SubtleHover} from '#/components/SubtleHover'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import * as bsky from '#/types/bsky'
|
||||
import {PostFeedReason} from './PostFeedReason'
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {HITSLOP_20} from '#/lib/constants'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
@@ -60,7 +59,7 @@ import {VerificationCreatePrompt} from '#/components/verification/VerificationCr
|
||||
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {useLiveNowConfig} from '#/features/liveNow'
|
||||
import {useActorStatus, useLiveNowConfig} from '#/features/liveNow'
|
||||
import {Dot} from '#/features/nuxs/components/Dot'
|
||||
import {Gradient} from '#/features/nuxs/components/Gradient'
|
||||
import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||
|
||||
@@ -5,7 +5,6 @@ import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {forceLTR} from '#/lib/strings/bidi'
|
||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||
@@ -21,6 +20,7 @@ import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {IS_ANDROID} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {TimeElapsed} from './TimeElapsed'
|
||||
import {PreviewableUserAvatar} from './UserAvatar'
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
import {
|
||||
useCameraPermission,
|
||||
@@ -54,6 +53,7 @@ import * as Menu from '#/components/Menu'
|
||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||
import {useAnalytics} from '#/analytics'
|
||||
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'
|
||||
|
||||
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 {StackActions, useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
||||
import {type PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
|
||||
@@ -57,6 +56,7 @@ import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import {IS_WEB} from '#/env'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
|
||||
const iconWidth = 26
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import {useLingui} from '@lingui/react'
|
||||
import {type BottomTabBarProps} from '@react-navigation/bottom-tabs'
|
||||
import {StackActions} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
import {BOTTOM_BAR_AVI} from '#/lib/demo'
|
||||
import {useHaptics} from '#/lib/haptics'
|
||||
@@ -49,6 +48,7 @@ import {
|
||||
Message_Stroke2_Corner0_Rounded_Filled as MessageFilled,
|
||||
} from '#/components/icons/Message'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {useDemoMode} from '#/storage/hooks/demo-mode'
|
||||
import {styles} from './BottomBarStyles'
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import {msg, plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation, useNavigationState} from '@react-navigation/native'
|
||||
|
||||
import {useActorStatus} from '#/lib/actor-status'
|
||||
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
|
||||
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 Prompt from '#/components/Prompt'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useActorStatus} from '#/features/liveNow'
|
||||
import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
|
||||
import {router} from '../../../routes'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user