, // 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
- }
-}
diff --git a/src/lib/async/retry.ts b/src/lib/async/retry.ts
index 8a1729091d..479a1cdc12 100644
--- a/src/lib/async/retry.ts
+++ b/src/lib/async/retry.ts
@@ -29,6 +29,7 @@ export async function retry(
export async function networkRetry
(
retries: number,
fn: () => Promise
,
+ delay?: number,
): Promise
{
- return retry(retries, isNetworkError, fn)
+ return retry(retries, isNetworkError, fn, delay)
}
diff --git a/src/lib/hooks/useDebouncedValue.ts b/src/lib/hooks/useDebouncedValue.ts
new file mode 100644
index 0000000000..c8e083b9b3
--- /dev/null
+++ b/src/lib/hooks/useDebouncedValue.ts
@@ -0,0 +1,16 @@
+import {useEffect, useState} from 'react'
+
+/**
+ * Returns a debounced version of the input value that only updates after the
+ * specified delay has passed without any changes to the input value.
+ */
+export function useDebouncedValue(val: T, delayMs: number): T {
+ const [prev, setPrev] = useState(val)
+
+ useEffect(() => {
+ const timeout = setTimeout(() => setPrev(val), delayMs)
+ return () => clearTimeout(timeout)
+ }, [val, delayMs])
+
+ return prev
+}
diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx
index e475b42de1..27fcaf0fa8 100644
--- a/src/screens/PostThread/components/ThreadItemAnchor.tsx
+++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx
@@ -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({
diff --git a/src/screens/PostThread/components/ThreadItemPost.tsx b/src/screens/PostThread/components/ThreadItemPost.tsx
index ea0d5631bb..4fe78785b8 100644
--- a/src/screens/PostThread/components/ThreadItemPost.tsx
+++ b/src/screens/PostThread/components/ThreadItemPost.tsx
@@ -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
diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
index 9c1c8a662a..f2f24edaab 100644
--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx
+++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx
@@ -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'
diff --git a/src/screens/Profile/Header/Shell.tsx b/src/screens/Profile/Header/Shell.tsx
index 8543d45bd1..ae7c146b8c 100644
--- a/src/screens/Profile/Header/Shell.tsx
+++ b/src/screens/Profile/Header/Shell.tsx
@@ -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'
@@ -28,13 +27,14 @@ import {atoms as a, platform, useTheme} from '#/alf'
import {Button} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import {ArrowLeft_Stroke2_Corner0_Rounded as ArrowLeftIcon} from '#/components/icons/Arrow'
-import {EditLiveDialog} from '#/components/live/EditLiveDialog'
-import {LiveIndicator} from '#/components/live/LiveIndicator'
-import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
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 {EditLiveDialog} from '#/features/liveNow/components/EditLiveDialog'
+import {LiveIndicator} from '#/features/liveNow/components/LiveIndicator'
+import {LiveStatusDialog} from '#/features/liveNow/components/LiveStatusDialog'
import {GrowableAvatar} from './GrowableAvatar'
import {GrowableBanner} from './GrowableBanner'
import {StatusBarShadow} from './StatusBarShadow'
diff --git a/src/screens/Settings/Settings.tsx b/src/screens/Settings/Settings.tsx
index 4f6fbb602b..c79386d05b 100644
--- a/src/screens/Settings/Settings.tsx
+++ b/src/screens/Settings/Settings.tsx
@@ -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'
diff --git a/src/state/appConfig.tsx b/src/state/appConfig.tsx
new file mode 100644
index 0000000000..67b0e553ed
--- /dev/null
+++ b/src/state/appConfig.tsx
@@ -0,0 +1,87 @@
+import {createContext, useContext} from 'react'
+import {QueryClient, useQuery} from '@tanstack/react-query'
+
+import {APP_CONFIG_URL} from '#/env'
+
+const qc = new QueryClient()
+const appConfigQueryKey = ['app-config']
+
+/**
+ * Matches the types defined in our `app-config` worker
+ */
+type AppConfigResponse = {
+ liveNow: {
+ allow: string[]
+ exceptions: {
+ did: string
+ allow: string[]
+ }[]
+ }
+}
+
+export const DEFAULT_APP_CONFIG_RESPONSE: AppConfigResponse = {
+ liveNow: {
+ allow: [],
+ exceptions: [],
+ },
+}
+
+let fetchAppConfigPromise: Promise | undefined
+
+async function fetchAppConfig(): Promise {
+ try {
+ if (!fetchAppConfigPromise) {
+ fetchAppConfigPromise = (async () => {
+ const r = await fetch(`${APP_CONFIG_URL}/config`)
+ if (!r.ok) throw new Error(await r.text())
+ const data = await r.json()
+ return data
+ })()
+ }
+ return await fetchAppConfigPromise
+ } catch (e) {
+ fetchAppConfigPromise = undefined
+ throw e
+ }
+}
+
+const Context = createContext(DEFAULT_APP_CONFIG_RESPONSE)
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+ const {data} = useQuery(
+ {
+ staleTime: Infinity,
+ queryKey: appConfigQueryKey,
+ refetchInterval: query => {
+ // refetch regularly if fetch failed, otherwise never refetch
+ return query.state.status === 'error' ? 60e3 : Infinity
+ },
+ async queryFn() {
+ return fetchAppConfig()
+ },
+ },
+ qc,
+ )
+ return (
+
+ {children}
+
+ )
+}
+
+export async function prefetchAppConfig() {
+ try {
+ const data = await fetchAppConfig()
+ if (data) {
+ qc.setQueryData(appConfigQueryKey, data)
+ }
+ } catch {}
+}
+
+export function useAppConfig() {
+ const ctx = useContext(Context)
+ if (!ctx) {
+ throw new Error('useAppConfig must be used within a Provider')
+ }
+ return ctx
+}
diff --git a/src/state/queries/handle-availability.ts b/src/state/queries/handle-availability.ts
index e3f7a6b741..fb25697c76 100644
--- a/src/state/queries/handle-availability.ts
+++ b/src/state/queries/handle-availability.ts
@@ -6,8 +6,8 @@ import {
BSKY_SERVICE_DID,
PUBLIC_BSKY_SERVICE,
} from '#/lib/constants'
+import {useDebouncedValue} from '#/lib/hooks/useDebouncedValue'
import {createFullHandle} from '#/lib/strings/handles'
-import {useDebouncedValue} from '#/components/live/utils'
import {useAnalytics} from '#/analytics'
import * as bsky from '#/types/bsky'
import {Agent} from '../session/agent'
diff --git a/src/state/service-config.tsx b/src/state/service-config.tsx
index 29fa6bec90..e102cde2f9 100644
--- a/src/state/service-config.tsx
+++ b/src/state/service-config.tsx
@@ -2,28 +2,17 @@ import {createContext, useContext, useMemo} from 'react'
import {useLanguagePrefs} from '#/state/preferences/languages'
import {useServiceConfigQuery} from '#/state/queries/service-config'
-import {useSession} from '#/state/session'
-import {useAnalytics} from '#/analytics'
-import {IS_DEV} from '#/env'
import {device} from '#/storage'
type TrendingContext = {
enabled: boolean
}
-type LiveNowContext = {
- did: string
- domains: string[]
-}[]
-
const TrendingContext = createContext({
enabled: false,
})
TrendingContext.displayName = 'TrendingContext'
-const LiveNowContext = createContext([])
-LiveNowContext.displayName = 'LiveNowContext'
-
const CheckEmailConfirmedContext = createContext(null)
export function Provider({children}: {children: React.ReactNode}) {
@@ -60,19 +49,15 @@ export function Provider({children}: {children: React.ReactNode}) {
return {enabled}
}, [isInitialLoad, config, langPrefs.contentLanguages])
- const liveNow = useMemo(() => config?.liveNow ?? [], [config])
-
// probably true, so default to true when loading
// if the call fails, the query will set it to false for us
const checkEmailConfirmed = config?.checkEmailConfirmed ?? true
return (
-
-
- {children}
-
-
+
+ {children}
+
)
}
@@ -81,55 +66,6 @@ export function useTrendingConfig() {
return useContext(TrendingContext)
}
-const DEFAULT_LIVE_ALLOWED_DOMAINS = [
- 'twitch.tv',
- 'www.twitch.tv',
- 'stream.place',
- 'bluecast.app',
- 'www.bluecast.app',
-]
-export type LiveNowConfig = {
- currentAccountAllowedHosts: Set
- defaultAllowedHosts: Set
- allowedHostsExceptionsByDid: Map>
-}
-export function useLiveNowConfig(): LiveNowConfig {
- const ctx = useContext(LiveNowContext)
- const canGoLive = useCanGoLive()
- const {currentAccount} = useSession()
- return useMemo(() => {
- const defaultAllowedHosts = new Set(DEFAULT_LIVE_ALLOWED_DOMAINS)
- const allowedHostsExceptionsByDid = new Map>()
- for (const live of ctx) {
- allowedHostsExceptionsByDid.set(
- live.did,
- new Set(DEFAULT_LIVE_ALLOWED_DOMAINS.concat(live.domains)),
- )
- }
- if (!currentAccount?.did || !canGoLive)
- return {
- currentAccountAllowedHosts: new Set(),
- defaultAllowedHosts,
- allowedHostsExceptionsByDid,
- }
- const vip = ctx.find(live => live.did === currentAccount.did)
- return {
- currentAccountAllowedHosts: new Set(
- DEFAULT_LIVE_ALLOWED_DOMAINS.concat(vip ? vip.domains : []),
- ),
- defaultAllowedHosts,
- allowedHostsExceptionsByDid,
- }
- }, [ctx, currentAccount, canGoLive])
-}
-
-export function useCanGoLive() {
- const ax = useAnalytics()
- const {hasSession} = useSession()
- if (!hasSession) return false
- return IS_DEV ? true : !ax.features.enabled(ax.features.LiveNowBetaDisable)
-}
-
export function useCheckEmailConfirmed() {
const ctx = useContext(CheckEmailConfirmedContext)
if (ctx === null) {
diff --git a/src/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx
index b79fc1ab32..899907cdef 100644
--- a/src/view/com/posts/PostFeed.tsx
+++ b/src/view/com/posts/PostFeed.tsx
@@ -19,7 +19,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'
@@ -40,7 +39,6 @@ import {
RQKEY,
usePostFeedQuery,
} from '#/state/queries/post-feed'
-import {useLiveNowConfig} from '#/state/service-config'
import {useSession} from '#/state/session'
import {useProgressGuide} from '#/state/shell/progress-guide'
import {useSelectedFeed} from '#/state/shell/selected-feed'
@@ -63,6 +61,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 {
+ isStatusStillActive,
+ isStatusValidForViewers,
+ useLiveNowConfig,
+} from '#/features/liveNow'
import {ComposerPrompt} from '../feeds/ComposerPrompt'
import {DiscoverFallbackHeader} from './DiscoverFallbackHeader'
import {FeedShutdownMsg} from './FeedShutdownMsg'
diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx
index 0961004952..064c94d2c3 100644
--- a/src/view/com/posts/PostFeedItem.tsx
+++ b/src/view/com/posts/PostFeedItem.tsx
@@ -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'
diff --git a/src/view/com/profile/ProfileMenu.tsx b/src/view/com/profile/ProfileMenu.tsx
index 684dcbf0fe..76b58fb718 100644
--- a/src/view/com/profile/ProfileMenu.tsx
+++ b/src/view/com/profile/ProfileMenu.tsx
@@ -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'
@@ -20,7 +19,6 @@ import {
useProfileFollowMutationQueue,
useProfileMuteMutationQueue,
} from '#/state/queries/profile'
-import {useCanGoLive} from '#/state/service-config'
import {useSession} from '#/state/session'
import {EventStopper} from '#/view/com/util/EventStopper'
import * as Toast from '#/view/com/util/Toast'
@@ -47,9 +45,6 @@ import {
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker'
import {StarterPack} from '#/components/icons/StarterPack'
-import {EditLiveDialog} from '#/components/live/EditLiveDialog'
-import {GoLiveDialog} from '#/components/live/GoLiveDialog'
-import {GoLiveDisabledDialog} from '#/components/live/GoLiveDisabledDialog'
import * as Menu from '#/components/Menu'
import {
ReportDialog,
@@ -61,6 +56,10 @@ import {VerificationCreatePrompt} from '#/components/verification/VerificationCr
import {VerificationRemovePrompt} from '#/components/verification/VerificationRemovePrompt'
import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env'
+import {useActorStatus, useLiveNowConfig} from '#/features/liveNow'
+import {EditLiveDialog} from '#/features/liveNow/components/EditLiveDialog'
+import {GoLiveDialog} from '#/features/liveNow/components/GoLiveDialog'
+import {GoLiveDisabledDialog} from '#/features/liveNow/components/GoLiveDisabledDialog'
import {Dot} from '#/features/nuxs/components/Dot'
import {Gradient} from '#/features/nuxs/components/Gradient'
import {useDevMode} from '#/storage/hooks/dev-mode'
@@ -85,7 +84,7 @@ let ProfileMenu = ({
const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked
const [devModeEnabled] = useDevMode()
const verification = useFullVerificationState({profile})
- const canGoLive = useCanGoLive()
+ const {canGoLive} = useLiveNowConfig()
const status = useActorStatus(profile)
const statusNudge = useNux(Nux.LiveNowBetaNudge)
const statusNudgeActive =
diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx
index ca40ef5f42..1a37e55cbd 100644
--- a/src/view/com/util/PostMeta.tsx
+++ b/src/view/com/util/PostMeta.tsx
@@ -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'
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index 529a6ed52f..6acbc6506e 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -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,
@@ -47,13 +46,14 @@ import {
import {StreamingLive_Stroke2_Corner0_Rounded as LibraryIcon} from '#/components/icons/StreamingLive'
import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash'
import {Link} from '#/components/Link'
-import {LiveIndicator} from '#/components/live/LiveIndicator'
-import {LiveStatusDialog} from '#/components/live/LiveStatusDialog'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
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 {LiveIndicator} from '#/features/liveNow/components/LiveIndicator'
+import {LiveStatusDialog} from '#/features/liveNow/components/LiveStatusDialog'
import type * as bsky from '#/types/bsky'
export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
index 42a5fe417c..d46e1e44e5 100644
--- a/src/view/shell/Drawer.tsx
+++ b/src/view/shell/Drawer.tsx
@@ -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
diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx
index 7c2a010ab1..ef0ceaba97 100644
--- a/src/view/shell/bottom-bar/BottomBar.tsx
+++ b/src/view/shell/bottom-bar/BottomBar.tsx
@@ -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'
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 3e9ccea647..a9d1942051 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -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'