From 7158157f5fe07b8f97842736ea87b598baabb7da Mon Sep 17 00:00:00 2001 From: Noritada Kobayashi Date: Wed, 8 Nov 2023 02:56:44 +0900 Subject: [PATCH 1/2] Correct meta tag attributes (#1829) --- bskyweb/templates/base.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bskyweb/templates/base.html b/bskyweb/templates/base.html index 7eeb7e4cc1..b03fbbee4e 100644 --- a/bskyweb/templates/base.html +++ b/bskyweb/templates/base.html @@ -176,8 +176,8 @@ {% block html_head_extra -%}{%- endblock %} - - + + {%- block body_all %} From bfe196bac5e618bfbeab4f6fabef3e5a18194868 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 7 Nov 2023 13:37:47 -0600 Subject: [PATCH 2/2] Extract shell state into separate context (#1824) * WIP * Add shell state * Integrate new shell state for drawer and minimal shell mode * Replace isDrawerSwipeDisabled * Split shell state into separate contexts to avoid needless re-renders * Fix typo --------- Co-authored-by: Paul Frazee --- src/App.native.tsx | 31 +++++++++------- src/App.web.tsx | 31 +++++++++------- src/lib/hooks/useAccountSwitcher.ts | 6 ++- src/lib/hooks/useMinimalShellMode.tsx | 10 +++-- src/lib/hooks/useOnMainScroll.ts | 31 +++++++++------- src/lib/routes/back-handler.ts | 19 ---------- src/state/models/ui/shell.ts | 26 ------------- src/state/shell/drawer-open.tsx | 24 ++++++++++++ src/state/shell/drawer-swipe-disabled.tsx | 24 ++++++++++++ src/state/shell/index.tsx | 21 +++++++++++ src/state/shell/minimal-mode.tsx | 24 ++++++++++++ src/view/com/auth/LoggedOut.tsx | 6 ++- src/view/com/auth/Onboarding.tsx | 6 ++- src/view/com/feeds/FeedPage.tsx | 2 +- src/view/com/pager/FeedsTabBarMobile.tsx | 12 +++--- src/view/com/profile/ProfileSubpageHeader.tsx | 6 ++- src/view/com/search/HeaderWithInput.tsx | 8 ++-- src/view/com/util/SimpleViewHeader.tsx | 8 ++-- src/view/com/util/ViewHeader.tsx | 8 ++-- src/view/screens/AppPasswords.tsx | 6 ++- src/view/screens/CommunityGuidelines.tsx | 8 ++-- src/view/screens/CopyrightPolicy.tsx | 8 ++-- src/view/screens/Feeds.tsx | 6 ++- src/view/screens/Home.tsx | 17 +++++---- src/view/screens/LanguageSettings.tsx | 6 ++- src/view/screens/Lists.tsx | 6 ++- src/view/screens/Log.tsx | 8 ++-- src/view/screens/Moderation.tsx | 6 ++- .../screens/ModerationBlockedAccounts.tsx | 6 ++- src/view/screens/ModerationModlists.tsx | 6 ++- src/view/screens/ModerationMutedAccounts.tsx | 6 ++- src/view/screens/NotFound.tsx | 8 ++-- src/view/screens/Notifications.tsx | 9 +++-- src/view/screens/PostLikedBy.tsx | 8 ++-- src/view/screens/PostRepostedBy.tsx | 8 ++-- src/view/screens/PostThread.tsx | 9 +++-- src/view/screens/PrivacyPolicy.tsx | 8 ++-- src/view/screens/Profile.tsx | 6 ++- src/view/screens/ProfileFeedLikedBy.tsx | 8 ++-- src/view/screens/ProfileFollowers.tsx | 8 ++-- src/view/screens/ProfileFollows.tsx | 8 ++-- src/view/screens/ProfileList.tsx | 6 ++- src/view/screens/SavedFeeds.tsx | 6 ++- src/view/screens/SearchMobile.tsx | 24 ++++++++---- src/view/screens/Settings.tsx | 6 ++- src/view/screens/Support.tsx | 8 ++-- src/view/screens/TermsOfService.tsx | 8 ++-- src/view/shell/Drawer.tsx | 23 +++++++----- src/view/shell/bottom-bar/BottomBar.tsx | 4 +- src/view/shell/index.tsx | 37 +++++++++++++------ src/view/shell/index.web.tsx | 10 +++-- 51 files changed, 367 insertions(+), 237 deletions(-) delete mode 100644 src/lib/routes/back-handler.ts create mode 100644 src/state/shell/drawer-open.tsx create mode 100644 src/state/shell/drawer-swipe-disabled.tsx create mode 100644 src/state/shell/index.tsx create mode 100644 src/state/shell/minimal-mode.tsx diff --git a/src/App.native.tsx b/src/App.native.tsx index 3250ea563b..a99dbc9515 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -19,6 +19,7 @@ import * as analytics from 'lib/analytics/analytics' import * as Toast from 'view/com/util/Toast' import {queryClient} from 'lib/react-query' import {TestCtrls} from 'view/com/testing/TestCtrls' +import {Provider as ShellStateProvider} from 'state/shell' SplashScreen.preventAutoHideAsync() @@ -44,20 +45,22 @@ const App = observer(function AppImpl() { return null } return ( - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ) }) diff --git a/src/App.web.tsx b/src/App.web.tsx index 3b67af0dcd..6bbc2065db 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -14,6 +14,7 @@ import {Shell} from 'view/shell/index' import {ToastContainer} from 'view/com/util/Toast.web' import {ThemeProvider} from 'lib/ThemeContext' import {queryClient} from 'lib/react-query' +import {Provider as ShellStateProvider} from 'state/shell' const App = observer(function AppImpl() { const [rootStore, setRootStore] = useState( @@ -34,20 +35,22 @@ const App = observer(function AppImpl() { } return ( - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + ) }) diff --git a/src/lib/hooks/useAccountSwitcher.ts b/src/lib/hooks/useAccountSwitcher.ts index 85bd5d0d45..1ddb181a85 100644 --- a/src/lib/hooks/useAccountSwitcher.ts +++ b/src/lib/hooks/useAccountSwitcher.ts @@ -6,6 +6,7 @@ import {NavigationProp} from 'lib/routes/types' import {AccountData} from 'state/models/session' import {reset as resetNavigation} from '../../Navigation' import * as Toast from 'view/com/util/Toast' +import {useSetDrawerOpen} from '#/state/shell/drawer-open' export function useAccountSwitcher(): [ boolean, @@ -13,8 +14,8 @@ export function useAccountSwitcher(): [ (acct: AccountData) => Promise, ] { const {track} = useAnalytics() - const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const [isSwitching, setIsSwitching] = useState(false) const navigation = useNavigation() @@ -23,6 +24,7 @@ export function useAccountSwitcher(): [ track('Settings:SwitchAccountButtonClicked') setIsSwitching(true) const success = await store.session.resumeSession(acct) + setDrawerOpen(false) store.shell.closeAllActiveElements() if (success) { resetNavigation() @@ -34,7 +36,7 @@ export function useAccountSwitcher(): [ store.session.clear() } }, - [track, setIsSwitching, navigation, store], + [track, setIsSwitching, navigation, store, setDrawerOpen], ) return [isSwitching, setIsSwitching, onPressSwitchAccount] diff --git a/src/lib/hooks/useMinimalShellMode.tsx b/src/lib/hooks/useMinimalShellMode.tsx index 475d165d3f..ada934a263 100644 --- a/src/lib/hooks/useMinimalShellMode.tsx +++ b/src/lib/hooks/useMinimalShellMode.tsx @@ -1,6 +1,5 @@ import React from 'react' import {autorun} from 'mobx' -import {useStores} from 'state/index' import { Easing, interpolate, @@ -9,8 +8,10 @@ import { withTiming, } from 'react-native-reanimated' +import {useMinimalShellMode as useMinimalShellModeState} from '#/state/shell/minimal-mode' + export function useMinimalShellMode() { - const store = useStores() + const minimalShellMode = useMinimalShellModeState() const minimalShellInterp = useSharedValue(0) const footerMinimalShellTransform = useAnimatedStyle(() => { return { @@ -38,7 +39,7 @@ export function useMinimalShellMode() { React.useEffect(() => { return autorun(() => { - if (store.shell.minimalShellMode) { + if (minimalShellMode) { minimalShellInterp.value = withTiming(1, { duration: 125, easing: Easing.bezier(0.25, 0.1, 0.25, 1), @@ -50,9 +51,10 @@ export function useMinimalShellMode() { }) } }) - }, [minimalShellInterp, store.shell.minimalShellMode]) + }, [minimalShellInterp, minimalShellMode]) return { + minimalShellMode, footerMinimalShellTransform, headerMinimalShellTransform, fabMinimalShellTransform, diff --git a/src/lib/hooks/useOnMainScroll.ts b/src/lib/hooks/useOnMainScroll.ts index 250ef3a364..2eab4b250f 100644 --- a/src/lib/hooks/useOnMainScroll.ts +++ b/src/lib/hooks/useOnMainScroll.ts @@ -1,8 +1,8 @@ import {useState, useCallback, useRef} from 'react' import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native' -import {RootStoreModel} from 'state/index' import {s} from 'lib/styles' import {useWebMediaQueries} from './useWebMediaQueries' +import {useSetMinimalShellMode, useMinimalShellMode} from '#/state/shell' const Y_LIMIT = 10 @@ -19,12 +19,12 @@ export type OnScrollCb = ( ) => void export type ResetCb = () => void -export function useOnMainScroll( - store: RootStoreModel, -): [OnScrollCb, boolean, ResetCb] { +export function useOnMainScroll(): [OnScrollCb, boolean, ResetCb] { let lastY = useRef(0) let [isScrolledDown, setIsScrolledDown] = useState(false) const {dyLimitUp, dyLimitDown} = useDeviceLimits() + const minimalShellMode = useMinimalShellMode() + const setMinimalShellMode = useSetMinimalShellMode() return [ useCallback( @@ -33,13 +33,10 @@ export function useOnMainScroll( const dy = y - (lastY.current || 0) lastY.current = y - if (!store.shell.minimalShellMode && dy > dyLimitDown && y > Y_LIMIT) { - store.shell.setMinimalShellMode(true) - } else if ( - store.shell.minimalShellMode && - (dy < dyLimitUp * -1 || y <= Y_LIMIT) - ) { - store.shell.setMinimalShellMode(false) + if (!minimalShellMode && dy > dyLimitDown && y > Y_LIMIT) { + setMinimalShellMode(true) + } else if (minimalShellMode && (dy < dyLimitUp * -1 || y <= Y_LIMIT)) { + setMinimalShellMode(false) } if ( @@ -54,13 +51,19 @@ export function useOnMainScroll( setIsScrolledDown(false) } }, - [store.shell, dyLimitDown, dyLimitUp, isScrolledDown], + [ + dyLimitDown, + dyLimitUp, + isScrolledDown, + minimalShellMode, + setMinimalShellMode, + ], ), isScrolledDown, useCallback(() => { setIsScrolledDown(false) - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) lastY.current = 1e8 // NOTE we set this very high so that the onScroll logic works right -prf - }, [store, setIsScrolledDown]), + }, [setIsScrolledDown, setMinimalShellMode]), ] } diff --git a/src/lib/routes/back-handler.ts b/src/lib/routes/back-handler.ts deleted file mode 100644 index aae2f2c24e..0000000000 --- a/src/lib/routes/back-handler.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {isAndroid} from 'platform/detection' -import {BackHandler} from 'react-native' -import {RootStoreModel} from 'state/index' - -export function init(store: RootStoreModel) { - // only register back handler on android, otherwise it throws an error - if (isAndroid) { - const backHandler = BackHandler.addEventListener( - 'hardwareBackPress', - () => { - return store.shell.closeAnyActiveElement() - }, - ) - return () => { - backHandler.remove() - } - } - return () => {} -} diff --git a/src/state/models/ui/shell.ts b/src/state/models/ui/shell.ts index 9c0cc6e307..d690b9331a 100644 --- a/src/state/models/ui/shell.ts +++ b/src/state/models/ui/shell.ts @@ -266,9 +266,6 @@ export interface ComposerOpts { export class ShellUiModel { colorMode: ColorMode = 'system' - minimalShellMode = false - isDrawerOpen = false - isDrawerSwipeDisabled = false isModalActive = false activeModals: Modal[] = [] isLightboxActive = false @@ -313,10 +310,6 @@ export class ShellUiModel { } } - setMinimalShellMode(v: boolean) { - this.minimalShellMode = v - } - /** * returns true if something was closed * (used by the android hardware back btn) @@ -334,10 +327,6 @@ export class ShellUiModel { this.closeComposer() return true } - if (this.isDrawerOpen) { - this.closeDrawer() - return true - } return false } @@ -354,21 +343,6 @@ export class ShellUiModel { if (this.isComposerActive) { this.closeComposer() } - if (this.isDrawerOpen) { - this.closeDrawer() - } - } - - openDrawer() { - this.isDrawerOpen = true - } - - closeDrawer() { - this.isDrawerOpen = false - } - - setIsDrawerSwipeDisabled(v: boolean) { - this.isDrawerSwipeDisabled = v } openModal(modal: Modal) { diff --git a/src/state/shell/drawer-open.tsx b/src/state/shell/drawer-open.tsx new file mode 100644 index 0000000000..a2322f6806 --- /dev/null +++ b/src/state/shell/drawer-open.tsx @@ -0,0 +1,24 @@ +import React from 'react' + +type StateContext = boolean +type SetContext = (v: boolean) => void + +const stateContext = React.createContext(false) +const setContext = React.createContext((_: boolean) => {}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(false) + return ( + + {children} + + ) +} + +export function useIsDrawerOpen() { + return React.useContext(stateContext) +} + +export function useSetDrawerOpen() { + return React.useContext(setContext) +} diff --git a/src/state/shell/drawer-swipe-disabled.tsx b/src/state/shell/drawer-swipe-disabled.tsx new file mode 100644 index 0000000000..d3f09f2a8b --- /dev/null +++ b/src/state/shell/drawer-swipe-disabled.tsx @@ -0,0 +1,24 @@ +import React from 'react' + +type StateContext = boolean +type SetContext = (v: boolean) => void + +const stateContext = React.createContext(false) +const setContext = React.createContext((_: boolean) => {}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(false) + return ( + + {children} + + ) +} + +export function useIsDrawerSwipeDisabled() { + return React.useContext(stateContext) +} + +export function useSetDrawerSwipeDisabled() { + return React.useContext(setContext) +} diff --git a/src/state/shell/index.tsx b/src/state/shell/index.tsx new file mode 100644 index 0000000000..ac2f24b4a9 --- /dev/null +++ b/src/state/shell/index.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import {Provider as DrawerOpenProvider} from './drawer-open' +import {Provider as DrawerSwipableProvider} from './drawer-swipe-disabled' +import {Provider as MinimalModeProvider} from './minimal-mode' + +export {useIsDrawerOpen, useSetDrawerOpen} from './drawer-open' +export { + useIsDrawerSwipeDisabled, + useSetDrawerSwipeDisabled, +} from './drawer-swipe-disabled' +export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode' + +export function Provider({children}: React.PropsWithChildren<{}>) { + return ( + + + {children} + + + ) +} diff --git a/src/state/shell/minimal-mode.tsx b/src/state/shell/minimal-mode.tsx new file mode 100644 index 0000000000..4909a9a651 --- /dev/null +++ b/src/state/shell/minimal-mode.tsx @@ -0,0 +1,24 @@ +import React from 'react' + +type StateContext = boolean +type SetContext = (v: boolean) => void + +const stateContext = React.createContext(false) +const setContext = React.createContext((_: boolean) => {}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(false) + return ( + + {children} + + ) +} + +export function useMinimalShellMode() { + return React.useContext(stateContext) +} + +export function useSetMinimalShellMode() { + return React.useContext(setContext) +} diff --git a/src/view/com/auth/LoggedOut.tsx b/src/view/com/auth/LoggedOut.tsx index c74c2aa33e..3e2c9c1bff 100644 --- a/src/view/com/auth/LoggedOut.tsx +++ b/src/view/com/auth/LoggedOut.tsx @@ -9,6 +9,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {useStores} from 'state/index' import {useAnalytics} from 'lib/analytics/analytics' import {SplashScreen} from './SplashScreen' +import {useSetMinimalShellMode} from '#/state/shell/minimal-mode' enum ScreenState { S_LoginOrCreateAccount, @@ -19,6 +20,7 @@ enum ScreenState { export const LoggedOut = observer(function LoggedOutImpl() { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {screen} = useAnalytics() const [screenState, setScreenState] = React.useState( ScreenState.S_LoginOrCreateAccount, @@ -26,8 +28,8 @@ export const LoggedOut = observer(function LoggedOutImpl() { React.useEffect(() => { screen('Login') - store.shell.setMinimalShellMode(true) - }, [store, screen]) + setMinimalShellMode(true) + }, [screen, setMinimalShellMode]) if ( store.session.isResumingSession || diff --git a/src/view/com/auth/Onboarding.tsx b/src/view/com/auth/Onboarding.tsx index a36544a037..bec1dc236a 100644 --- a/src/view/com/auth/Onboarding.tsx +++ b/src/view/com/auth/Onboarding.tsx @@ -8,14 +8,16 @@ import {useStores} from 'state/index' import {Welcome} from './onboarding/Welcome' import {RecommendedFeeds} from './onboarding/RecommendedFeeds' import {RecommendedFollows} from './onboarding/RecommendedFollows' +import {useSetMinimalShellMode} from '#/state/shell/minimal-mode' export const Onboarding = observer(function OnboardingImpl() { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() React.useEffect(() => { - store.shell.setMinimalShellMode(true) - }, [store]) + setMinimalShellMode(true) + }, [setMinimalShellMode]) const next = () => store.onboarding.next() const skip = () => store.onboarding.skip() diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx index b4d2578160..1037007b77 100644 --- a/src/view/com/feeds/FeedPage.tsx +++ b/src/view/com/feeds/FeedPage.tsx @@ -38,7 +38,7 @@ export const FeedPage = observer(function FeedPageImpl({ const store = useStores() const pal = usePalette('default') const {isDesktop} = useWebMediaQueries() - const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll(store) + const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const {screen, track} = useAnalytics() const headerOffset = useHeaderOffset() const scrollElRef = React.useRef(null) diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx index d5de870819..9848ce2d51 100644 --- a/src/view/com/pager/FeedsTabBarMobile.tsx +++ b/src/view/com/pager/FeedsTabBarMobile.tsx @@ -13,21 +13,23 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {s} from 'lib/styles' import {HITSLOP_10} from 'lib/constants' -import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' import Animated from 'react-native-reanimated' +import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' +import {useSetDrawerOpen} from '#/state/shell/drawer-open' export const FeedsTabBar = observer(function FeedsTabBarImpl( props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, ) { const pal = usePalette('default') const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const items = useHomeTabs(store.preferences.pinnedFeeds) const brandBlue = useColorSchemeStyle(s.brandBlue, s.blue3) - const {headerMinimalShellTransform} = useMinimalShellMode() + const {minimalShellMode, headerMinimalShellTransform} = useMinimalShellMode() const onPressAvi = React.useCallback(() => { - store.shell.openDrawer() - }, [store]) + setDrawerOpen(true) + }, [setDrawerOpen]) return ( diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx index 8e957728bd..0b8015aa92 100644 --- a/src/view/com/profile/ProfileSubpageHeader.tsx +++ b/src/view/com/profile/ProfileSubpageHeader.tsx @@ -17,6 +17,7 @@ import {NavigationProp} from 'lib/routes/types' import {BACK_HITSLOP} from 'lib/constants' import {isNative} from 'platform/detection' import {ImagesLightbox} from 'state/models/ui/shell' +import {useSetDrawerOpen} from '#/state/shell' export const ProfileSubpageHeader = observer(function HeaderImpl({ isLoading, @@ -42,6 +43,7 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({ avatarType: UserAvatarType }>) { const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const navigation = useNavigation() const {isMobile} = useWebMediaQueries() const pal = usePalette('default') @@ -56,8 +58,8 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({ }, [navigation]) const onPressMenu = React.useCallback(() => { - store.shell.openDrawer() - }, [store]) + setDrawerOpen(true) + }, [setDrawerOpen]) const onPressAvi = React.useCallback(() => { if ( diff --git a/src/view/com/search/HeaderWithInput.tsx b/src/view/com/search/HeaderWithInput.tsx index 6bd1b2f00b..1a6b427c61 100644 --- a/src/view/com/search/HeaderWithInput.tsx +++ b/src/view/com/search/HeaderWithInput.tsx @@ -8,10 +8,10 @@ import {Text} from 'view/com/util/text/Text' import {MagnifyingGlassIcon} from 'lib/icons' import {useTheme} from 'lib/ThemeContext' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {useAnalytics} from 'lib/analytics/analytics' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {HITSLOP_10} from 'lib/constants' +import {useSetDrawerOpen} from '#/state/shell' interface Props { isInputFocused: boolean @@ -33,7 +33,7 @@ export function HeaderWithInput({ onSubmitQuery, showMenu = true, }: Props) { - const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const theme = useTheme() const pal = usePalette('default') const {track} = useAnalytics() @@ -42,8 +42,8 @@ export function HeaderWithInput({ const onPressMenu = React.useCallback(() => { track('ViewHeader:MenuButtonClicked') - store.shell.openDrawer() - }, [track, store]) + setDrawerOpen(true) + }, [track, setDrawerOpen]) const onPressCancelSearchInner = React.useCallback(() => { onPressCancelSearch() diff --git a/src/view/com/util/SimpleViewHeader.tsx b/src/view/com/util/SimpleViewHeader.tsx index 4eff38a315..c871d94042 100644 --- a/src/view/com/util/SimpleViewHeader.tsx +++ b/src/view/com/util/SimpleViewHeader.tsx @@ -10,11 +10,11 @@ import { import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' import {CenteredView} from './Views' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useAnalytics} from 'lib/analytics/analytics' import {NavigationProp} from 'lib/routes/types' +import {useSetDrawerOpen} from '#/state/shell' const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} @@ -27,7 +27,7 @@ export const SimpleViewHeader = observer(function SimpleViewHeaderImpl({ style?: StyleProp }>) { const pal = usePalette('default') - const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const navigation = useNavigation() const {track} = useAnalytics() const {isMobile} = useWebMediaQueries() @@ -43,8 +43,8 @@ export const SimpleViewHeader = observer(function SimpleViewHeaderImpl({ const onPressMenu = React.useCallback(() => { track('ViewHeader:MenuButtonClicked') - store.shell.openDrawer() - }, [track, store]) + setDrawerOpen(true) + }, [track, setDrawerOpen]) const Container = isMobile ? View : CenteredView return ( diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 4cc9efb78d..adf2e4f087 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -5,13 +5,13 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' import {CenteredView} from './Views' import {Text} from './text/Text' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useAnalytics} from 'lib/analytics/analytics' import {NavigationProp} from 'lib/routes/types' import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' import Animated from 'react-native-reanimated' +import {useSetDrawerOpen} from '#/state/shell' const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} @@ -33,7 +33,7 @@ export const ViewHeader = observer(function ViewHeaderImpl({ renderButton?: () => JSX.Element }) { const pal = usePalette('default') - const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const navigation = useNavigation() const {track} = useAnalytics() const {isDesktop, isTablet} = useWebMediaQueries() @@ -48,8 +48,8 @@ export const ViewHeader = observer(function ViewHeaderImpl({ const onPressMenu = React.useCallback(() => { track('ViewHeader:MenuButtonClicked') - store.shell.openDrawer() - }, [track, store]) + setDrawerOpen(true) + }, [track, setDrawerOpen]) if (isDesktop) { if (showOnDesktop) { diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx index 32f9e13e16..74d293ef4a 100644 --- a/src/view/screens/AppPasswords.tsx +++ b/src/view/screens/AppPasswords.tsx @@ -16,20 +16,22 @@ import {useAnalytics} from 'lib/analytics/analytics' import {useFocusEffect} from '@react-navigation/native' import {ViewHeader} from '../com/util/ViewHeader' import {CenteredView} from 'view/com/util/Views' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const AppPasswords = withAuthRequired( observer(function AppPasswordsImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {screen} = useAnalytics() const {isTabletOrDesktop} = useWebMediaQueries() useFocusEffect( React.useCallback(() => { screen('AppPasswords') - store.shell.setMinimalShellMode(false) - }, [screen, store]), + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), ) const onAdd = React.useCallback(async () => { diff --git a/src/view/screens/CommunityGuidelines.tsx b/src/view/screens/CommunityGuidelines.tsx index e80eba905d..712172c3bb 100644 --- a/src/view/screens/CommunityGuidelines.tsx +++ b/src/view/screens/CommunityGuidelines.tsx @@ -5,10 +5,10 @@ import {Text} from 'view/com/util/text/Text' import {TextLink} from 'view/com/util/Link' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' -import {useStores} from 'state/index' import {ScrollView} from 'view/com/util/Views' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps< CommonNavigatorParams, @@ -16,12 +16,12 @@ type Props = NativeStackScreenProps< > export const CommunityGuidelinesScreen = (_props: Props) => { const pal = usePalette('default') - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/CopyrightPolicy.tsx b/src/view/screens/CopyrightPolicy.tsx index 9de4dc9e72..816c1c1eeb 100644 --- a/src/view/screens/CopyrightPolicy.tsx +++ b/src/view/screens/CopyrightPolicy.tsx @@ -5,20 +5,20 @@ import {Text} from 'view/com/util/text/Text' import {TextLink} from 'view/com/util/Link' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' -import {useStores} from 'state/index' import {ScrollView} from 'view/com/util/Views' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const CopyrightPolicyScreen = (_props: Props) => { const pal = usePalette('default') - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index 3ef5b4d864..169660a8f3 100644 --- a/src/view/screens/Feeds.tsx +++ b/src/view/screens/Feeds.tsx @@ -27,12 +27,14 @@ import {FeedSourceModel} from 'state/models/content/feed-source' import {FlatList} from 'view/com/util/Views' import {useFocusEffect} from '@react-navigation/native' import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const FeedsScreen = withAuthRequired( observer(function FeedsScreenImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {isMobile, isTabletOrDesktop} = useWebMediaQueries() const myFeeds = store.me.myFeeds const [query, setQuery] = React.useState('') @@ -43,14 +45,14 @@ export const FeedsScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) myFeeds.setup() const softResetSub = store.onScreenSoftReset(() => myFeeds.refresh()) return () => { softResetSub.remove() } - }, [store, myFeeds]), + }, [store, myFeeds, setMinimalShellMode]), ) React.useEffect(() => { // watch for changes to saved/pinned feeds diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index d8bf4f637a..c581753277 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -14,6 +14,7 @@ import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager' import {useStores} from 'state/index' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {FeedPage} from 'view/com/feeds/FeedPage' +import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell' export const POLL_FREQ = 30e3 // 30sec @@ -21,6 +22,8 @@ type Props = NativeStackScreenProps export const HomeScreen = withAuthRequired( observer(function HomeScreenImpl({}: Props) { const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() + const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() const pagerRef = React.useRef(null) const [selectedPage, setSelectedPage] = React.useState(0) const [customFeeds, setCustomFeeds] = React.useState([]) @@ -61,21 +64,21 @@ export const HomeScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - store.shell.setIsDrawerSwipeDisabled(selectedPage > 0) + setMinimalShellMode(false) + setDrawerSwipeDisabled(selectedPage > 0) return () => { - store.shell.setIsDrawerSwipeDisabled(false) + setDrawerSwipeDisabled(false) } - }, [store, selectedPage]), + }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]), ) const onPageSelected = React.useCallback( (index: number) => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) setSelectedPage(index) - store.shell.setIsDrawerSwipeDisabled(index > 0) + setDrawerSwipeDisabled(index > 0) }, - [store, setSelectedPage], + [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode], ) const onPressSelected = React.useCallback(() => { diff --git a/src/view/screens/LanguageSettings.tsx b/src/view/screens/LanguageSettings.tsx index 8b952a564d..a68a3b5e32 100644 --- a/src/view/screens/LanguageSettings.tsx +++ b/src/view/screens/LanguageSettings.tsx @@ -18,6 +18,7 @@ import {useAnalytics} from 'lib/analytics/analytics' import {useFocusEffect} from '@react-navigation/native' import {LANGUAGES} from 'lib/../locale/languages' import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps @@ -28,12 +29,13 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl( const store = useStores() const {isTabletOrDesktop} = useWebMediaQueries() const {screen, track} = useAnalytics() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { screen('Settings') - store.shell.setMinimalShellMode(false) - }, [screen, store]), + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), ) const onPressContentLanguages = React.useCallback(() => { diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx index c798b9087b..a64b0ca3b3 100644 --- a/src/view/screens/Lists.tsx +++ b/src/view/screens/Lists.tsx @@ -16,12 +16,14 @@ import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ListsScreen = withAuthRequired( observer(function ListsScreenImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {isMobile} = useWebMediaQueries() const navigation = useNavigation() @@ -32,9 +34,9 @@ export const ListsScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) listsLists.refresh() - }, [store, listsLists]), + }, [listsLists, setMinimalShellMode]), ) const onPressNewList = React.useCallback(() => { diff --git a/src/view/screens/Log.tsx b/src/view/screens/Log.tsx index 6ae61888d2..f524279a50 100644 --- a/src/view/screens/Log.tsx +++ b/src/view/screens/Log.tsx @@ -5,26 +5,26 @@ import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ScrollView} from '../com/util/Views' -import {useStores} from 'state/index' import {s} from 'lib/styles' import {ViewHeader} from '../com/util/ViewHeader' import {Text} from '../com/util/text/Text' import {usePalette} from 'lib/hooks/usePalette' import {getEntries} from '#/logger/logDump' import {ago} from 'lib/strings/time' +import {useSetMinimalShellMode} from '#/state/shell' export const LogScreen = observer(function Log({}: NativeStackScreenProps< CommonNavigatorParams, 'Log' >) { const pal = usePalette('default') - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const [expanded, setExpanded] = React.useState([]) useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) const toggler = (id: string) => () => { diff --git a/src/view/screens/Moderation.tsx b/src/view/screens/Moderation.tsx index d24bc145a5..142f3bce8d 100644 --- a/src/view/screens/Moderation.tsx +++ b/src/view/screens/Moderation.tsx @@ -17,20 +17,22 @@ import {Text} from '../com/util/text/Text' import {usePalette} from 'lib/hooks/usePalette' import {useAnalytics} from 'lib/analytics/analytics' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ModerationScreen = withAuthRequired( observer(function Moderation({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {screen, track} = useAnalytics() const {isTabletOrDesktop} = useWebMediaQueries() useFocusEffect( React.useCallback(() => { screen('Moderation') - store.shell.setMinimalShellMode(false) - }, [screen, store]), + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), ) const onPressContentFiltering = React.useCallback(() => { diff --git a/src/view/screens/ModerationBlockedAccounts.tsx b/src/view/screens/ModerationBlockedAccounts.tsx index f302c96b5b..0dc3b706bd 100644 --- a/src/view/screens/ModerationBlockedAccounts.tsx +++ b/src/view/screens/ModerationBlockedAccounts.tsx @@ -22,6 +22,7 @@ import {ViewHeader} from '../com/util/ViewHeader' import {CenteredView} from 'view/com/util/Views' import {ProfileCard} from 'view/com/profile/ProfileCard' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps< CommonNavigatorParams, @@ -31,6 +32,7 @@ export const ModerationBlockedAccounts = withAuthRequired( observer(function ModerationBlockedAccountsImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {isTabletOrDesktop} = useWebMediaQueries() const {screen} = useAnalytics() const blockedAccounts = useMemo( @@ -41,9 +43,9 @@ export const ModerationBlockedAccounts = withAuthRequired( useFocusEffect( React.useCallback(() => { screen('BlockedAccounts') - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) blockedAccounts.refresh() - }, [screen, store, blockedAccounts]), + }, [screen, setMinimalShellMode, blockedAccounts]), ) const onRefresh = React.useCallback(() => { diff --git a/src/view/screens/ModerationModlists.tsx b/src/view/screens/ModerationModlists.tsx index 6a48d88ae7..8794c6d176 100644 --- a/src/view/screens/ModerationModlists.tsx +++ b/src/view/screens/ModerationModlists.tsx @@ -16,12 +16,14 @@ import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ModerationModlistsScreen = withAuthRequired( observer(function ModerationModlistsScreenImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {isMobile} = useWebMediaQueries() const navigation = useNavigation() @@ -32,9 +34,9 @@ export const ModerationModlistsScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) mutelists.refresh() - }, [store, mutelists]), + }, [mutelists, setMinimalShellMode]), ) const onPressNewList = React.useCallback(() => { diff --git a/src/view/screens/ModerationMutedAccounts.tsx b/src/view/screens/ModerationMutedAccounts.tsx index 20bd21f37a..2fa27ee54f 100644 --- a/src/view/screens/ModerationMutedAccounts.tsx +++ b/src/view/screens/ModerationMutedAccounts.tsx @@ -22,6 +22,7 @@ import {ViewHeader} from '../com/util/ViewHeader' import {CenteredView} from 'view/com/util/Views' import {ProfileCard} from 'view/com/profile/ProfileCard' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps< CommonNavigatorParams, @@ -31,6 +32,7 @@ export const ModerationMutedAccounts = withAuthRequired( observer(function ModerationMutedAccountsImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {isTabletOrDesktop} = useWebMediaQueries() const {screen} = useAnalytics() const mutedAccounts = useMemo(() => new MutedAccountsModel(store), [store]) @@ -38,9 +40,9 @@ export const ModerationMutedAccounts = withAuthRequired( useFocusEffect( React.useCallback(() => { screen('MutedAccounts') - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) mutedAccounts.refresh() - }, [screen, store, mutedAccounts]), + }, [screen, setMinimalShellMode, mutedAccounts]), ) const onRefresh = React.useCallback(() => { diff --git a/src/view/screens/NotFound.tsx b/src/view/screens/NotFound.tsx index cb52da58b3..c2125756cd 100644 --- a/src/view/screens/NotFound.tsx +++ b/src/view/screens/NotFound.tsx @@ -10,18 +10,18 @@ import {Text} from '../com/util/text/Text' import {Button} from 'view/com/util/forms/Button' import {NavigationProp} from 'lib/routes/types' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' export const NotFoundScreen = () => { const pal = usePalette('default') const navigation = useNavigation() - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) const canGoBack = navigation.canGoBack() diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx index e1137ae9d5..cd482bd1c4 100644 --- a/src/view/screens/Notifications.tsx +++ b/src/view/screens/Notifications.tsx @@ -21,6 +21,7 @@ import {s, colors} from 'lib/styles' import {useAnalytics} from 'lib/analytics/analytics' import {isWeb} from 'platform/detection' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps< NotificationsTabNavigatorParams, @@ -29,8 +30,8 @@ type Props = NativeStackScreenProps< export const NotificationsScreen = withAuthRequired( observer(function NotificationsScreenImpl({}: Props) { const store = useStores() - const [onMainScroll, isScrolledDown, resetMainScroll] = - useOnMainScroll(store) + const setMinimalShellMode = useSetMinimalShellMode() + const [onMainScroll, isScrolledDown, resetMainScroll] = useOnMainScroll() const scrollElRef = React.useRef(null) const {screen} = useAnalytics() const pal = usePalette('default') @@ -60,7 +61,7 @@ export const NotificationsScreen = withAuthRequired( // = useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) logger.debug('NotificationsScreen: Updating feed') const softResetSub = store.onScreenSoftReset(onPressLoadLatest) store.me.notifications.update() @@ -70,7 +71,7 @@ export const NotificationsScreen = withAuthRequired( softResetSub.remove() store.me.notifications.markAllRead() } - }, [store, screen, onPressLoadLatest]), + }, [store, screen, onPressLoadLatest, setMinimalShellMode]), ) useTabFocusEffect( diff --git a/src/view/screens/PostLikedBy.tsx b/src/view/screens/PostLikedBy.tsx index fb44f1f9be..2f45908b3d 100644 --- a/src/view/screens/PostLikedBy.tsx +++ b/src/view/screens/PostLikedBy.tsx @@ -5,19 +5,19 @@ import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {ViewHeader} from '../com/util/ViewHeader' import {PostLikedBy as PostLikedByComponent} from '../com/post-thread/PostLikedBy' -import {useStores} from 'state/index' import {makeRecordUri} from 'lib/strings/url-helpers' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const PostLikedByScreen = withAuthRequired(({route}: Props) => { - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/PostRepostedBy.tsx b/src/view/screens/PostRepostedBy.tsx index 19f0af18b5..abe03467a7 100644 --- a/src/view/screens/PostRepostedBy.tsx +++ b/src/view/screens/PostRepostedBy.tsx @@ -5,19 +5,19 @@ import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' import {PostRepostedBy as PostRepostedByComponent} from '../com/post-thread/PostRepostedBy' -import {useStores} from 'state/index' import {makeRecordUri} from 'lib/strings/url-helpers' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const PostRepostedByScreen = withAuthRequired(({route}: Props) => { - const store = useStores() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index 8bb279be84..0bdd062698 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -15,6 +15,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context' import {clamp} from 'lodash' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {logger} from '#/logger' +import {useMinimalShellMode, useSetMinimalShellMode} from '#/state/shell' const SHELL_FOOTER_HEIGHT = 44 @@ -22,6 +23,8 @@ type Props = NativeStackScreenProps export const PostThreadScreen = withAuthRequired( observer(function PostThreadScreenImpl({route}: Props) { const store = useStores() + const minimalShellMode = useMinimalShellMode() + const setMinimalShellMode = useSetMinimalShellMode() const safeAreaInsets = useSafeAreaInsets() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) @@ -33,7 +36,7 @@ export const PostThreadScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) const threadCleanup = view.registerListeners() InteractionManager.runAfterInteractions(() => { @@ -47,7 +50,7 @@ export const PostThreadScreen = withAuthRequired( return () => { threadCleanup() } - }, [store, view]), + }, [view, setMinimalShellMode]), ) const onPressReply = React.useCallback(() => { @@ -80,7 +83,7 @@ export const PostThreadScreen = withAuthRequired( treeView={!!store.preferences.thread.lab_treeViewEnabled} /> - {isMobile && !store.shell.minimalShellMode && ( + {isMobile && !minimalShellMode && ( export const PrivacyPolicyScreen = (_props: Props) => { const pal = usePalette('default') - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index f183ebbc2b..9a25612add 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -30,11 +30,13 @@ import {FeedSourceModel} from 'state/models/content/feed-source' import {useSetTitle} from 'lib/hooks/useSetTitle' import {combinedDisplayName} from 'lib/strings/display-names' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ProfileScreen = withAuthRequired( observer(function ProfileScreenImpl({route}: Props) { const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {screen, track} = useAnalytics() const viewSelectorRef = React.useRef(null) const name = route.params.name === 'me' ? store.me.did : route.params.name @@ -69,7 +71,7 @@ export const ProfileScreen = withAuthRequired( React.useCallback(() => { const softResetSub = store.onScreenSoftReset(onSoftReset) let aborted = false - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) const feedCleanup = uiState.feed.registerListeners() if (!hasSetup) { uiState.setup().then(() => { @@ -84,7 +86,7 @@ export const ProfileScreen = withAuthRequired( feedCleanup() softResetSub.remove() } - }, [store, onSoftReset, uiState, hasSetup]), + }, [store, onSoftReset, uiState, hasSetup, setMinimalShellMode]), ) // events diff --git a/src/view/screens/ProfileFeedLikedBy.tsx b/src/view/screens/ProfileFeedLikedBy.tsx index 2e9d12aae3..4972116f35 100644 --- a/src/view/screens/ProfileFeedLikedBy.tsx +++ b/src/view/screens/ProfileFeedLikedBy.tsx @@ -5,19 +5,19 @@ import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {ViewHeader} from '../com/util/ViewHeader' import {PostLikedBy as PostLikedByComponent} from '../com/post-thread/PostLikedBy' -import {useStores} from 'state/index' import {makeRecordUri} from 'lib/strings/url-helpers' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => { - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {name, rkey} = route.params const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey) useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/ProfileFollowers.tsx b/src/view/screens/ProfileFollowers.tsx index e2f95fbe4f..49f55bf46b 100644 --- a/src/view/screens/ProfileFollowers.tsx +++ b/src/view/screens/ProfileFollowers.tsx @@ -5,17 +5,17 @@ import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {ViewHeader} from '../com/util/ViewHeader' import {ProfileFollowers as ProfileFollowersComponent} from '../com/profile/ProfileFollowers' -import {useStores} from 'state/index' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => { - const store = useStores() const {name} = route.params + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx index f70944f557..4f0ff7d67f 100644 --- a/src/view/screens/ProfileFollows.tsx +++ b/src/view/screens/ProfileFollows.tsx @@ -5,17 +5,17 @@ import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {ViewHeader} from '../com/util/ViewHeader' import {ProfileFollows as ProfileFollowsComponent} from '../com/profile/ProfileFollows' -import {useStores} from 'state/index' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => { - const store = useStores() const {name} = route.params + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx index 594e9fd296..b84732d532 100644 --- a/src/view/screens/ProfileList.tsx +++ b/src/view/screens/ProfileList.tsx @@ -45,6 +45,7 @@ import {makeProfileLink, makeListLink} from 'lib/routes/links' import {ComposeIcon2} from 'lib/icons' import {ListItems} from 'view/com/lists/ListItems' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_MOD = ['About'] @@ -105,6 +106,7 @@ export const ProfileListScreenInner = observer( listOwnerDid, }: Props & {listOwnerDid: string}) { const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const {rkey} = route.params const feedSectionRef = React.useRef(null) const aboutSectionRef = React.useRef(null) @@ -124,13 +126,13 @@ export const ProfileListScreenInner = observer( useFocusEffect( useCallback(() => { - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) list.loadMore(true).then(() => { if (list.isCuratelist) { feed.setup() } }) - }, [store, list, feed]), + }, [setMinimalShellMode, list, feed]), ) const onPressAddUser = useCallback(() => { diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx index 18bbf06c6e..487f566434 100644 --- a/src/view/screens/SavedFeeds.tsx +++ b/src/view/screens/SavedFeeds.tsx @@ -27,6 +27,7 @@ import * as Toast from 'view/com/util/Toast' import {Haptics} from 'lib/haptics' import {TextLink} from 'view/com/util/Link' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' const HITSLOP_TOP = { top: 20, @@ -48,6 +49,7 @@ export const SavedFeeds = withAuthRequired( const store = useStores() const {isMobile, isTabletOrDesktop} = useWebMediaQueries() const {screen} = useAnalytics() + const setMinimalShellMode = useSetMinimalShellMode() const savedFeeds = useMemo(() => { const model = new SavedFeedsModel(store) @@ -57,9 +59,9 @@ export const SavedFeeds = withAuthRequired( useFocusEffect( useCallback(() => { screen('SavedFeeds') - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) savedFeeds.refresh() - }, [screen, store, savedFeeds]), + }, [screen, setMinimalShellMode, savedFeeds]), ) return ( diff --git a/src/view/screens/SearchMobile.tsx b/src/view/screens/SearchMobile.tsx index b80c1667ff..c1df58ffdb 100644 --- a/src/view/screens/SearchMobile.tsx +++ b/src/view/screens/SearchMobile.tsx @@ -27,15 +27,18 @@ import {ProfileCard} from 'view/com/profile/ProfileCard' import {usePalette} from 'lib/hooks/usePalette' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {isAndroid, isIOS} from 'platform/detection' +import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell' type Props = NativeStackScreenProps export const SearchScreen = withAuthRequired( observer(function SearchScreenImpl({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() + const setIsDrawerSwipeDisabled = useSetDrawerSwipeDisabled() const scrollViewRef = React.useRef(null) const flatListRef = React.useRef(null) - const [onMainScroll] = useOnMainScroll(store) + const [onMainScroll] = useOnMainScroll() const [isInputFocused, setIsInputFocused] = React.useState(false) const [query, setQuery] = React.useState('') const autocompleteView = React.useMemo( @@ -75,8 +78,8 @@ export const SearchScreen = withAuthRequired( setQuery('') autocompleteView.setActive(false) setSearchUIModel(undefined) - store.shell.setIsDrawerSwipeDisabled(false) - }, [setQuery, autocompleteView, store]) + setIsDrawerSwipeDisabled(false) + }, [setQuery, autocompleteView, setIsDrawerSwipeDisabled]) const onSubmitQuery = React.useCallback(() => { if (query.length === 0) { @@ -86,8 +89,8 @@ export const SearchScreen = withAuthRequired( const model = new SearchUIModel(store) model.fetch(query) setSearchUIModel(model) - store.shell.setIsDrawerSwipeDisabled(true) - }, [query, setSearchUIModel, store]) + setIsDrawerSwipeDisabled(true) + }, [query, setSearchUIModel, store, setIsDrawerSwipeDisabled]) const onSoftReset = React.useCallback(() => { scrollViewRef.current?.scrollTo({x: 0, y: 0}) @@ -102,7 +105,7 @@ export const SearchScreen = withAuthRequired( softResetSub.remove() } - store.shell.setMinimalShellMode(false) + setMinimalShellMode(false) autocompleteView.setup() if (!foafs.hasData) { foafs.fetch() @@ -112,7 +115,14 @@ export const SearchScreen = withAuthRequired( } return cleanup - }, [store, autocompleteView, foafs, suggestedActors, onSoftReset]), + }, [ + store, + autocompleteView, + foafs, + suggestedActors, + onSoftReset, + setMinimalShellMode, + ]), ) const onPress = useCallback(() => { diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 3f498ba85a..3f957f3ffb 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -46,6 +46,7 @@ import Clipboard from '@react-native-clipboard/clipboard' import {makeProfileLink} from 'lib/routes/links' import {AccountDropdownBtn} from 'view/com/util/AccountDropdownBtn' import {logger} from '#/logger' +import {useSetMinimalShellMode} from '#/state/shell' // TEMPORARY (APP-700) // remove after backend testing finishes @@ -58,6 +59,7 @@ export const SettingsScreen = withAuthRequired( observer(function Settings({}: Props) { const pal = usePalette('default') const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() const navigation = useNavigation() const {isMobile} = useWebMediaQueries() const {screen, track} = useAnalytics() @@ -88,8 +90,8 @@ export const SettingsScreen = withAuthRequired( useFocusEffect( React.useCallback(() => { screen('Settings') - store.shell.setMinimalShellMode(false) - }, [screen, store]), + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), ) const onPressAddAccount = React.useCallback(() => { diff --git a/src/view/screens/Support.tsx b/src/view/screens/Support.tsx index dc00d473d5..7106b4136a 100644 --- a/src/view/screens/Support.tsx +++ b/src/view/screens/Support.tsx @@ -3,23 +3,23 @@ import {View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' -import {useStores} from 'state/index' import {Text} from 'view/com/util/text/Text' import {TextLink} from 'view/com/util/Link' import {CenteredView} from 'view/com/util/Views' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' import {HELP_DESK_URL} from 'lib/constants' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const SupportScreen = (_props: Props) => { - const store = useStores() const pal = usePalette('default') + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/screens/TermsOfService.tsx b/src/view/screens/TermsOfService.tsx index 09b2a7f22b..b7a388b65d 100644 --- a/src/view/screens/TermsOfService.tsx +++ b/src/view/screens/TermsOfService.tsx @@ -5,20 +5,20 @@ import {Text} from 'view/com/util/text/Text' import {TextLink} from 'view/com/util/Link' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ViewHeader} from '../com/util/ViewHeader' -import {useStores} from 'state/index' import {ScrollView} from 'view/com/util/Views' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' +import {useSetMinimalShellMode} from '#/state/shell' type Props = NativeStackScreenProps export const TermsOfServiceScreen = (_props: Props) => { const pal = usePalette('default') - const store = useStores() + const setMinimalShellMode = useSetMinimalShellMode() useFocusEffect( React.useCallback(() => { - store.shell.setMinimalShellMode(false) - }, [store]), + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) return ( diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx index c2d307f598..7f5e6c5e56 100644 --- a/src/view/shell/Drawer.tsx +++ b/src/view/shell/Drawer.tsx @@ -43,11 +43,13 @@ import {NavigationProp} from 'lib/routes/types' import {useNavigationTabState} from 'lib/hooks/useNavigationTabState' import {isWeb} from 'platform/detection' import {formatCount, formatCountShortOnly} from 'view/com/util/numeric/format' +import {useSetDrawerOpen} from '#/state/shell' export const DrawerContent = observer(function DrawerContentImpl() { const theme = useTheme() const pal = usePalette('default') const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const navigation = useNavigation() const {track} = useAnalytics() const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} = @@ -62,7 +64,7 @@ export const DrawerContent = observer(function DrawerContentImpl() { (tab: string) => { track('Menu:ItemClicked', {url: tab}) const state = navigation.getState() - store.shell.closeDrawer() + setDrawerOpen(false) if (isWeb) { // hack because we have flat navigator for web and MyProfile does not exist on the web navigator -ansh if (tab === 'MyProfile') { @@ -83,7 +85,7 @@ export const DrawerContent = observer(function DrawerContentImpl() { } } }, - [store, track, navigation], + [store, track, navigation, setDrawerOpen], ) const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab]) @@ -110,20 +112,20 @@ export const DrawerContent = observer(function DrawerContentImpl() { const onPressLists = React.useCallback(() => { track('Menu:ItemClicked', {url: 'Lists'}) navigation.navigate('Lists') - store.shell.closeDrawer() - }, [navigation, track, store.shell]) + setDrawerOpen(false) + }, [navigation, track, setDrawerOpen]) const onPressModeration = React.useCallback(() => { track('Menu:ItemClicked', {url: 'Moderation'}) navigation.navigate('Moderation') - store.shell.closeDrawer() - }, [navigation, track, store.shell]) + setDrawerOpen(false) + }, [navigation, track, setDrawerOpen]) const onPressSettings = React.useCallback(() => { track('Menu:ItemClicked', {url: 'Settings'}) navigation.navigate('Settings') - store.shell.closeDrawer() - }, [navigation, track, store.shell]) + setDrawerOpen(false) + }, [navigation, track, setDrawerOpen]) const onPressFeedback = React.useCallback(() => { track('Menu:FeedbackClicked') @@ -437,13 +439,14 @@ const InviteCodes = observer(function InviteCodesImpl({ }) { const {track} = useAnalytics() const store = useStores() + const setDrawerOpen = useSetDrawerOpen() const pal = usePalette('default') const {invitesAvailable} = store.me const onPress = React.useCallback(() => { track('Menu:ItemClicked', {url: '#invite-codes'}) - store.shell.closeDrawer() + setDrawerOpen(false) store.shell.openModal({name: 'invite-codes'}) - }, [store, track]) + }, [store, track, setDrawerOpen]) return ( , []) const onOpenDrawer = React.useCallback( - () => store.shell.openDrawer(), - [store], + () => setIsDrawerOpen(true), + [setIsDrawerOpen], ) const onCloseDrawer = React.useCallback( - () => store.shell.closeDrawer(), - [store], + () => setIsDrawerOpen(false), + [setIsDrawerOpen], ) const canGoBack = useNavigationState(state => !isStateAtTabRoot(state)) React.useEffect(() => { - const listener = backHandler.init(store) + let listener = {remove() {}} + if (isAndroid) { + listener = BackHandler.addEventListener('hardwareBackPress', () => { + setIsDrawerOpen(false) + return store.shell.closeAnyActiveElement() + }) + } return () => { - listener() + listener.remove() } - }, [store]) + }, [store, setIsDrawerOpen]) return ( <> @@ -59,14 +74,12 @@ const ShellInner = observer(function ShellInnerImpl() { diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index 3f2fed69b9..843d0b284b 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -17,18 +17,22 @@ import {BottomBarWeb} from './bottom-bar/BottomBarWeb' import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' import {useAuxClick} from 'lib/hooks/useAuxClick' +import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' const ShellInner = observer(function ShellInnerImpl() { const store = useStores() + const isDrawerOpen = useIsDrawerOpen() + const setDrawerOpen = useSetDrawerOpen() const {isDesktop, isMobile} = useWebMediaQueries() const navigator = useNavigation() useAuxClick() useEffect(() => { navigator.addListener('state', () => { + setDrawerOpen(false) store.shell.closeAnyActiveElement() }) - }, [navigator, store.shell]) + }, [navigator, store.shell, setDrawerOpen]) const showBottomBar = isMobile && !store.onboarding.isActive const showSideNavs = @@ -57,9 +61,9 @@ const ShellInner = observer(function ShellInnerImpl() { {showBottomBar && } - {!isDesktop && store.shell.isDrawerOpen && ( + {!isDesktop && isDrawerOpen && ( store.shell.closeDrawer()} + onPress={() => setDrawerOpen(false)} style={styles.drawerMask} accessibilityLabel="Close navigation footer" accessibilityHint="Closes bottom navigation bar">