[iPad support] Custom tab navigator for native tablet, with side nav (#3385)
* fix fab position
* show left nav
* custom tab navigator for tablets
* re-disable right nav on tablet
* fix unread count not being rounded
* use mobile subpage header on native tablet
* fix feed being hidden under header
* rename misleading variable name
* remove drawer on native tablet, as on web tablet
* fix prompt styles on tablet
* import isWeb (ts-ignore 😡)
* disable emoji picker on tablet
* prettier format
This commit is contained in:
+224
-42
@@ -1,5 +1,6 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import {JSX} from 'react/jsx-runtime'
|
import {JSX} from 'react/jsx-runtime'
|
||||||
|
import {View} from 'react-native'
|
||||||
import {i18n, MessageDescriptor} from '@lingui/core'
|
import {i18n, MessageDescriptor} from '@lingui/core'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {
|
import {
|
||||||
@@ -19,7 +20,7 @@ import {timeout} from '#/lib/async/timeout'
|
|||||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||||
import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration'
|
import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration'
|
||||||
import {buildStateObject} from '#/lib/routes/helpers'
|
import {buildStateObject} from '#/lib/routes/helpers'
|
||||||
import {
|
import type {
|
||||||
AllNavigatorParams,
|
AllNavigatorParams,
|
||||||
BottomTabNavigatorParams,
|
BottomTabNavigatorParams,
|
||||||
FlatNavigatorParams,
|
FlatNavigatorParams,
|
||||||
@@ -28,11 +29,12 @@ import {
|
|||||||
MyProfileTabNavigatorParams,
|
MyProfileTabNavigatorParams,
|
||||||
NotificationsTabNavigatorParams,
|
NotificationsTabNavigatorParams,
|
||||||
SearchTabNavigatorParams,
|
SearchTabNavigatorParams,
|
||||||
|
SideTabNavigatorParams,
|
||||||
} from '#/lib/routes/types'
|
} from '#/lib/routes/types'
|
||||||
import {RouteParams, State} from '#/lib/routes/types'
|
import {RouteParams, State} from '#/lib/routes/types'
|
||||||
import {attachRouteToLogEvents, logEvent} from '#/lib/statsig/statsig'
|
import {attachRouteToLogEvents, logEvent} from '#/lib/statsig/statsig'
|
||||||
import {bskyTitle} from '#/lib/strings/headings'
|
import {bskyTitle} from '#/lib/strings/headings'
|
||||||
import {isAndroid, isNative, isWeb} from '#/platform/detection'
|
import {isAndroid, isNative, isNativeTablet, isWeb} from '#/platform/detection'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
@@ -78,27 +80,27 @@ import {PostQuotesScreen} from '#/screens/Post/PostQuotes'
|
|||||||
import {PostRepostedByScreen} from '#/screens/Post/PostRepostedBy'
|
import {PostRepostedByScreen} from '#/screens/Post/PostRepostedBy'
|
||||||
import {ProfileKnownFollowersScreen} from '#/screens/Profile/KnownFollowers'
|
import {ProfileKnownFollowersScreen} from '#/screens/Profile/KnownFollowers'
|
||||||
import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
|
import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
|
||||||
|
import {AboutSettingsScreen} from '#/screens/Settings/AboutSettings'
|
||||||
|
import {AccessibilitySettingsScreen} from '#/screens/Settings/AccessibilitySettings'
|
||||||
|
import {AccountSettingsScreen} from '#/screens/Settings/AccountSettings'
|
||||||
import {AppearanceSettingsScreen} from '#/screens/Settings/AppearanceSettings'
|
import {AppearanceSettingsScreen} from '#/screens/Settings/AppearanceSettings'
|
||||||
|
import {AppPasswordsScreen} from '#/screens/Settings/AppPasswords'
|
||||||
|
import {ContentAndMediaSettingsScreen} from '#/screens/Settings/ContentAndMediaSettings'
|
||||||
|
import {ExternalMediaPreferencesScreen} from '#/screens/Settings/ExternalMediaPreferences'
|
||||||
|
import {FollowingFeedPreferencesScreen} from '#/screens/Settings/FollowingFeedPreferences'
|
||||||
|
import {LanguageSettingsScreen} from '#/screens/Settings/LanguageSettings'
|
||||||
import {NotificationSettingsScreen} from '#/screens/Settings/NotificationSettings'
|
import {NotificationSettingsScreen} from '#/screens/Settings/NotificationSettings'
|
||||||
|
import {PrivacyAndSecuritySettingsScreen} from '#/screens/Settings/PrivacyAndSecuritySettings'
|
||||||
|
import {SettingsScreen} from '#/screens/Settings/Settings'
|
||||||
|
import {ThreadPreferencesScreen} from '#/screens/Settings/ThreadPreferences'
|
||||||
import {
|
import {
|
||||||
StarterPackScreen,
|
StarterPackScreen,
|
||||||
StarterPackScreenShort,
|
StarterPackScreenShort,
|
||||||
} from '#/screens/StarterPack/StarterPackScreen'
|
} from '#/screens/StarterPack/StarterPackScreen'
|
||||||
import {Wizard} from '#/screens/StarterPack/Wizard'
|
import {Wizard} from '#/screens/StarterPack/Wizard'
|
||||||
import {useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {router} from '#/routes'
|
import {router} from '#/routes'
|
||||||
import {Referrer} from '../modules/expo-bluesky-swiss-army'
|
import {Referrer} from '../modules/expo-bluesky-swiss-army'
|
||||||
import {AboutSettingsScreen} from './screens/Settings/AboutSettings'
|
|
||||||
import {AccessibilitySettingsScreen} from './screens/Settings/AccessibilitySettings'
|
|
||||||
import {AccountSettingsScreen} from './screens/Settings/AccountSettings'
|
|
||||||
import {AppPasswordsScreen} from './screens/Settings/AppPasswords'
|
|
||||||
import {ContentAndMediaSettingsScreen} from './screens/Settings/ContentAndMediaSettings'
|
|
||||||
import {ExternalMediaPreferencesScreen} from './screens/Settings/ExternalMediaPreferences'
|
|
||||||
import {FollowingFeedPreferencesScreen} from './screens/Settings/FollowingFeedPreferences'
|
|
||||||
import {LanguageSettingsScreen} from './screens/Settings/LanguageSettings'
|
|
||||||
import {PrivacyAndSecuritySettingsScreen} from './screens/Settings/PrivacyAndSecuritySettings'
|
|
||||||
import {SettingsScreen} from './screens/Settings/Settings'
|
|
||||||
import {ThreadPreferencesScreen} from './screens/Settings/ThreadPreferences'
|
|
||||||
|
|
||||||
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
||||||
|
|
||||||
@@ -110,15 +112,23 @@ const MyProfileTab =
|
|||||||
createNativeStackNavigatorWithAuth<MyProfileTabNavigatorParams>()
|
createNativeStackNavigatorWithAuth<MyProfileTabNavigatorParams>()
|
||||||
const MessagesTab =
|
const MessagesTab =
|
||||||
createNativeStackNavigatorWithAuth<MessagesTabNavigatorParams>()
|
createNativeStackNavigatorWithAuth<MessagesTabNavigatorParams>()
|
||||||
|
const ListsTab = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||||
|
const ModerationTab = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||||
|
const SettingsTab = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||||
const Flat = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
const Flat = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||||
const Tab = createBottomTabNavigator<BottomTabNavigatorParams>()
|
|
||||||
|
const MobileTab = createBottomTabNavigator<BottomTabNavigatorParams>()
|
||||||
|
const TabletTab = createBottomTabNavigator<SideTabNavigatorParams>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These "common screens" are reused across stacks.
|
* These "common screens" are reused across stacks.
|
||||||
*/
|
*/
|
||||||
function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
function commonScreens(
|
||||||
|
Stack: typeof HomeTab,
|
||||||
|
opts?: {unreadCountLabel?: string},
|
||||||
|
) {
|
||||||
const title = (page: MessageDescriptor) =>
|
const title = (page: MessageDescriptor) =>
|
||||||
bskyTitle(i18n._(page), unreadCountLabel)
|
bskyTitle(i18n._(page), opts?.unreadCountLabel)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -127,16 +137,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
|||||||
getComponent={() => NotFoundScreen}
|
getComponent={() => NotFoundScreen}
|
||||||
options={{title: title(msg`Not Found`)}}
|
options={{title: title(msg`Not Found`)}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
|
||||||
name="Lists"
|
|
||||||
component={ListsScreen}
|
|
||||||
options={{title: title(msg`Lists`), requireAuth: true}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
|
||||||
name="Moderation"
|
|
||||||
getComponent={() => ModerationScreen}
|
|
||||||
options={{title: title(msg`Moderation`), requireAuth: true}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="ModerationModlists"
|
name="ModerationModlists"
|
||||||
getComponent={() => ModerationModlistsScreen}
|
getComponent={() => ModerationModlistsScreen}
|
||||||
@@ -152,11 +152,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
|||||||
getComponent={() => ModerationBlockedAccounts}
|
getComponent={() => ModerationBlockedAccounts}
|
||||||
options={{title: title(msg`Blocked Accounts`), requireAuth: true}}
|
options={{title: title(msg`Blocked Accounts`), requireAuth: true}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
|
||||||
name="Settings"
|
|
||||||
getComponent={() => SettingsScreen}
|
|
||||||
options={{title: title(msg`Settings`), requireAuth: true}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="LanguageSettings"
|
name="LanguageSettings"
|
||||||
getComponent={() => LanguageSettingsScreen}
|
getComponent={() => LanguageSettingsScreen}
|
||||||
@@ -166,7 +161,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
|||||||
name="Profile"
|
name="Profile"
|
||||||
getComponent={() => ProfileScreen}
|
getComponent={() => ProfileScreen}
|
||||||
options={({route}) => ({
|
options={({route}) => ({
|
||||||
title: bskyTitle(`@${route.params.name}`, unreadCountLabel),
|
title: bskyTitle(`@${route.params.name}`, opts?.unreadCountLabel),
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -407,15 +402,38 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
|||||||
getComponent={() => Wizard}
|
getComponent={() => Wizard}
|
||||||
options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
|
options={{title: title(msg`Edit your starter pack`), requireAuth: true}}
|
||||||
/>
|
/>
|
||||||
|
{!isNativeTablet && (
|
||||||
|
<>
|
||||||
|
<Stack.Screen
|
||||||
|
name="Moderation"
|
||||||
|
getComponent={() => ModerationScreen}
|
||||||
|
options={{title: title(msg`Moderation`), requireAuth: true}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="Lists"
|
||||||
|
component={ListsScreen}
|
||||||
|
options={{title: title(msg`Lists`), requireAuth: true}}
|
||||||
|
/>
|
||||||
|
<Stack.Screen
|
||||||
|
name="Settings"
|
||||||
|
getComponent={() => SettingsScreen}
|
||||||
|
options={{title: title(msg`Settings`), requireAuth: true}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The TabsNavigator is used by native mobile to represent the routes
|
* The TabsNavigator is used by native mobile to represent the routes
|
||||||
* in 3 distinct tab-stacks with a different root screen on each.
|
* in the distinct tab-stacks with a different root screen on each.
|
||||||
*/
|
*/
|
||||||
function TabsNavigator() {
|
function TabsNavigator() {
|
||||||
|
return isNativeTablet ? <TabNavigatorTablet /> : <TabsNavigatorMobile />
|
||||||
|
}
|
||||||
|
|
||||||
|
function TabsNavigatorMobile() {
|
||||||
const tabBar = React.useCallback(
|
const tabBar = React.useCallback(
|
||||||
(props: JSX.IntrinsicAttributes & BottomTabBarProps) => (
|
(props: JSX.IntrinsicAttributes & BottomTabBarProps) => (
|
||||||
<BottomBar {...props} />
|
<BottomBar {...props} />
|
||||||
@@ -424,26 +442,91 @@ function TabsNavigator() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tab.Navigator
|
<MobileTab.Navigator
|
||||||
initialRouteName="HomeTab"
|
initialRouteName="HomeTab"
|
||||||
backBehavior="initialRoute"
|
backBehavior="initialRoute"
|
||||||
screenOptions={{headerShown: false, lazy: true}}
|
screenOptions={{headerShown: false, lazy: true}}
|
||||||
tabBar={tabBar}>
|
tabBar={tabBar}>
|
||||||
<Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} />
|
<MobileTab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} />
|
||||||
<Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} />
|
<MobileTab.Screen
|
||||||
<Tab.Screen
|
name="SearchTab"
|
||||||
|
getComponent={() => SearchTabNavigator}
|
||||||
|
/>
|
||||||
|
<MobileTab.Screen
|
||||||
|
name="FeedsTab"
|
||||||
|
getComponent={() => FeedsTabNavigator}
|
||||||
|
/>
|
||||||
|
<MobileTab.Screen
|
||||||
name="NotificationsTab"
|
name="NotificationsTab"
|
||||||
getComponent={() => NotificationsTabNavigator}
|
getComponent={() => NotificationsTabNavigator}
|
||||||
/>
|
/>
|
||||||
<Tab.Screen
|
<MobileTab.Screen
|
||||||
name="MyProfileTab"
|
name="MyProfileTab"
|
||||||
getComponent={() => MyProfileTabNavigator}
|
getComponent={() => MyProfileTabNavigator}
|
||||||
/>
|
/>
|
||||||
<Tab.Screen
|
<MobileTab.Screen
|
||||||
name="MessagesTab"
|
name="MessagesTab"
|
||||||
getComponent={() => MessagesTabNavigator}
|
getComponent={() => MessagesTabNavigator}
|
||||||
/>
|
/>
|
||||||
</Tab.Navigator>
|
</MobileTab.Navigator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TabNavigatorTablet is used by native tablet to represent the routes
|
||||||
|
* in all the extra tabs shown in the tablet left nav.
|
||||||
|
*/
|
||||||
|
function TabNavigatorTablet() {
|
||||||
|
// we can't style the wrapper component of the tab navigator
|
||||||
|
// to set it to flex_row, so put the left nav outside of the tab navigator
|
||||||
|
const tabBar = React.useCallback(() => null, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[a.flex_row, a.flex_1]}>
|
||||||
|
<LeftNav />
|
||||||
|
<TabletTab.Navigator
|
||||||
|
initialRouteName="HomeTab"
|
||||||
|
backBehavior="initialRoute"
|
||||||
|
screenOptions={{headerShown: false, lazy: true}}
|
||||||
|
tabBar={tabBar}>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="HomeTab"
|
||||||
|
getComponent={() => HomeTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="SearchTab"
|
||||||
|
getComponent={() => SearchTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="NotificationsTab"
|
||||||
|
getComponent={() => NotificationsTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="MessagesTab"
|
||||||
|
getComponent={() => MessagesTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="FeedsTab"
|
||||||
|
getComponent={() => FeedsTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="ListsTab"
|
||||||
|
getComponent={() => ListsTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="ModerationTab"
|
||||||
|
getComponent={() => ModerationTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="MyProfileTab"
|
||||||
|
getComponent={() => MyProfileTabNavigator}
|
||||||
|
/>
|
||||||
|
<TabletTab.Screen
|
||||||
|
name="SettingsTab"
|
||||||
|
getComponent={() => SettingsTabNavigator}
|
||||||
|
/>
|
||||||
|
</TabletTab.Navigator>
|
||||||
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,6 +568,24 @@ function SearchTabNavigator() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function FeedsTabNavigator() {
|
||||||
|
const t = useTheme()
|
||||||
|
return (
|
||||||
|
<FeedsTab.Navigator
|
||||||
|
screenOptions={{
|
||||||
|
animation: isAndroid ? 'ios' : undefined,
|
||||||
|
animationDuration: 285,
|
||||||
|
gestureEnabled: true,
|
||||||
|
fullScreenGestureEnabled: true,
|
||||||
|
headerShown: false,
|
||||||
|
contentStyle: t.atoms.bg,
|
||||||
|
}}>
|
||||||
|
<FeedsTab.Screen name="Feeds" getComponent={() => FeedsScreen} />
|
||||||
|
{commonScreens(FeedsTab as typeof HomeTab)}
|
||||||
|
</FeedsTab.Navigator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function NotificationsTabNavigator() {
|
function NotificationsTabNavigator() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
return (
|
return (
|
||||||
@@ -558,6 +659,72 @@ function MessagesTabNavigator() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ListsTabNavigator() {
|
||||||
|
const t = useTheme()
|
||||||
|
return (
|
||||||
|
<ListsTab.Navigator
|
||||||
|
screenOptions={{
|
||||||
|
animation: isAndroid ? 'ios' : undefined,
|
||||||
|
animationDuration: 285,
|
||||||
|
gestureEnabled: true,
|
||||||
|
fullScreenGestureEnabled: true,
|
||||||
|
headerShown: false,
|
||||||
|
contentStyle: t.atoms.bg,
|
||||||
|
}}>
|
||||||
|
<ListsTab.Screen
|
||||||
|
name="Lists"
|
||||||
|
getComponent={() => ListsScreen}
|
||||||
|
options={{requireAuth: true}}
|
||||||
|
/>
|
||||||
|
{commonScreens(ListsTab as typeof HomeTab)}
|
||||||
|
</ListsTab.Navigator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ModerationTabNavigator() {
|
||||||
|
const t = useTheme()
|
||||||
|
return (
|
||||||
|
<ModerationTab.Navigator
|
||||||
|
screenOptions={{
|
||||||
|
animation: isAndroid ? 'ios' : undefined,
|
||||||
|
animationDuration: 285,
|
||||||
|
gestureEnabled: true,
|
||||||
|
fullScreenGestureEnabled: true,
|
||||||
|
headerShown: false,
|
||||||
|
contentStyle: t.atoms.bg,
|
||||||
|
}}>
|
||||||
|
<ModerationTab.Screen
|
||||||
|
name="Moderation"
|
||||||
|
getComponent={() => ModerationScreen}
|
||||||
|
options={{requireAuth: true}}
|
||||||
|
/>
|
||||||
|
{commonScreens(ModerationTab as typeof HomeTab)}
|
||||||
|
</ModerationTab.Navigator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SettingsTabNavigator() {
|
||||||
|
const t = useTheme()
|
||||||
|
return (
|
||||||
|
<SettingsTab.Navigator
|
||||||
|
screenOptions={{
|
||||||
|
animation: isAndroid ? 'ios' : undefined,
|
||||||
|
animationDuration: 285,
|
||||||
|
gestureEnabled: true,
|
||||||
|
fullScreenGestureEnabled: true,
|
||||||
|
headerShown: false,
|
||||||
|
contentStyle: t.atoms.bg,
|
||||||
|
}}>
|
||||||
|
<SettingsTab.Screen
|
||||||
|
name="Settings"
|
||||||
|
getComponent={() => SettingsScreen}
|
||||||
|
options={{requireAuth: true}}
|
||||||
|
/>
|
||||||
|
{commonScreens(SettingsTab as typeof HomeTab)}
|
||||||
|
</SettingsTab.Navigator>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The FlatNavigator is used by Web to represent the routes
|
* The FlatNavigator is used by Web to represent the routes
|
||||||
* in a single ("flat") stack.
|
* in a single ("flat") stack.
|
||||||
@@ -604,7 +771,7 @@ const FlatNavigator = () => {
|
|||||||
getComponent={() => HomeScreen}
|
getComponent={() => HomeScreen}
|
||||||
options={{title: title(msg`Home`)}}
|
options={{title: title(msg`Home`)}}
|
||||||
/>
|
/>
|
||||||
{commonScreens(Flat as typeof HomeTab, numUnread)}
|
{commonScreens(Flat as typeof HomeTab, {unreadCountLabel: numUnread})}
|
||||||
</Flat.Navigator>
|
</Flat.Navigator>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -651,6 +818,9 @@ const LINKING = {
|
|||||||
if (name === 'Search') {
|
if (name === 'Search') {
|
||||||
return buildStateObject('SearchTab', 'Search', params)
|
return buildStateObject('SearchTab', 'Search', params)
|
||||||
}
|
}
|
||||||
|
if (name === 'Feeds') {
|
||||||
|
return buildStateObject('FeedsTab', 'Feeds', params)
|
||||||
|
}
|
||||||
if (name === 'Notifications') {
|
if (name === 'Notifications') {
|
||||||
return buildStateObject('NotificationsTab', 'Notifications', params)
|
return buildStateObject('NotificationsTab', 'Notifications', params)
|
||||||
}
|
}
|
||||||
@@ -660,6 +830,17 @@ const LINKING = {
|
|||||||
if (name === 'Messages') {
|
if (name === 'Messages') {
|
||||||
return buildStateObject('MessagesTab', 'Messages', params)
|
return buildStateObject('MessagesTab', 'Messages', params)
|
||||||
}
|
}
|
||||||
|
if (isNativeTablet) {
|
||||||
|
if (name === 'Lists') {
|
||||||
|
return buildStateObject('ListsTab', 'Lists', params)
|
||||||
|
}
|
||||||
|
if (name === 'Moderation') {
|
||||||
|
return buildStateObject('ModerationTab', 'Moderation', params)
|
||||||
|
}
|
||||||
|
if (name === 'Settings') {
|
||||||
|
return buildStateObject('SettingsTab', 'Settings', params)
|
||||||
|
}
|
||||||
|
}
|
||||||
// if the path is something else, like a post, profile, or even settings, we need to initialize the home tab as pre-existing state otherwise the back button will not work
|
// if the path is something else, like a post, profile, or even settings, we need to initialize the home tab as pre-existing state otherwise the back button will not work
|
||||||
return buildStateObject('HomeTab', name, params, [
|
return buildStateObject('HomeTab', name, params, [
|
||||||
{
|
{
|
||||||
@@ -855,5 +1036,6 @@ export {
|
|||||||
reset,
|
reset,
|
||||||
resetToTab,
|
resetToTab,
|
||||||
RoutesContainer,
|
RoutesContainer,
|
||||||
|
TabNavigatorTablet,
|
||||||
TabsNavigator,
|
TabsNavigator,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {GestureResponderEvent, View} from 'react-native'
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {isNativeTablet} from '#/platform/detection'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||||
import {Button, ButtonColor, ButtonText} from '#/components/Button'
|
import {Button, ButtonColor, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
@@ -52,7 +53,9 @@ export function Outer({
|
|||||||
accessibilityLabelledBy={titleId}
|
accessibilityLabelledBy={titleId}
|
||||||
accessibilityDescribedBy={descriptionId}
|
accessibilityDescribedBy={descriptionId}
|
||||||
style={[
|
style={[
|
||||||
gtMobile ? {width: 'auto', maxWidth: 400, minWidth: 200} : a.w_full,
|
gtMobile && !isNativeTablet
|
||||||
|
? {width: 'auto', maxWidth: 400, minWidth: 200}
|
||||||
|
: a.w_full,
|
||||||
]}>
|
]}>
|
||||||
{children}
|
{children}
|
||||||
</Dialog.ScrollableInner>
|
</Dialog.ScrollableInner>
|
||||||
@@ -97,7 +100,7 @@ export function Actions({children}: React.PropsWithChildren<{}>) {
|
|||||||
a.w_full,
|
a.w_full,
|
||||||
a.gap_md,
|
a.gap_md,
|
||||||
a.justify_end,
|
a.justify_end,
|
||||||
gtMobile
|
gtMobile && !isNativeTablet
|
||||||
? [a.flex_row, a.flex_row_reverse, a.justify_start]
|
? [a.flex_row, a.flex_row_reverse, a.justify_start]
|
||||||
: [a.flex_col],
|
: [a.flex_col],
|
||||||
]}>
|
]}>
|
||||||
|
|||||||
@@ -65,6 +65,18 @@ export type BottomTabNavigatorParams = CommonNavigatorParams & {
|
|||||||
MessagesTab: undefined
|
MessagesTab: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SideTabNavigatorParams = CommonNavigatorParams & {
|
||||||
|
HomeTab: undefined
|
||||||
|
SearchTab: undefined
|
||||||
|
FeedsTab: undefined
|
||||||
|
NotificationsTab: undefined
|
||||||
|
MyProfileTab: undefined
|
||||||
|
MessagesTab: undefined
|
||||||
|
ListsTab: undefined
|
||||||
|
ModerationTab: undefined
|
||||||
|
SettingsTab: undefined
|
||||||
|
}
|
||||||
|
|
||||||
export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
||||||
Home: undefined
|
Home: undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {HITSLOP_10} from '#/lib/constants'
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
import {useMinimalShellHeaderTransform} from '#/lib/hooks/useMinimalShellTransform'
|
import {useMinimalShellHeaderTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isNativeTablet, isWeb} from '#/platform/detection'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useSetDrawerOpen} from '#/state/shell/drawer-open'
|
import {useSetDrawerOpen} from '#/state/shell/drawer-open'
|
||||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||||
@@ -46,6 +46,7 @@ export function HomeHeaderLayoutMobile({
|
|||||||
headerHeight.value = e.nativeEvent.layout.height
|
headerHeight.value = e.nativeEvent.layout.height
|
||||||
}}>
|
}}>
|
||||||
<View style={[pal.view, styles.topBar]}>
|
<View style={[pal.view, styles.topBar]}>
|
||||||
|
{!isNativeTablet ? (
|
||||||
<View style={[pal.view, {width: 100}]}>
|
<View style={[pal.view, {width: 100}]}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
testID="viewHeaderDrawerBtn"
|
testID="viewHeaderDrawerBtn"
|
||||||
@@ -59,6 +60,11 @@ export function HomeHeaderLayoutMobile({
|
|||||||
<Menu size="lg" fill={t.atoms.text_contrast_medium.color} />
|
<Menu size="lg" fill={t.atoms.text_contrast_medium.color} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
) : (
|
||||||
|
// subtract width of LeftNav
|
||||||
|
<View style={{width: 100 - 77}} />
|
||||||
|
)}
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<Logo width={30} />
|
<Logo width={30} />
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
|||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative, isNativeTablet} from '#/platform/detection'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {useLightboxControls} from '#/state/lightbox'
|
import {useLightboxControls} from '#/state/lightbox'
|
||||||
import {useSetDrawerOpen} from '#/state/shell'
|
import {useSetDrawerOpen} from '#/state/shell'
|
||||||
@@ -89,9 +89,11 @@ export function ProfileSubpageHeader({
|
|||||||
}
|
}
|
||||||
}, [openLightbox, avatar])
|
}, [openLightbox, avatar])
|
||||||
|
|
||||||
|
const isMobileLayout = isMobile || isNativeTablet
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView style={pal.view}>
|
<CenteredView style={pal.view}>
|
||||||
{isMobile && (
|
{isMobileLayout && (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
@@ -100,7 +102,7 @@ export function ProfileSubpageHeader({
|
|||||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||||
paddingTop: isNative ? 0 : 8,
|
paddingTop: isNative ? 0 : 8,
|
||||||
paddingBottom: 8,
|
paddingBottom: 8,
|
||||||
paddingHorizontal: isMobile ? 12 : 14,
|
paddingHorizontal: isMobileLayout ? 12 : 14,
|
||||||
},
|
},
|
||||||
pal.border,
|
pal.border,
|
||||||
]}>
|
]}>
|
||||||
@@ -133,7 +135,7 @@ export function ProfileSubpageHeader({
|
|||||||
gap: 10,
|
gap: 10,
|
||||||
paddingTop: 14,
|
paddingTop: 14,
|
||||||
paddingBottom: 6,
|
paddingBottom: 6,
|
||||||
paddingHorizontal: isMobile ? 12 : 14,
|
paddingHorizontal: isMobileLayout ? 12 : 14,
|
||||||
}}>
|
}}>
|
||||||
<Pressable
|
<Pressable
|
||||||
testID="headerAviButton"
|
testID="headerAviButton"
|
||||||
@@ -188,7 +190,7 @@ export function ProfileSubpageHeader({
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
{!isMobile && (
|
{!isMobileLayout && (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {useNavigation} from '@react-navigation/native'
|
|||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isNativeTablet, isWeb} from '#/platform/detection'
|
||||||
import {useSetDrawerOpen} from '#/state/shell'
|
import {useSetDrawerOpen} from '#/state/shell'
|
||||||
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
|
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
|
||||||
import {CenteredView} from './Views'
|
import {CenteredView} from './Views'
|
||||||
@@ -70,9 +70,9 @@ export function SimpleViewHeader({
|
|||||||
icon="angle-left"
|
icon="angle-left"
|
||||||
style={[styles.backIcon, pal.text]}
|
style={[styles.backIcon, pal.text]}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : !isNativeTablet ? (
|
||||||
<Menu size="lg" style={[{marginTop: 4}, pal.textLight]} />
|
<Menu size="lg" style={[{marginTop: 4}, pal.textLight]} />
|
||||||
)}
|
) : null}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
) : null}
|
) : null}
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
import Animated from 'react-native-reanimated'
|
import Animated from 'react-native-reanimated'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {useMediaQuery} from 'react-responsive'
|
import {useMediaQuery} from 'react-responsive'
|
||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
|
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
import {clamp} from '#/lib/numbers'
|
|
||||||
import {colors} from '#/lib/styles'
|
import {colors} from '#/lib/styles'
|
||||||
import {isNativeTablet, isWeb} from '#/platform/detection'
|
import {isNativeTablet} from '#/platform/detection'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
import {useTheme} from '#/alf'
|
||||||
|
|
||||||
const AnimatedTouchableOpacity =
|
const AnimatedTouchableOpacity =
|
||||||
Animated.createAnimatedComponent(TouchableOpacity)
|
Animated.createAnimatedComponent(TouchableOpacity)
|
||||||
@@ -26,24 +24,17 @@ export function LoadLatestBtn({
|
|||||||
label: string
|
label: string
|
||||||
showIndicator: boolean
|
showIndicator: boolean
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const t = useTheme()
|
||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
|
const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
|
||||||
const fabMinimalShellTransform = useMinimalShellFabTransform()
|
const fabMinimalShellTransform = useMinimalShellFabTransform()
|
||||||
const insets = useSafeAreaInsets()
|
|
||||||
|
|
||||||
// move button inline if it starts overlapping the left nav
|
// move button inline if it starts overlapping the left nav
|
||||||
const isTallViewport = useMediaQuery({minHeight: 700})
|
const isTallViewport = useMediaQuery({minHeight: 700})
|
||||||
|
|
||||||
// Adjust height of the fab if we have a session only on mobile web. If we don't have a session, we want to adjust
|
// Adjust height of the fab if we have a session only on mobile web. If we don't have a session, we want to adjust
|
||||||
// it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth)
|
// it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth)
|
||||||
const showBottomBar = hasSession
|
const showBottomBar = hasSession ? isMobile : isTabletOrMobile
|
||||||
? isMobile || isNativeTablet
|
|
||||||
: isTabletOrMobile
|
|
||||||
|
|
||||||
const bottomPosition = isTablet
|
|
||||||
? {bottom: 50}
|
|
||||||
: {bottom: clamp(insets.bottom, 15, 60) + 15}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatedTouchableOpacity
|
<AnimatedTouchableOpacity
|
||||||
@@ -54,9 +45,8 @@ export function LoadLatestBtn({
|
|||||||
? styles.loadLatestOutOfLine
|
? styles.loadLatestOutOfLine
|
||||||
: styles.loadLatestInline),
|
: styles.loadLatestInline),
|
||||||
isTablet && !isNativeTablet && styles.loadLatestInline,
|
isTablet && !isNativeTablet && styles.loadLatestInline,
|
||||||
pal.borderDark,
|
t.atoms.border_contrast_high,
|
||||||
pal.view,
|
t.atoms.bg,
|
||||||
bottomPosition,
|
|
||||||
showBottomBar && fabMinimalShellTransform,
|
showBottomBar && fabMinimalShellTransform,
|
||||||
]}
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
@@ -64,8 +54,10 @@ export function LoadLatestBtn({
|
|||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
accessibilityLabel={label}
|
accessibilityLabel={label}
|
||||||
accessibilityHint="">
|
accessibilityHint="">
|
||||||
<FontAwesomeIcon icon="angle-up" color={pal.colors.text} size={19} />
|
<FontAwesomeIcon icon="angle-up" color={t.atoms.text.color} size={19} />
|
||||||
{showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
|
{showIndicator && (
|
||||||
|
<View style={[styles.indicator, t.atoms.border_contrast_high]} />
|
||||||
|
)}
|
||||||
</AnimatedTouchableOpacity>
|
</AnimatedTouchableOpacity>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import {Onboarding} from '#/screens/Onboarding'
|
|||||||
import {SignupQueued} from '#/screens/SignupQueued'
|
import {SignupQueued} from '#/screens/SignupQueued'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a} from '#/alf'
|
||||||
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
||||||
import {DesktopLeftNav} from './desktop/LeftNav'
|
import {LeftNav} from './desktop/LeftNav'
|
||||||
import {DesktopRightNav} from './desktop/RightNav'
|
import {DesktopRightNav} from './desktop/RightNav'
|
||||||
|
|
||||||
type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & {
|
type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & {
|
||||||
@@ -149,7 +149,7 @@ function NativeStackNavigator({
|
|||||||
{isWeb && showBottomBar && <BottomBarWeb />}
|
{isWeb && showBottomBar && <BottomBarWeb />}
|
||||||
{isWeb && !showBottomBar && (
|
{isWeb && !showBottomBar && (
|
||||||
<>
|
<>
|
||||||
<DesktopLeftNav />
|
<LeftNav />
|
||||||
<DesktopRightNav routeName={activeRoute.name} />
|
<DesktopRightNav routeName={activeRoute.name} />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ function ChatNavItem() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DesktopLeftNav() {
|
export function LeftNav() {
|
||||||
const {hasSession, currentAccount} = useSession()
|
const {hasSession, currentAccount} = useSession()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
@@ -519,16 +519,18 @@ export function DesktopLeftNav() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
leftNav: {
|
|
||||||
// @ts-ignore web only
|
// @ts-ignore web only
|
||||||
|
leftNav: isWeb
|
||||||
|
? {
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: 10,
|
top: 10,
|
||||||
// @ts-ignore web only
|
|
||||||
left: 'calc(50vw - 300px - 220px - 20px)',
|
left: 'calc(50vw - 300px - 220px - 20px)',
|
||||||
width: 220,
|
width: 220,
|
||||||
// @ts-ignore web only
|
|
||||||
maxHeight: 'calc(100vh - 10px)',
|
maxHeight: 'calc(100vh - 10px)',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
paddingTop: 12,
|
||||||
},
|
},
|
||||||
leftNavTablet: {
|
leftNavTablet: {
|
||||||
top: 0,
|
top: 0,
|
||||||
@@ -556,4 +558,41 @@ const styles = StyleSheet.create({
|
|||||||
width: 30,
|
width: 30,
|
||||||
height: 30,
|
height: 30,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navItemWrapper: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
padding: 12,
|
||||||
|
borderRadius: 8,
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
navItemIconWrapper: {
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: 28,
|
||||||
|
height: 24,
|
||||||
|
marginTop: 2,
|
||||||
|
zIndex: 1,
|
||||||
|
},
|
||||||
|
navItemIconWrapperTablet: {
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
},
|
||||||
|
navItemCount: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 15,
|
||||||
|
backgroundColor: colors.blue3,
|
||||||
|
color: colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
borderRadius: 6,
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
navItemCountTablet: {
|
||||||
|
left: 18,
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -119,14 +119,17 @@ export function DesktopRightNav({routeName}: {routeName: string}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
rightNav: {
|
|
||||||
// @ts-ignore web only
|
// @ts-ignore web only
|
||||||
|
rightNav: isWeb
|
||||||
|
? {
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
// @ts-ignore web only
|
|
||||||
left: 'calc(50vw + 300px + 20px)',
|
left: 'calc(50vw + 300px + 20px)',
|
||||||
width: 300,
|
width: 300,
|
||||||
maxHeight: '100%',
|
maxHeight: '100%',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
width: 300,
|
||||||
},
|
},
|
||||||
|
|
||||||
message: {
|
message: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {BackHandler, StyleSheet, useWindowDimensions, View} from 'react-native'
|
import {BackHandler, useWindowDimensions, View} from 'react-native'
|
||||||
import {Drawer} from 'react-native-drawer-layout'
|
import {Drawer} from 'react-native-drawer-layout'
|
||||||
import Animated from 'react-native-reanimated'
|
import Animated from 'react-native-reanimated'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
@@ -14,7 +14,7 @@ import {usePalette} from '#/lib/hooks/usePalette'
|
|||||||
import {useNotificationsRegistration} from '#/lib/notifications/notifications'
|
import {useNotificationsRegistration} from '#/lib/notifications/notifications'
|
||||||
import {isStateAtTabRoot} from '#/lib/routes/helpers'
|
import {isStateAtTabRoot} from '#/lib/routes/helpers'
|
||||||
import {useTheme} from '#/lib/ThemeContext'
|
import {useTheme} from '#/lib/ThemeContext'
|
||||||
import {isAndroid, isIOS} from '#/platform/detection'
|
import {isAndroid, isIOS, isNativeTablet} from '#/platform/detection'
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {
|
import {
|
||||||
@@ -26,6 +26,7 @@ import {useCloseAnyActiveElement} from '#/state/util'
|
|||||||
import {Lightbox} from '#/view/com/lightbox/Lightbox'
|
import {Lightbox} from '#/view/com/lightbox/Lightbox'
|
||||||
import {ModalsContainer} from '#/view/com/modals/Modal'
|
import {ModalsContainer} from '#/view/com/modals/Modal'
|
||||||
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
|
||||||
|
import {useTheme as useAlfTheme} from '#/alf'
|
||||||
import {atoms as a, select, useTheme as useNewTheme} from '#/alf'
|
import {atoms as a, select, useTheme as useNewTheme} from '#/alf'
|
||||||
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
||||||
import {SigninDialog} from '#/components/dialogs/Signin'
|
import {SigninDialog} from '#/components/dialogs/Signin'
|
||||||
@@ -98,6 +99,7 @@ function ShellInner() {
|
|||||||
<Animated.View style={[a.h_full]}>
|
<Animated.View style={[a.h_full]}>
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
style={{paddingTop: insets.top, paddingBottom: insets.bottom}}>
|
style={{paddingTop: insets.top, paddingBottom: insets.bottom}}>
|
||||||
|
{!isNativeTablet ? (
|
||||||
<Drawer
|
<Drawer
|
||||||
renderDrawerContent={renderDrawerContent}
|
renderDrawerContent={renderDrawerContent}
|
||||||
drawerStyle={{width: Math.min(400, winDim.width * 0.8)}}
|
drawerStyle={{width: Math.min(400, winDim.width * 0.8)}}
|
||||||
@@ -117,6 +119,9 @@ function ShellInner() {
|
|||||||
}}>
|
}}>
|
||||||
<TabsNavigator />
|
<TabsNavigator />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
) : (
|
||||||
|
<TabsNavigator />
|
||||||
|
)}
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Composer winHeight={winDim.height} />
|
<Composer winHeight={winDim.height} />
|
||||||
@@ -132,8 +137,8 @@ function ShellInner() {
|
|||||||
|
|
||||||
export const Shell: React.FC = function ShellImpl() {
|
export const Shell: React.FC = function ShellImpl() {
|
||||||
const {fullyExpandedCount} = useDialogStateControlContext()
|
const {fullyExpandedCount} = useDialogStateControlContext()
|
||||||
const pal = usePalette('default')
|
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const t = useAlfTheme
|
||||||
useIntentHandler()
|
useIntentHandler()
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -146,7 +151,7 @@ export const Shell: React.FC = function ShellImpl() {
|
|||||||
}
|
}
|
||||||
}, [theme])
|
}, [theme])
|
||||||
return (
|
return (
|
||||||
<View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
|
<View testID="mobileShellView" style={[a.h_full, t.atoms.bg]}>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
style={
|
style={
|
||||||
theme.colorScheme === 'dark' || (isIOS && fullyExpandedCount > 0)
|
theme.colorScheme === 'dark' || (isIOS && fullyExpandedCount > 0)
|
||||||
@@ -161,9 +166,3 @@ export const Shell: React.FC = function ShellImpl() {
|
|||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
outerContainer: {
|
|
||||||
height: '100%',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
Reference in New Issue
Block a user