From 4428bfc8a2fbb0066824d602ff6cad068787c0fe Mon Sep 17 00:00:00 2001 From: scanash00 Date: Fri, 12 Jun 2026 07:34:42 -0800 Subject: [PATCH] Remove app-config + live-events phone-home services and cosmetic Bluesky links --- src/App.native.tsx | 16 +- src/App.web.tsx | 17 +- src/components/FeedCard.tsx | 28 +-- .../Post/Embed/GalleryFallbackEmbed.tsx | 21 +-- src/env/common.ts | 20 --- ...verFeedLiveEventFeedsAndTrendingBanner.tsx | 110 ------------ .../ExploreScreenLiveEventFeedsBanner.tsx | 17 -- .../components/LiveEventFeedCardCompact.tsx | 123 ------------- .../components/LiveEventFeedCardWide.tsx | 132 -------------- .../components/LiveEventFeedOptionsMenu.tsx | 170 ------------------ .../LiveEventFeedsSettingsToggle.tsx | 44 ----- .../SidebarLiveEventFeedsBanner.tsx | 91 ---------- src/features/liveEvents/context.tsx | 136 -------------- src/features/liveEvents/preferences.ts | 146 --------------- src/features/liveEvents/types.ts | 27 --- src/features/liveNow/index.tsx | 15 +- src/lib/constants.ts | 2 - src/screens/Search/Explore.tsx | 10 -- src/screens/Settings/AboutSettings.tsx | 10 -- src/state/appConfig.tsx | 87 --------- src/view/com/posts/PostFeed.tsx | 3 +- src/view/shell/desktop/RightNav.tsx | 2 - 22 files changed, 9 insertions(+), 1218 deletions(-) delete mode 100644 src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx delete mode 100644 src/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner.tsx delete mode 100644 src/features/liveEvents/components/LiveEventFeedCardCompact.tsx delete mode 100644 src/features/liveEvents/components/LiveEventFeedCardWide.tsx delete mode 100644 src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx delete mode 100644 src/features/liveEvents/components/LiveEventFeedsSettingsToggle.tsx delete mode 100644 src/features/liveEvents/components/SidebarLiveEventFeedsBanner.tsx delete mode 100644 src/features/liveEvents/context.tsx delete mode 100644 src/features/liveEvents/preferences.ts delete mode 100644 src/features/liveEvents/types.ts delete mode 100644 src/state/appConfig.tsx diff --git a/src/App.native.tsx b/src/App.native.tsx index 8e76627..a337702 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -18,10 +18,6 @@ import {Provider as TranslateOnDeviceProvider} from '#/lib/translation' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' import {Provider as A11yProvider} from '#/state/a11y' -import { - prefetchAppConfig, - Provider as AppConfigProvider, -} from '#/state/appConfig' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' import {Provider as EmailVerificationProvider} from '#/state/email-verification' @@ -65,10 +61,6 @@ import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbe import * as Toast from '#/components/Toast' import {ToastOutlet} from '#/components/Toast' import {IS_ANDROID, IS_IOS} from '#/env' -import { - prefetchLiveEvents, - Provider as LiveEventsProvider, -} from '#/features/liveEvents/context' import {Splash} from '#/Splash' import {BottomSheetProvider} from '../modules/bottom-sheet' import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' @@ -86,8 +78,6 @@ if (IS_ANDROID) { ) } -void prefetchLiveEvents() -void prefetchAppConfig() function InnerApp() { const [isReady, setIsReady] = useState(false) @@ -133,7 +123,6 @@ function InnerApp() { key={currentAccount?.did}> - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} @@ -177,7 +166,6 @@ function InnerApp() { - @@ -207,8 +195,7 @@ function App() { * that is set up in the InnerApp component above. */ return ( - - + @@ -238,7 +225,6 @@ function App() { - ) } diff --git a/src/App.web.tsx b/src/App.web.tsx index 56c8f78..637fcf2 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -13,10 +13,6 @@ import {Provider as TranslateOnDeviceProvider} from '#/lib/translation' import I18nProvider from '#/locale/i18nProvider' import {logger} from '#/logger' import {Provider as A11yProvider} from '#/state/a11y' -import { - prefetchAppConfig, - Provider as AppConfigProvider, -} from '#/state/appConfig' import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes' import {Provider as DialogStateProvider} from '#/state/dialogs' import {Provider as EmailVerificationProvider} from '#/state/email-verification' @@ -58,17 +54,10 @@ import {Provider as ActiveVideoProvider} from '#/components/Post/Embed/VideoEmbe import {Provider as VideoVolumeProvider} from '#/components/Post/Embed/VideoEmbed/VideoVolumeContext' import * as Toast from '#/components/Toast' import {ToastOutlet} from '#/components/Toast' -import { - prefetchLiveEvents, - Provider as LiveEventsProvider, -} from '#/features/liveEvents/context' import {Splash} from '#/Splash' import {BackgroundNotificationPreferencesProvider} from '../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' import {Provider as HideBottomBarBorderProvider} from './lib/hooks/useHideBottomBarBorder' -void prefetchLiveEvents() -void prefetchAppConfig() - function InnerApp() { const [isReady, setIsReady] = useState(false) const {currentAccount} = useSession() @@ -114,7 +103,6 @@ function InnerApp() { key={currentAccount?.did}> - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} @@ -156,7 +144,6 @@ function InnerApp() { - @@ -187,8 +174,7 @@ function App() { * that is set up in the InnerApp component above. */ return ( - - + @@ -213,7 +199,6 @@ function App() { - ) } diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx index efd14be..c6407f7 100644 --- a/src/components/FeedCard.tsx +++ b/src/components/FeedCard.tsx @@ -19,14 +19,13 @@ import { } from '#/state/queries/preferences' import {useSession} from '#/state/session' import {UserAvatar} from '#/view/com/util/UserAvatar' -import {atoms as a, select, useTheme} from '#/alf' +import {atoms as a, useTheme} from '#/alf' import { Button, ButtonIcon, type ButtonProps, ButtonText, } from '#/components/Button' -import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live' import {Pin_Stroke2_Corner0_Rounded as PinIcon} from '#/components/icons/Pin' import {Link as InternalLink, type LinkProps} from '#/components/Link' import {Loader} from '#/components/Loader' @@ -34,7 +33,6 @@ import * as Prompt from '#/components/Prompt' import {RichText, type RichTextProps} from '#/components/RichText' import * as Toast from '#/components/Toast' import {Text} from '#/components/Typography' -import {useActiveLiveEventFeedUris} from '#/features/liveEvents/context' import type * as bsky from '#/types/bsky' import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from './icons/Trash' @@ -130,33 +128,9 @@ export function TitleAndByline({ uri?: string }) { const t = useTheme() - const activeLiveEvents = useActiveLiveEventFeedUris() - const liveColor = useMemo( - () => - select(t.name, { - dark: t.palette.negative_600, - dim: t.palette.negative_600, - light: t.palette.negative_500, - }), - [t], - ) return ( - {uri && activeLiveEvents.has(uri) && ( - - - - Happening now - - - )} Refresh the page to see it. )} - {IS_NATIVE && ( - - )} ) } diff --git a/src/env/common.ts b/src/env/common.ts index 9505686..adb6019 100644 --- a/src/env/common.ts +++ b/src/env/common.ts @@ -92,23 +92,3 @@ export const GCP_PROJECT_ID: number = process.env.EXPO_PUBLIC_GCP_PROJECT_ID === undefined ? 0 : Number(process.env.EXPO_PUBLIC_GCP_PROJECT_ID) - -/** - * URLs for the live-event config web worker. Can be a - * locally running server, see `env.example` for more. - */ -export const LIVE_EVENTS_DEV_URL = process.env.LIVE_EVENTS_DEV_URL -export const LIVE_EVENTS_PROD_URL = `https://live-events.workers.bsky.app` -export const LIVE_EVENTS_URL = IS_DEV - ? (LIVE_EVENTS_DEV_URL ?? LIVE_EVENTS_PROD_URL) - : LIVE_EVENTS_PROD_URL - -/** - * URLs for the app-config web worker. Can be a - * locally running server, see `env.example` for more. - */ -export const APP_CONFIG_DEV_URL = process.env.APP_CONFIG_DEV_URL -export const APP_CONFIG_PROD_URL = `https://app-config.workers.bsky.app` -export const APP_CONFIG_URL = IS_DEV - ? (APP_CONFIG_DEV_URL ?? APP_CONFIG_PROD_URL) - : APP_CONFIG_PROD_URL diff --git a/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx b/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx deleted file mode 100644 index 96a9bf3..0000000 --- a/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import {View} from 'react-native' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' -import {Trans} from '@lingui/react/macro' - -import {useTrendingSettings} from '#/state/preferences/trending' -import {atoms as a, useLayoutBreakpoints} from '#/alf' -import {Button} from '#/components/Button' -import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times' -import {TrendingInterstitial} from '#/components/interstitials/Trending' -import * as Toast from '#/components/Toast' -import {LiveEventFeedCardWide} from '#/features/liveEvents/components/LiveEventFeedCardWide' -import {useUserPreferencedLiveEvents} from '#/features/liveEvents/context' -import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences' -import {type LiveEventFeed} from '#/features/liveEvents/types' - -export function DiscoverFeedLiveEventFeedsAndTrendingBanner() { - const events = useUserPreferencedLiveEvents() - const {rightNavVisible} = useLayoutBreakpoints() - const {trendingDisabled} = useTrendingSettings() - - if (!events.feeds.length) { - if (!rightNavVisible && !trendingDisabled) { - // only show trending on mobile when live event banner is not shown - return - } else { - // no feed, no trending - return null - } - } - - // On desktop, we show in the sidebar - if (rightNavVisible) return null - - return events.feeds.map(feed => ) -} - -function Inner({feed}: {feed: LiveEventFeed}) { - const {_} = useLingui() - const layout = feed.layouts.wide - - const {mutate: update, variables} = useUpdateLiveEventPreferences({ - feed, - metricContext: 'discover', - onUpdateSuccess({undoAction}) { - Toast.show( - - - - {undoAction ? ( - Live event hidden - ) : ( - Live event unhidden - )} - - {undoAction && ( - { - if (undoAction) { - update(undoAction) - } - }}> - Undo - - )} - , - {type: 'success'}, - ) - }, - }) - - if (variables) return null - - return ( - <> - - - - - - - - - ) -} diff --git a/src/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner.tsx b/src/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner.tsx deleted file mode 100644 index bf80ed6..0000000 --- a/src/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import {View} from 'react-native' - -import {atoms as a, useTheme} from '#/alf' -import {LiveEventFeedCardWide} from '#/features/liveEvents/components/LiveEventFeedCardWide' -import {useLiveEvents} from '#/features/liveEvents/context' - -export function ExploreScreenLiveEventFeedsBanner() { - const t = useTheme() - const events = useLiveEvents() - return events.feeds.map(feed => ( - - - - )) -} diff --git a/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx b/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx deleted file mode 100644 index fb80010..0000000 --- a/src/features/liveEvents/components/LiveEventFeedCardCompact.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import {useMemo} from 'react' -import {View} from 'react-native' -import {Image} from 'expo-image' -import {LinearGradient} from 'expo-linear-gradient' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' - -import {useCallOnce} from '#/lib/once' -import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers' -import {atoms as a, utils} from '#/alf' -import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live' -import {Link} from '#/components/Link' -import {Text} from '#/components/Typography' -import { - type LiveEventFeed, - type LiveEventFeedMetricContext, -} from '#/features/liveEvents/types' - -const roundedStyles = [a.rounded_md, a.curve_continuous] - -export function LiveEventFeedCardCompact({ - feed, - metricContext, -}: { - feed: LiveEventFeed - metricContext: LiveEventFeedMetricContext -}) { - const {_} = useLingui() - const layout = feed.layouts.compact - const overlayColor = layout.overlayColor - const textColor = layout.textColor - const url = useMemo(() => { - // Validated in multiple places on the backend - if (isBskyCustomFeedUrl(feed.url)) { - return new URL(feed.url).pathname - } - return '/' - }, [feed.url]) - - useCallOnce(() => { - })() - - return ( - { - }}> - {({hovered, pressed}) => ( - - - - - - - - - - - - - {layout.title} - - - - - - )} - - ) -} diff --git a/src/features/liveEvents/components/LiveEventFeedCardWide.tsx b/src/features/liveEvents/components/LiveEventFeedCardWide.tsx deleted file mode 100644 index 2e4bff6..0000000 --- a/src/features/liveEvents/components/LiveEventFeedCardWide.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import {useMemo} from 'react' -import {View} from 'react-native' -import {Image} from 'expo-image' -import {LinearGradient} from 'expo-linear-gradient' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' -import {Trans} from '@lingui/react/macro' - -import {useCallOnce} from '#/lib/once' -import {isBskyCustomFeedUrl} from '#/lib/strings/url-helpers' -import {atoms as a, useBreakpoints, utils} from '#/alf' -import {Link} from '#/components/Link' -import {Text} from '#/components/Typography' -import { - type LiveEventFeed, - type LiveEventFeedMetricContext, -} from '#/features/liveEvents/types' - -const roundedStyles = [a.rounded_lg, a.curve_continuous] - -export function LiveEventFeedCardWide({ - feed, - metricContext, -}: { - feed: LiveEventFeed - metricContext: LiveEventFeedMetricContext -}) { - const {_} = useLingui() - const {gtPhone} = useBreakpoints() - - const layout = feed.layouts.wide - const overlayColor = layout.overlayColor - const textColor = layout.textColor - const url = useMemo(() => { - // Validated in multiple places on the backend - if (isBskyCustomFeedUrl(feed.url)) { - return new URL(feed.url).pathname - } - return '/' - }, [feed.url]) - - useCallOnce(() => { - })() - - return ( - { - }}> - {({hovered, pressed}) => ( - - - - - - - - - - - - {feed.preview ? ( - Preview - ) : ( - Happening now - )} - - - {layout.title} - - - - - - )} - - ) -} diff --git a/src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx b/src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx deleted file mode 100644 index c01a7fe..0000000 --- a/src/features/liveEvents/components/LiveEventFeedOptionsMenu.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import {View} from 'react-native' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' -import {Trans} from '@lingui/react/macro' - -import {useCleanError} from '#/lib/hooks/useCleanError' -import {atoms as a, web} from '#/alf' -import {Admonition} from '#/components/Admonition' -import {Button, ButtonIcon, ButtonText} from '#/components/Button' -import * as Dialog from '#/components/Dialog' -import {Loader} from '#/components/Loader' -import * as Toast from '#/components/Toast' -import {Span, Text} from '#/components/Typography' -import {IS_NATIVE} from '#/env' -import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences' -import { - type LiveEventFeed, - type LiveEventFeedMetricContext, -} from '#/features/liveEvents/types' - -export {useDialogControl} from '#/components/Dialog' - -export function LiveEventFeedOptionsMenu({ - control, - feed, - metricContext, -}: { - control: Dialog.DialogControlProps - feed: LiveEventFeed - metricContext: LiveEventFeedMetricContext -}) { - const {_} = useLingui() - return ( - - - - - - - - ) -} - -function Inner({ - control, - feed, - metricContext, -}: { - control: Dialog.DialogControlProps - feed: LiveEventFeed - metricContext: LiveEventFeedMetricContext -}) { - const {_} = useLingui() - const { - isPending, - mutate: update, - error: rawError, - variables, - } = useUpdateLiveEventPreferences({ - feed, - metricContext, - onUpdateSuccess({undoAction}) { - Toast.show( - - - - Your live event preferences have been updated. - - {undoAction && ( - { - if (undoAction) { - update(undoAction) - } - }}> - Undo - - )} - , - {type: 'success'}, - ) - - /* - * If there is no `undoAction`, it means that the action was already - * undone, and therefore the menu would have been closed prior to the - * undo happening. - */ - if (undoAction) { - control.close() - } - }, - }) - const cleanError = useCleanError() - const error = rawError ? cleanError(rawError) : undefined - - const isHidingFeed = variables?.type === 'hideFeed' && isPending - const isHidingAllFeeds = variables?.type === 'toggleHideAllFeeds' && isPending - - return ( - - - - Live event options - - - - - Live events appear occasionally when something exciting is - happening. If you'd like, you can hide this particular event, or all - events for this placement in your app interface. - - - - - - If you choose to hide all events, you can always re-enable them from{' '} - Settings → Content & Media. - - - - - - - - {IS_NATIVE && ( - - )} - - - {error && ( - - {error.clean || error.raw || _(msg`An unknown error occurred.`)} - - )} - - ) -} diff --git a/src/features/liveEvents/components/LiveEventFeedsSettingsToggle.tsx b/src/features/liveEvents/components/LiveEventFeedsSettingsToggle.tsx deleted file mode 100644 index f226550..0000000 --- a/src/features/liveEvents/components/LiveEventFeedsSettingsToggle.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' -import {Trans} from '@lingui/react/macro' - -import * as SettingsList from '#/screens/Settings/components/SettingsList' -import * as Toggle from '#/components/forms/Toggle' -import {Live_Stroke2_Corner0_Rounded as LiveIcon} from '#/components/icons/Live' -import { - useLiveEventPreferences, - useUpdateLiveEventPreferences, -} from '#/features/liveEvents/preferences' - -export function LiveEventFeedsSettingsToggle() { - const {_} = useLingui() - const {data: prefs} = useLiveEventPreferences() - const { - isPending, - data: updatedPrefs, - mutate: update, - } = useUpdateLiveEventPreferences({ - metricContext: 'settings', - }) - const hideAllFeeds = !!(updatedPrefs || prefs)?.hideAllFeeds - - return ( - { - if (!isPending) { - update({type: 'toggleHideAllFeeds'}) - } - }}> - - - - Show live events in your Discover Feed - - - - - ) -} diff --git a/src/features/liveEvents/components/SidebarLiveEventFeedsBanner.tsx b/src/features/liveEvents/components/SidebarLiveEventFeedsBanner.tsx deleted file mode 100644 index c5b6cc5..0000000 --- a/src/features/liveEvents/components/SidebarLiveEventFeedsBanner.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import {View} from 'react-native' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' -import {Trans} from '@lingui/react/macro' - -import {atoms as a} from '#/alf' -import {Button} from '#/components/Button' -import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times' -import * as Toast from '#/components/Toast' -import {LiveEventFeedCardCompact} from '#/features/liveEvents/components/LiveEventFeedCardCompact' -import {useUserPreferencedLiveEvents} from '#/features/liveEvents/context' -import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences' -import {type LiveEventFeed} from '#/features/liveEvents/types' - -export function SidebarLiveEventFeedsBanner() { - const events = useUserPreferencedLiveEvents() - return events.feeds.map(feed => ) -} - -function Inner({feed}: {feed: LiveEventFeed}) { - const {_} = useLingui() - const layout = feed.layouts.wide - - const {mutate: update, variables} = useUpdateLiveEventPreferences({ - feed, - metricContext: 'sidebar', - onUpdateSuccess({undoAction}) { - Toast.show( - - - - {undoAction ? ( - Live event hidden - ) : ( - Live event unhidden - )} - - {undoAction && ( - { - if (undoAction) { - update(undoAction) - } - }}> - Undo - - )} - , - {type: 'success'}, - ) - }, - }) - - if (variables) return null - - return ( - - - - - - - - ) -} diff --git a/src/features/liveEvents/context.tsx b/src/features/liveEvents/context.tsx deleted file mode 100644 index 3de2534..0000000 --- a/src/features/liveEvents/context.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import {createContext, useContext, useMemo} from 'react' -import {hasMutedWord} from '@atproto/api' -import {QueryClient, useQuery} from '@tanstack/react-query' - -import {useOnAppStateChange} from '#/lib/appState' -import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam' -import { - convertBskyAppUrlIfNeeded, - isBskyCustomFeedUrl, - makeRecordUri, -} from '#/lib/strings/url-helpers' -import {usePreferencesQuery} from '#/state/queries/preferences' -import {IS_DEV, LIVE_EVENTS_URL} from '#/env' -import {useLiveEventPreferences} from '#/features/liveEvents/preferences' -import {type LiveEventsWorkerResponse} from '#/features/liveEvents/types' -import {useDevMode} from '#/storage/hooks/dev-mode' - -const qc = new QueryClient() -const liveEventsQueryKey = ['live-events'] - -export const DEFAULT_LIVE_EVENTS = { - feeds: [], -} - -async function fetchLiveEvents(): Promise { - try { - const res = await fetch(`${LIVE_EVENTS_URL}/config`) - if (!res.ok) return null - const data = await res.json() - return data - } catch { - return null - } -} - -const Context = createContext(DEFAULT_LIVE_EVENTS) - -export function Provider({children}: React.PropsWithChildren<{}>) { - const [isDevMode] = useDevMode() - const isBskyTeam = useIsBskyTeam() - const {data: preferences} = usePreferencesQuery() - const mutedWords = useMemo( - () => preferences?.moderationPrefs?.mutedWords ?? [], - [preferences?.moderationPrefs?.mutedWords], - ) - - const {data, refetch} = useQuery( - { - // keep this, prefectching handles initial load - staleTime: 1000 * 15, - queryKey: liveEventsQueryKey, - refetchInterval: 1000 * 60 * 5, // refetch every 5 minutes - async queryFn() { - return fetchLiveEvents() - }, - }, - qc, - ) - - useOnAppStateChange(state => { - if (state === 'active') void refetch() - }) - - const ctx = useMemo(() => { - if (!data) return DEFAULT_LIVE_EVENTS - const skipMuteFilter = isBskyTeam || IS_DEV - const feeds = data.feeds.filter(f => { - if (f.preview && !isBskyTeam) return false - if (!skipMuteFilter && mutedWords.length > 0) { - const text = [ - f.title, - f.layouts?.wide?.title, - f.layouts?.compact?.title, - ] - .filter(Boolean) - .join(' ') - if (hasMutedWord({mutedWords, text})) return false - } - return true - }) - return { - ...data, - // only one at a time for now, unless bsky team and dev mode - feeds: isBskyTeam && isDevMode ? feeds : feeds.slice(0, 1), - } - }, [data, isBskyTeam, isDevMode, mutedWords]) - - return {children} -} - -export async function prefetchLiveEvents() { - const data = await fetchLiveEvents() - if (data) { - qc.setQueryData(liveEventsQueryKey, data) - } -} - -export function useLiveEvents() { - const ctx = useContext(Context) - if (!ctx) { - throw new Error('useLiveEventsContext must be used within a Provider') - } - return ctx -} - -export function useUserPreferencedLiveEvents() { - const events = useLiveEvents() - const {data, isLoading} = useLiveEventPreferences() - if (isLoading) return DEFAULT_LIVE_EVENTS - const {hideAllFeeds, hiddenFeedIds} = data - return { - ...events, - feeds: hideAllFeeds - ? [] - : events.feeds.filter(f => { - const hidden = f?.id ? hiddenFeedIds.includes(f?.id || '') : false - return !hidden - }), - } -} - -export function useActiveLiveEventFeedUris() { - const {feeds} = useLiveEvents() - - return new Set( - feeds - // insurance - .filter(f => isBskyCustomFeedUrl(f.url)) - .map(f => { - const uri = convertBskyAppUrlIfNeeded(f.url) - const [_0, did, _1, rkey] = uri.split('/').filter(Boolean) - const urip = makeRecordUri(did, 'app.bsky.feed.generator', rkey) - return urip.toString() - }), - ) -} diff --git a/src/features/liveEvents/preferences.ts b/src/features/liveEvents/preferences.ts deleted file mode 100644 index ff20db9..0000000 --- a/src/features/liveEvents/preferences.ts +++ /dev/null @@ -1,146 +0,0 @@ -import {logger} from '#/logger' -import {useEffect} from 'react' -import {type Agent, AppBskyActorDefs, asPredicate} from '@atproto/api' -import {useMutation, useQueryClient} from '@tanstack/react-query' - -import { - preferencesQueryKey, - usePreferencesQuery, -} from '#/state/queries/preferences' -import {useAgent} from '#/state/session' -import * as env from '#/env' -import {IS_WEB} from '#/env' -import { - type LiveEventFeed, - type LiveEventFeedMetricContext, -} from '#/features/liveEvents/types' - -export type LiveEventPreferencesAction = Parameters< - Agent['updateLiveEventPreferences'] ->[0] & { - /** - * Flag that is internal to this hook, do not set when updating prefs - */ - __canUndo?: boolean -} - -export function useLiveEventPreferences() { - const query = usePreferencesQuery() - useWebOnlyDebugLiveEventPreferences() - return { - ...query, - data: query.data?.liveEventPreferences || { - hideAllFeeds: false, - hiddenFeedIds: [], - }, - } -} - -function useWebOnlyDebugLiveEventPreferences() { - const queryClient = useQueryClient() - const agent = useAgent() - - useEffect(() => { - if (env.IS_DEV && IS_WEB && typeof window !== 'undefined') { - // @ts-ignore - window.__updateLiveEventPreferences = async ( - action: LiveEventPreferencesAction, - ) => { - await agent.updateLiveEventPreferences(action) - // triggers a refetch - await queryClient.invalidateQueries({ - queryKey: preferencesQueryKey, - }) - } - } - }, [agent, queryClient]) -} - -export function useUpdateLiveEventPreferences(props: { - feed?: LiveEventFeed - metricContext: LiveEventFeedMetricContext - onUpdateSuccess?: (props: { - undoAction: LiveEventPreferencesAction | null - }) => void -}) { - const queryClient = useQueryClient() - const agent = useAgent() - - return useMutation< - AppBskyActorDefs.LiveEventPreferences, - Error, - LiveEventPreferencesAction, - {undoAction: LiveEventPreferencesAction | null} - >({ - onSettled(data, error, variables) { - /* - * `onSettled` runs after the mutation completes, success or no. The idea - * here is that we want to invert the action that was just passed in, and - * provide it as an `undoAction` to the `onUpdateSuccess` callback. - * - * If the operation was not a success, we don't provide the `undoAction`. - * - * Upon the first call of the mutation, the `__canUndo` flag is undefined, - * so we allow the undo. However, when we create the `undoAction`, we - * set its `__canUndo` flag to false, so that if the user were to call - * the undo action, we would not provide another undo for that. - */ - const canUndo = variables.__canUndo === undefined ? true : false - let undoAction: LiveEventPreferencesAction | null = null - - switch (variables.type) { - case 'hideFeed': - undoAction = {type: 'unhideFeed', id: variables.id, __canUndo: false} - break - case 'unhideFeed': - undoAction = {type: 'hideFeed', id: variables.id, __canUndo: false} - break - case 'toggleHideAllFeeds': - undoAction = {type: 'toggleHideAllFeeds', __canUndo: false} - break - } - - if (data && !error) { - props?.onUpdateSuccess?.({ - undoAction: canUndo ? undoAction : null, - }) - } - }, - mutationFn: async action => { - const updated = await agent.updateLiveEventPreferences(action) - const prefs = updated.find(p => - asPredicate(AppBskyActorDefs.validateLiveEventPreferences)(p), - ) - - switch (action.type) { - case 'hideFeed': - case 'unhideFeed': { - if (!props.feed) { - logger.error( - `useUpdateLiveEventPreferences: feed is missing, but required for hiding/unhiding`, - { - action, - }, - ) - break - } - - break - } - case 'toggleHideAllFeeds': { - if (prefs!.hideAllFeeds) { - } else { - } - break - } - } - - // triggers a refetch - queryClient.invalidateQueries({ - queryKey: preferencesQueryKey, - }) - - return prefs! - }, - }) -} diff --git a/src/features/liveEvents/types.ts b/src/features/liveEvents/types.ts deleted file mode 100644 index 8bc88c4..0000000 --- a/src/features/liveEvents/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -export type LiveEventFeedImageLayout = 'wide' | 'compact' // maybe more in the future - -export type LiveEventFeedLayout = { - title: string - overlayColor: string - textColor: string - image: string - blurhash: string -} - -export type LiveEventFeed = { - id: string - preview: boolean - title: string - url: string - layouts: Record -} - -export type LiveEventsWorkerResponse = { - feeds: LiveEventFeed[] -} - -export type LiveEventFeedMetricContext = - | 'explore' - | 'discover' - | 'sidebar' - | 'settings' diff --git a/src/features/liveNow/index.tsx b/src/features/liveNow/index.tsx index 818ab36..ca6adfb 100644 --- a/src/features/liveNow/index.tsx +++ b/src/features/liveNow/index.tsx @@ -18,7 +18,6 @@ import {isAfter, parseISO} from 'date-fns' import {uploadBlob} from '#/lib/api' import {imageToThumb} from '#/lib/api/resolve' import {getLinkMeta, type LinkMeta} from '#/lib/link-meta/link-meta' -import {useAppConfig} from '#/state/appConfig' import { updateProfileShadow, useMaybeProfileShadow, @@ -57,22 +56,14 @@ export type LiveNowConfig = { } export function useLiveNowConfig(): LiveNowConfig { - const {liveNow} = useAppConfig() const {currentAccount} = useSession() return useMemo(() => { const disabled = false - const defaultAllowedHosts = new Set( - DEFAULT_ALLOWED_DOMAINS.concat(liveNow.allow), - ) + // Remote app-config has been removed; use the built-in allowed domains only. + const defaultAllowedHosts = new Set(DEFAULT_ALLOWED_DOMAINS) const allowedHostsExceptionsByDid = new Map>() - for (const ex of liveNow.exceptions) { - allowedHostsExceptionsByDid.set( - ex.did, - new Set(DEFAULT_ALLOWED_DOMAINS.concat(ex.allow)), - ) - } if (!currentAccount?.did || disabled) { return { @@ -91,7 +82,7 @@ export function useLiveNowConfig(): LiveNowConfig { defaultAllowedHosts, allowedHostsExceptionsByDid, } - }, [liveNow, currentAccount]) + }, [currentAccount]) } export function useActorStatus(actor?: bsky.profile.AnyProfileView) { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index adc51c5..9b88159 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -102,8 +102,6 @@ export function LINK_META_PROXY(_serviceUrl: string) { return PROD_LINK_META_PROXY } -export const STATUS_PAGE_URL = 'https://status.bsky.app/' - // Hitslop constants export const createHitslop = (size: number): Insets => ({ top: size, diff --git a/src/screens/Search/Explore.tsx b/src/screens/Search/Explore.tsx index fce3f49..fb743e8 100644 --- a/src/screens/Search/Explore.tsx +++ b/src/screens/Search/Explore.tsx @@ -70,7 +70,6 @@ import {Loader} from '#/components/Loader' import * as ProfileCard from '#/components/ProfileCard' import {SubtleHover} from '#/components/SubtleHover' import {Text} from '#/components/Typography' -import {ExploreScreenLiveEventFeedsBanner} from '#/features/liveEvents/components/ExploreScreenLiveEventFeedsBanner' import * as ModuleHeader from './components/ModuleHeader' import { SuggestedAccountsTabBar, @@ -208,10 +207,6 @@ type ExploreScreenItems = type: 'interests-card' key: 'interests-card' } - | { - type: 'liveEventFeedsBanner' - key: string - } export function Explore({ focusSearchInput, @@ -719,8 +714,6 @@ export function Explore({ i.push(topBorder) i.push(...interestsNuxModule) - i.push({type: 'liveEventFeedsBanner', key: 'liveEventFeedsBanner'}) - if (useFullExperience) { i.push(trendingTopicsModule) i.push(...suggestedFeedsModule) @@ -1025,9 +1018,6 @@ export function Explore({ case 'interests-card': { return } - case 'liveEventFeedsBanner': { - return - } } }, [ diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx index ac4896c..006b8a9 100644 --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -8,7 +8,6 @@ import {Trans} from '@lingui/react/macro' import {type NativeStackScreenProps} from '@react-navigation/native-stack' import {useMutation} from '@tanstack/react-query' -import {STATUS_PAGE_URL} from '#/lib/constants' import {getDeviceId} from '#/lib/deviceId' import {type CommonNavigatorParams} from '#/lib/routes/types' import * as SettingsList from '#/screens/Settings/components/SettingsList' @@ -16,7 +15,6 @@ import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom' import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/components/icons/BroomSparkle' import {Bubbles_Stroke2_Corner2_Rounded as BubblesIcon} from '#/components/icons/Bubble' import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines' -import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/icons/Newspaper' import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench' import * as Layout from '#/components/Layout' @@ -98,14 +96,6 @@ export function AboutSettingsScreen({}: Props) { Privacy Policy - - - - Status Page - - diff --git a/src/state/appConfig.tsx b/src/state/appConfig.tsx deleted file mode 100644 index 67b0e55..0000000 --- a/src/state/appConfig.tsx +++ /dev/null @@ -1,87 +0,0 @@ -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/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx index 70e3ade..21b3a37 100644 --- a/src/view/com/posts/PostFeed.tsx +++ b/src/view/com/posts/PostFeed.tsx @@ -59,7 +59,6 @@ import {TrendingInterstitial} from '#/components/interstitials/Trending' import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos' import {isStandardSiteEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils' import {IS_IOS, IS_NATIVE, IS_WEB} from '#/env' -import {DiscoverFeedLiveEventFeedsAndTrendingBanner} from '#/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner' import { isStatusStillActive, isStatusValidForViewers, @@ -740,7 +739,7 @@ let PostFeed = ({ } else if (row.type === 'interstitialTrending') { return } else if (row.type === 'liveEventFeedsAndTrendingBanner') { - return + return } else if (row.type === 'composerPrompt') { return } else if (row.type === 'interstitialTrendingVideos') { diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx index fa05581..4b7427a 100644 --- a/src/view/shell/desktop/RightNav.tsx +++ b/src/view/shell/desktop/RightNav.tsx @@ -22,7 +22,6 @@ import {CENTER_COLUMN_OFFSET} from '#/components/Layout' import {InlineLinkText} from '#/components/Link' import {ProgressGuideList} from '#/components/ProgressGuide/List' import {Text} from '#/components/Typography' -import {SidebarLiveEventFeedsBanner} from '#/features/liveEvents/components/SidebarLiveEventFeedsBanner' function useWebQueryParams() { const navigation = useNavigation() @@ -93,7 +92,6 @@ export function DesktopRightNav({routeName}: {routeName: string}) { )} - {showExploreScreenDuplicatedContent && } {showExploreScreenDuplicatedContent && } -- 2.51.2