From 50c1841a06d0502428f70bb0bb225cca70f82c20 Mon Sep 17 00:00:00 2001 From: LW Date: Tue, 16 May 2023 11:13:05 -0700 Subject: feat: Update HTML `title` on web #626 #599 (#655) For any `Screen` that shows on desktop, `title` is "(1) ... - Bluesky" where "(1)" is the unread notification count. The titles are unlocalized and the string "Bluesky" is hardcoded, following the pattern of the rest of the app. Display names and post content are loaded into the title as effects. Tested: * all screens * screen changes / component mounts/unmounts * long posts with links and images * display name set/unset * spamming myself with notifications, clearing notifications * /profile/did:... links * lint (only my changed files), jest, e2e. New utilities: `useUnreadCountLabel`, `bskyTitle`, `combinedDisplayName`, `useSetTitle`. resolves: #626 #599 --- src/lib/hooks/useSetTitle.ts | 16 ++++++++++++++++ src/lib/hooks/useUnreadCountLabel.ts | 19 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/lib/hooks/useSetTitle.ts create mode 100644 src/lib/hooks/useUnreadCountLabel.ts (limited to 'src/lib/hooks') diff --git a/src/lib/hooks/useSetTitle.ts b/src/lib/hooks/useSetTitle.ts new file mode 100644 index 000000000..85ba44d29 --- /dev/null +++ b/src/lib/hooks/useSetTitle.ts @@ -0,0 +1,16 @@ +import {useEffect} from 'react' +import {useNavigation} from '@react-navigation/native' + +import {NavigationProp} from 'lib/routes/types' +import {bskyTitle} from 'lib/strings/headings' +import {useUnreadCountLabel} from './useUnreadCountLabel' + +export function useSetTitle(title?: string) { + const navigation = useNavigation() + const unreadCountLabel = useUnreadCountLabel() + useEffect(() => { + if (title) { + navigation.setOptions({title: bskyTitle(title, unreadCountLabel)}) + } + }, [title, navigation, unreadCountLabel]) +} diff --git a/src/lib/hooks/useUnreadCountLabel.ts b/src/lib/hooks/useUnreadCountLabel.ts new file mode 100644 index 000000000..e2bf77885 --- /dev/null +++ b/src/lib/hooks/useUnreadCountLabel.ts @@ -0,0 +1,19 @@ +import {useEffect, useReducer} from 'react' +import {DeviceEventEmitter} from 'react-native' +import {useStores} from 'state/index' + +export function useUnreadCountLabel() { + // HACK: We don't have anything like Redux selectors, + // and we don't want to use + // to react to the whole store + const [, forceUpdate] = useReducer(x => x + 1, 0) + useEffect(() => { + const subscription = DeviceEventEmitter.addListener( + 'unread-notifications', + forceUpdate, + ) + return () => subscription?.remove() + }, [forceUpdate]) + + return useStores().me.notifications.unreadCountLabel +} -- cgit 1.4.1 From 41f3a0551511c7141aa416efe92130c4bf020214 Mon Sep 17 00:00:00 2001 From: LW Date: Wed, 17 May 2023 07:50:28 -0700 Subject: style: remove `useUnreadCountLabel` hack from `50c1841` (#655) (#686) I just realized how `mobx` works (never used before lol) and now I feel dumb. --- src/Navigation.tsx | 7 +++---- src/lib/hooks/useSetTitle.ts | 8 ++++++-- src/lib/hooks/useUnreadCountLabel.ts | 19 ------------------- 3 files changed, 9 insertions(+), 25 deletions(-) delete mode 100644 src/lib/hooks/useUnreadCountLabel.ts (limited to 'src/lib/hooks') diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 17bb3c159..09631701f 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -28,7 +28,6 @@ import {isNative} from 'platform/detection' import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' import {router} from './routes' import {usePalette} from 'lib/hooks/usePalette' -import {useUnreadCountLabel} from 'lib/hooks/useUnreadCountLabel' import {useStores} from './state' import {HomeScreen} from './view/screens/Home' @@ -296,9 +295,9 @@ const MyProfileTabNavigator = observer(() => { * The FlatNavigator is used by Web to represent the routes * in a single ("flat") stack. */ -function FlatNavigator() { +const FlatNavigator = observer(() => { const pal = usePalette('default') - const unreadCountLabel = useUnreadCountLabel() + const unreadCountLabel = useStores().me.notifications.unreadCountLabel const title = (page: string) => bskyTitle(page, unreadCountLabel) return ( ) -} +}) /** * The RoutesContainer should wrap all components which need access diff --git a/src/lib/hooks/useSetTitle.ts b/src/lib/hooks/useSetTitle.ts index 85ba44d29..c5c7a5ca1 100644 --- a/src/lib/hooks/useSetTitle.ts +++ b/src/lib/hooks/useSetTitle.ts @@ -3,11 +3,15 @@ import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' import {bskyTitle} from 'lib/strings/headings' -import {useUnreadCountLabel} from './useUnreadCountLabel' +import {useStores} from 'state/index' +/** + * Requires consuming component to be wrapped in `observer`: + * https://stackoverflow.com/a/71488009 + */ export function useSetTitle(title?: string) { const navigation = useNavigation() - const unreadCountLabel = useUnreadCountLabel() + const {unreadCountLabel} = useStores().me.notifications useEffect(() => { if (title) { navigation.setOptions({title: bskyTitle(title, unreadCountLabel)}) diff --git a/src/lib/hooks/useUnreadCountLabel.ts b/src/lib/hooks/useUnreadCountLabel.ts deleted file mode 100644 index e2bf77885..000000000 --- a/src/lib/hooks/useUnreadCountLabel.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {useEffect, useReducer} from 'react' -import {DeviceEventEmitter} from 'react-native' -import {useStores} from 'state/index' - -export function useUnreadCountLabel() { - // HACK: We don't have anything like Redux selectors, - // and we don't want to use - // to react to the whole store - const [, forceUpdate] = useReducer(x => x + 1, 0) - useEffect(() => { - const subscription = DeviceEventEmitter.addListener( - 'unread-notifications', - forceUpdate, - ) - return () => subscription?.remove() - }, [forceUpdate]) - - return useStores().me.notifications.unreadCountLabel -} -- cgit 1.4.1