Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff7788dab5 | |||
| 1700ad751f | |||
| 776e0c5a9f | |||
| e81bb86682 | |||
| b335a3ca58 | |||
| 3727badd3a | |||
| fbcd9848c1 | |||
| ea7a672ae8 | |||
| 0bbfe966d8 | |||
| 98c7278867 | |||
| 106e494b8b |
+1
-1
@@ -60,7 +60,7 @@ module.exports = function (config) {
|
||||
userInterfaceStyle: 'automatic',
|
||||
splash: SPLASH_CONFIG,
|
||||
ios: {
|
||||
supportsTablet: false,
|
||||
supportsTablet: true,
|
||||
bundleIdentifier: 'xyz.blueskyweb.app',
|
||||
config: {
|
||||
usesNonExemptEncryption: false,
|
||||
|
||||
+254
-95
@@ -15,11 +15,12 @@ import {
|
||||
StackActions,
|
||||
} from '@react-navigation/native'
|
||||
|
||||
import {timeout} from 'lib/async/timeout'
|
||||
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {buildStateObject} from 'lib/routes/helpers'
|
||||
import {
|
||||
import {init as initAnalytics} from '#/lib/analytics/analytics'
|
||||
import {timeout} from '#/lib/async/timeout'
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration'
|
||||
import {buildStateObject} from '#/lib/routes/helpers'
|
||||
import type {
|
||||
AllNavigatorParams,
|
||||
BottomTabNavigatorParams,
|
||||
FeedsTabNavigatorParams,
|
||||
@@ -28,59 +29,60 @@ import {
|
||||
MyProfileTabNavigatorParams,
|
||||
NotificationsTabNavigatorParams,
|
||||
SearchTabNavigatorParams,
|
||||
} from 'lib/routes/types'
|
||||
import {RouteParams, State} from 'lib/routes/types'
|
||||
import {bskyTitle} from 'lib/strings/headings'
|
||||
import {isAndroid, isNative} from 'platform/detection'
|
||||
import {PreferencesExternalEmbeds} from '#/view/screens/PreferencesExternalEmbeds'
|
||||
import {AppPasswords} from 'view/screens/AppPasswords'
|
||||
import {ModerationBlockedAccounts} from 'view/screens/ModerationBlockedAccounts'
|
||||
import {ModerationMutedAccounts} from 'view/screens/ModerationMutedAccounts'
|
||||
import {PreferencesFollowingFeed} from 'view/screens/PreferencesFollowingFeed'
|
||||
import {PreferencesThreads} from 'view/screens/PreferencesThreads'
|
||||
import {SavedFeeds} from 'view/screens/SavedFeeds'
|
||||
import HashtagScreen from '#/screens/Hashtag'
|
||||
import {ModerationScreen} from '#/screens/Moderation'
|
||||
import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
|
||||
import {init as initAnalytics} from './lib/analytics/analytics'
|
||||
import {useWebScrollRestoration} from './lib/hooks/useWebScrollRestoration'
|
||||
import {attachRouteToLogEvents, logEvent} from './lib/statsig/statsig'
|
||||
import {router} from './routes'
|
||||
import {useModalControls} from './state/modals'
|
||||
import {useUnreadNotifications} from './state/queries/notifications/unread'
|
||||
import {useSession} from './state/session'
|
||||
SideTabNavigatorParams,
|
||||
} from '#/lib/routes/types'
|
||||
import {RouteParams, State} from '#/lib/routes/types'
|
||||
import {attachRouteToLogEvents, logEvent} from '#/lib/statsig/statsig'
|
||||
import {bskyTitle} from '#/lib/strings/headings'
|
||||
import {isAndroid, isNative, isNativeTablet} from '#/platform/detection'
|
||||
import {useModalControls} from '#/state/modals'
|
||||
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||
import {useSession} from '#/state/session'
|
||||
import {
|
||||
setEmailConfirmationRequested,
|
||||
shouldRequestEmailConfirmation,
|
||||
} from './state/shell/reminders'
|
||||
import {CommunityGuidelinesScreen} from './view/screens/CommunityGuidelines'
|
||||
import {CopyrightPolicyScreen} from './view/screens/CopyrightPolicy'
|
||||
import {DebugModScreen} from './view/screens/DebugMod'
|
||||
import {FeedsScreen} from './view/screens/Feeds'
|
||||
import {HomeScreen} from './view/screens/Home'
|
||||
import {LanguageSettingsScreen} from './view/screens/LanguageSettings'
|
||||
import {ListsScreen} from './view/screens/Lists'
|
||||
import {LogScreen} from './view/screens/Log'
|
||||
import {ModerationModlistsScreen} from './view/screens/ModerationModlists'
|
||||
import {NotFoundScreen} from './view/screens/NotFound'
|
||||
import {NotificationsScreen} from './view/screens/Notifications'
|
||||
import {PostLikedByScreen} from './view/screens/PostLikedBy'
|
||||
import {PostRepostedByScreen} from './view/screens/PostRepostedBy'
|
||||
import {PostThreadScreen} from './view/screens/PostThread'
|
||||
import {PrivacyPolicyScreen} from './view/screens/PrivacyPolicy'
|
||||
import {ProfileScreen} from './view/screens/Profile'
|
||||
import {ProfileFeedScreen} from './view/screens/ProfileFeed'
|
||||
import {ProfileFeedLikedByScreen} from './view/screens/ProfileFeedLikedBy'
|
||||
import {ProfileFollowersScreen} from './view/screens/ProfileFollowers'
|
||||
import {ProfileFollowsScreen} from './view/screens/ProfileFollows'
|
||||
import {ProfileListScreen} from './view/screens/ProfileList'
|
||||
import {SearchScreen} from './view/screens/Search'
|
||||
import {SettingsScreen} from './view/screens/Settings'
|
||||
import {Storybook} from './view/screens/Storybook'
|
||||
import {SupportScreen} from './view/screens/Support'
|
||||
import {TermsOfServiceScreen} from './view/screens/TermsOfService'
|
||||
import {BottomBar} from './view/shell/bottom-bar/BottomBar'
|
||||
import {createNativeStackNavigatorWithAuth} from './view/shell/createNativeStackNavigatorWithAuth'
|
||||
} from '#/state/shell/reminders'
|
||||
import {AppPasswords} from '#/view/screens/AppPasswords'
|
||||
import {CommunityGuidelinesScreen} from '#/view/screens/CommunityGuidelines'
|
||||
import {CopyrightPolicyScreen} from '#/view/screens/CopyrightPolicy'
|
||||
import {DebugModScreen} from '#/view/screens/DebugMod'
|
||||
import {FeedsScreen} from '#/view/screens/Feeds'
|
||||
import {HomeScreen} from '#/view/screens/Home'
|
||||
import {LanguageSettingsScreen} from '#/view/screens/LanguageSettings'
|
||||
import {ListsScreen} from '#/view/screens/Lists'
|
||||
import {LogScreen} from '#/view/screens/Log'
|
||||
import {ModerationBlockedAccounts} from '#/view/screens/ModerationBlockedAccounts'
|
||||
import {ModerationModlistsScreen} from '#/view/screens/ModerationModlists'
|
||||
import {ModerationMutedAccounts} from '#/view/screens/ModerationMutedAccounts'
|
||||
import {NotFoundScreen} from '#/view/screens/NotFound'
|
||||
import {NotificationsScreen} from '#/view/screens/Notifications'
|
||||
import {PostLikedByScreen} from '#/view/screens/PostLikedBy'
|
||||
import {PostRepostedByScreen} from '#/view/screens/PostRepostedBy'
|
||||
import {PostThreadScreen} from '#/view/screens/PostThread'
|
||||
import {PreferencesExternalEmbeds} from '#/view/screens/PreferencesExternalEmbeds'
|
||||
import {PreferencesFollowingFeed} from '#/view/screens/PreferencesFollowingFeed'
|
||||
import {PreferencesThreads} from '#/view/screens/PreferencesThreads'
|
||||
import {PrivacyPolicyScreen} from '#/view/screens/PrivacyPolicy'
|
||||
import {ProfileScreen} from '#/view/screens/Profile'
|
||||
import {ProfileFeedScreen} from '#/view/screens/ProfileFeed'
|
||||
import {ProfileFeedLikedByScreen} from '#/view/screens/ProfileFeedLikedBy'
|
||||
import {ProfileFollowersScreen} from '#/view/screens/ProfileFollowers'
|
||||
import {ProfileFollowsScreen} from '#/view/screens/ProfileFollows'
|
||||
import {ProfileListScreen} from '#/view/screens/ProfileList'
|
||||
import {SavedFeeds} from '#/view/screens/SavedFeeds'
|
||||
import {SearchScreen} from '#/view/screens/Search'
|
||||
import {SettingsScreen} from '#/view/screens/Settings'
|
||||
import {Storybook} from '#/view/screens/Storybook'
|
||||
import {SupportScreen} from '#/view/screens/Support'
|
||||
import {TermsOfServiceScreen} from '#/view/screens/TermsOfService'
|
||||
import {BottomBar} from '#/view/shell/bottom-bar/BottomBar'
|
||||
import {createNativeStackNavigatorWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth'
|
||||
import {LeftNav} from '#/view/shell/desktop/LeftNav'
|
||||
import HashtagScreen from '#/screens/Hashtag'
|
||||
import {ModerationScreen} from '#/screens/Moderation'
|
||||
import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
|
||||
import {useTheme} from '#/alf'
|
||||
import {router} from '#/routes'
|
||||
|
||||
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
||||
|
||||
@@ -91,15 +93,23 @@ const NotificationsTab =
|
||||
createNativeStackNavigatorWithAuth<NotificationsTabNavigatorParams>()
|
||||
const MyProfileTab =
|
||||
createNativeStackNavigatorWithAuth<MyProfileTabNavigatorParams>()
|
||||
const ListsTab = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||
const ModerationTab = createNativeStackNavigatorWithAuth<FlatNavigatorParams>()
|
||||
const SettingsTab = 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.
|
||||
*/
|
||||
function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
||||
function commonScreens(
|
||||
Stack: typeof HomeTab,
|
||||
opts?: {unreadCountLabel?: string},
|
||||
) {
|
||||
const title = (page: MessageDescriptor) =>
|
||||
bskyTitle(i18n._(page), unreadCountLabel)
|
||||
bskyTitle(i18n._(page), opts?.unreadCountLabel)
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -108,16 +118,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
||||
getComponent={() => NotFoundScreen}
|
||||
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
|
||||
name="ModerationModlists"
|
||||
getComponent={() => ModerationModlistsScreen}
|
||||
@@ -133,11 +133,6 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
||||
getComponent={() => ModerationBlockedAccounts}
|
||||
options={{title: title(msg`Blocked Accounts`), requireAuth: true}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Settings"
|
||||
getComponent={() => SettingsScreen}
|
||||
options={{title: title(msg`Settings`), requireAuth: true}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="LanguageSettings"
|
||||
getComponent={() => LanguageSettingsScreen}
|
||||
@@ -147,7 +142,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
||||
name="Profile"
|
||||
getComponent={() => ProfileScreen}
|
||||
options={({route}) => ({
|
||||
title: bskyTitle(`@${route.params.name}`, unreadCountLabel),
|
||||
title: bskyTitle(`@${route.params.name}`, opts?.unreadCountLabel),
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
@@ -281,15 +276,38 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
|
||||
getComponent={() => HashtagScreen}
|
||||
options={{title: title(msg`Hashtag`)}}
|
||||
/>
|
||||
{!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
|
||||
* 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() {
|
||||
return isNativeTablet ? <TabNavigatorTablet /> : <TabsNavigatorMobile />
|
||||
}
|
||||
|
||||
function TabsNavigatorMobile() {
|
||||
const tabBar = React.useCallback(
|
||||
(props: JSX.IntrinsicAttributes & BottomTabBarProps) => (
|
||||
<BottomBar {...props} />
|
||||
@@ -298,28 +316,88 @@ function TabsNavigator() {
|
||||
)
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
<MobileTab.Navigator
|
||||
initialRouteName="HomeTab"
|
||||
backBehavior="initialRoute"
|
||||
screenOptions={{headerShown: false, lazy: true}}
|
||||
tabBar={tabBar}>
|
||||
<Tab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} />
|
||||
<Tab.Screen name="SearchTab" getComponent={() => SearchTabNavigator} />
|
||||
<Tab.Screen name="FeedsTab" getComponent={() => FeedsTabNavigator} />
|
||||
<Tab.Screen
|
||||
<MobileTab.Screen name="HomeTab" getComponent={() => HomeTabNavigator} />
|
||||
<MobileTab.Screen
|
||||
name="SearchTab"
|
||||
getComponent={() => SearchTabNavigator}
|
||||
/>
|
||||
<MobileTab.Screen
|
||||
name="FeedsTab"
|
||||
getComponent={() => FeedsTabNavigator}
|
||||
/>
|
||||
<MobileTab.Screen
|
||||
name="NotificationsTab"
|
||||
getComponent={() => NotificationsTabNavigator}
|
||||
/>
|
||||
<Tab.Screen
|
||||
<MobileTab.Screen
|
||||
name="MyProfileTab"
|
||||
getComponent={() => MyProfileTabNavigator}
|
||||
/>
|
||||
</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 (
|
||||
<>
|
||||
<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="FeedsTab"
|
||||
getComponent={() => FeedsTabNavigator}
|
||||
/>
|
||||
<TabletTab.Screen
|
||||
name="NotificationsTab"
|
||||
getComponent={() => NotificationsTabNavigator}
|
||||
/>
|
||||
<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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function HomeTabNavigator() {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<HomeTab.Navigator
|
||||
@@ -329,7 +407,7 @@ function HomeTabNavigator() {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<HomeTab.Screen
|
||||
name="Home"
|
||||
@@ -342,7 +420,7 @@ function HomeTabNavigator() {
|
||||
}
|
||||
|
||||
function SearchTabNavigator() {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<SearchTab.Navigator
|
||||
screenOptions={{
|
||||
@@ -351,7 +429,7 @@ function SearchTabNavigator() {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<SearchTab.Screen name="Search" getComponent={() => SearchScreen} />
|
||||
{commonScreens(SearchTab as typeof HomeTab)}
|
||||
@@ -360,7 +438,7 @@ function SearchTabNavigator() {
|
||||
}
|
||||
|
||||
function FeedsTabNavigator() {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<FeedsTab.Navigator
|
||||
screenOptions={{
|
||||
@@ -369,7 +447,7 @@ function FeedsTabNavigator() {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<FeedsTab.Screen
|
||||
name="Feeds"
|
||||
@@ -382,7 +460,7 @@ function FeedsTabNavigator() {
|
||||
}
|
||||
|
||||
function NotificationsTabNavigator() {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<NotificationsTab.Navigator
|
||||
screenOptions={{
|
||||
@@ -391,7 +469,7 @@ function NotificationsTabNavigator() {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<NotificationsTab.Screen
|
||||
name="Notifications"
|
||||
@@ -404,7 +482,7 @@ function NotificationsTabNavigator() {
|
||||
}
|
||||
|
||||
function MyProfileTabNavigator() {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
return (
|
||||
<MyProfileTab.Navigator
|
||||
screenOptions={{
|
||||
@@ -413,7 +491,7 @@ function MyProfileTabNavigator() {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<MyProfileTab.Screen
|
||||
// @ts-ignore // TODO: fix this broken type in ProfileScreen
|
||||
@@ -428,12 +506,78 @@ function MyProfileTabNavigator() {
|
||||
)
|
||||
}
|
||||
|
||||
function ListsTabNavigator() {
|
||||
const t = useTheme()
|
||||
return (
|
||||
<ListsTab.Navigator
|
||||
screenOptions={{
|
||||
animation: isAndroid ? 'none' : undefined,
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
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 ? 'none' : undefined,
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
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 ? 'none' : undefined,
|
||||
gestureEnabled: true,
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
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
|
||||
* in a single ("flat") stack.
|
||||
*/
|
||||
const FlatNavigator = () => {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
const numUnread = useUnreadNotifications()
|
||||
const screenListeners = useWebScrollRestoration()
|
||||
const title = (page: MessageDescriptor) => bskyTitle(i18n._(page), numUnread)
|
||||
@@ -446,7 +590,7 @@ const FlatNavigator = () => {
|
||||
fullScreenGestureEnabled: true,
|
||||
headerShown: false,
|
||||
animationDuration: 250,
|
||||
contentStyle: pal.view,
|
||||
contentStyle: t.atoms.bg,
|
||||
}}>
|
||||
<Flat.Screen
|
||||
name="Home"
|
||||
@@ -468,7 +612,7 @@ const FlatNavigator = () => {
|
||||
getComponent={() => NotificationsScreen}
|
||||
options={{title: title(msg`Notifications`), requireAuth: true}}
|
||||
/>
|
||||
{commonScreens(Flat as typeof HomeTab, numUnread)}
|
||||
{commonScreens(Flat as typeof HomeTab, {unreadCountLabel: numUnread})}
|
||||
</Flat.Navigator>
|
||||
)
|
||||
}
|
||||
@@ -515,12 +659,26 @@ const LINKING = {
|
||||
if (name === 'Search') {
|
||||
return buildStateObject('SearchTab', 'Search', params)
|
||||
}
|
||||
if (name === 'Feeds') {
|
||||
return buildStateObject('FeedsTab', 'Feeds', params)
|
||||
}
|
||||
if (name === 'Notifications') {
|
||||
return buildStateObject('NotificationsTab', 'Notifications', params)
|
||||
}
|
||||
if (name === 'Home') {
|
||||
return buildStateObject('HomeTab', 'Home', 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
|
||||
return buildStateObject('HomeTab', name, params, [
|
||||
{
|
||||
@@ -703,5 +861,6 @@ export {
|
||||
reset,
|
||||
resetToTab,
|
||||
RoutesContainer,
|
||||
TabNavigatorTablet,
|
||||
TabsNavigator,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {isNativeTablet} from '#/platform/detection'
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {Button, ButtonColor, ButtonText} from '#/components/Button'
|
||||
import * as Dialog from '#/components/Dialog'
|
||||
@@ -43,7 +44,11 @@ export function Outer({
|
||||
<Dialog.ScrollableInner
|
||||
accessibilityLabelledBy={titleId}
|
||||
accessibilityDescribedBy={descriptionId}
|
||||
style={[gtMobile ? {width: 'auto', maxWidth: 400} : a.w_full]}>
|
||||
style={[
|
||||
gtMobile && !isNativeTablet
|
||||
? {width: 'auto', maxWidth: 400}
|
||||
: a.w_full,
|
||||
]}>
|
||||
{children}
|
||||
</Dialog.ScrollableInner>
|
||||
</Context.Provider>
|
||||
@@ -81,7 +86,7 @@ export function Actions({children}: React.PropsWithChildren<{}>) {
|
||||
a.w_full,
|
||||
a.gap_md,
|
||||
a.justify_end,
|
||||
gtMobile
|
||||
gtMobile && !isNativeTablet
|
||||
? [a.flex_row, a.flex_row_reverse, a.justify_start]
|
||||
: [a.flex_col],
|
||||
]}>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useMediaQuery} from 'react-responsive'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {isNative, isNativeTablet} from 'platform/detection'
|
||||
|
||||
export function useWebMediaQueries() {
|
||||
const isDesktop = useMediaQuery({minWidth: 1300})
|
||||
@@ -7,6 +7,15 @@ export function useWebMediaQueries() {
|
||||
const isMobile = useMediaQuery({maxWidth: 800 - 1})
|
||||
const isTabletOrMobile = isMobile || isTablet
|
||||
const isTabletOrDesktop = isDesktop || isTablet
|
||||
if (isNativeTablet) {
|
||||
return {
|
||||
isMobile: false,
|
||||
isTablet: true,
|
||||
isTabletOrMobile: true,
|
||||
isTabletOrDesktop: true,
|
||||
isDesktop: false,
|
||||
}
|
||||
}
|
||||
if (isNative) {
|
||||
return {
|
||||
isMobile: true,
|
||||
|
||||
+11
-1
@@ -47,6 +47,17 @@ export type BottomTabNavigatorParams = CommonNavigatorParams & {
|
||||
MyProfileTab: undefined
|
||||
}
|
||||
|
||||
export type SideTabNavigatorParams = CommonNavigatorParams & {
|
||||
HomeTab: undefined
|
||||
SearchTab: undefined
|
||||
FeedsTab: undefined
|
||||
NotificationsTab: undefined
|
||||
MyProfileTab: undefined
|
||||
ListsTab: undefined
|
||||
ModerationTab: undefined
|
||||
SettingsTab: undefined
|
||||
}
|
||||
|
||||
export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
||||
Home: undefined
|
||||
}
|
||||
@@ -72,7 +83,6 @@ export type FlatNavigatorParams = CommonNavigatorParams & {
|
||||
Search: {q?: string}
|
||||
Feeds: undefined
|
||||
Notifications: undefined
|
||||
Hashtag: {tag: string; author?: string}
|
||||
}
|
||||
|
||||
export type AllNavigatorParams = CommonNavigatorParams & {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {dedupArray} from 'lib/functions'
|
||||
export const isIOS = Platform.OS === 'ios'
|
||||
export const isAndroid = Platform.OS === 'android'
|
||||
export const isNative = isIOS || isAndroid
|
||||
export const isNativeTablet = Platform.OS === 'ios' && Platform.isPad
|
||||
export const devicePlatform = isIOS ? 'ios' : isAndroid ? 'android' : 'web'
|
||||
export const isWeb = !isNative
|
||||
export const isMobileWebMediaQuery = 'only screen and (max-width: 1300px)'
|
||||
|
||||
@@ -58,7 +58,9 @@ export const SplashScreen = ({
|
||||
<Trans>What's up?</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
<View testID="signinOrCreateAccount">
|
||||
<View
|
||||
testID="signinOrCreateAccount"
|
||||
style={[a.w_full, a.mx_auto, {maxWidth: 450}]}>
|
||||
<Button
|
||||
testID="createAccountButton"
|
||||
onPress={onPressCreateAccount}
|
||||
|
||||
@@ -484,7 +484,7 @@ export const ComposePost = observer(function ComposePost({
|
||||
<OpenCameraBtn gallery={gallery} />
|
||||
</>
|
||||
) : null}
|
||||
{!isMobile ? (
|
||||
{!isMobile && !isNative ? (
|
||||
<Pressable
|
||||
onPress={onEmojiButtonPress}
|
||||
accessibilityRole="button"
|
||||
|
||||
@@ -7,7 +7,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {getRootNavigation, getTabState, TabState} from '#/lib/routes/helpers'
|
||||
import {logEvent, useGate} from '#/lib/statsig/statsig'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isNative, isNativeTablet} from '#/platform/detection'
|
||||
import {listenSoftReset} from '#/state/events'
|
||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||
import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed'
|
||||
@@ -155,9 +155,9 @@ export function FeedPage({
|
||||
}
|
||||
|
||||
function useHeaderOffset() {
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const {fontScale} = useWindowDimensions()
|
||||
if (isDesktop || isTablet) {
|
||||
if (isTabletOrDesktop && !isNativeTablet) {
|
||||
return 0
|
||||
}
|
||||
const navBarHeight = 42
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {Link} from '../util/Link'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
|
||||
import {HITSLOP_10} from 'lib/constants'
|
||||
import {
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
useWindowDimensions,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
|
||||
|
||||
import {useSetDrawerOpen} from '#/state/shell/drawer-open'
|
||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {HITSLOP_10} from 'lib/constants'
|
||||
import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
|
||||
import {isNativeTablet, isWeb} from 'platform/detection'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
|
||||
import {IS_DEV} from '#/env'
|
||||
import {atoms} from '#/alf'
|
||||
import {Link as Link2} from '#/components/Link'
|
||||
import {atoms, useTheme} from '#/alf'
|
||||
import {ColorPalette_Stroke2_Corner0_Rounded as ColorPalette} from '#/components/icons/ColorPalette'
|
||||
import {Link as Link2} from '#/components/Link'
|
||||
import {IS_DEV} from '#/env'
|
||||
import {Link} from '../util/Link'
|
||||
|
||||
export function HomeHeaderLayoutMobile({
|
||||
children,
|
||||
@@ -25,11 +28,22 @@ export function HomeHeaderLayoutMobile({
|
||||
children: React.ReactNode
|
||||
tabBarAnchor: JSX.Element | null | undefined
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const {headerHeight} = useShellLayout()
|
||||
const {headerMinimalShellTransform} = useMinimalShellMode()
|
||||
const {width} = useWindowDimensions()
|
||||
const t = useTheme()
|
||||
|
||||
let tabBarTablet
|
||||
if (isNativeTablet && width > 677) {
|
||||
tabBarTablet = {
|
||||
marginLeft: (width - 600) / 2,
|
||||
width: 600,
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
}
|
||||
}
|
||||
|
||||
const onPressAvi = React.useCallback(() => {
|
||||
setDrawerOpen(true)
|
||||
@@ -37,27 +51,35 @@ export function HomeHeaderLayoutMobile({
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
style={[pal.view, pal.border, styles.tabBar, headerMinimalShellTransform]}
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
t.atoms.border_contrast_medium,
|
||||
styles.tabBar,
|
||||
tabBarTablet,
|
||||
headerMinimalShellTransform,
|
||||
]}
|
||||
onLayout={e => {
|
||||
headerHeight.value = e.nativeEvent.layout.height
|
||||
}}>
|
||||
<View style={[pal.view, styles.topBar]}>
|
||||
<View style={[pal.view, {width: 100}]}>
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderDrawerBtn"
|
||||
onPress={onPressAvi}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`Open navigation`)}
|
||||
accessibilityHint={_(
|
||||
msg`Access profile and other navigation links`,
|
||||
)}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<FontAwesomeIcon
|
||||
icon="bars"
|
||||
size={18}
|
||||
color={pal.colors.textLight}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<View style={[t.atoms.bg, styles.topBar]}>
|
||||
<View style={[t.atoms.bg, {width: 100}]}>
|
||||
{!isNativeTablet ? (
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderDrawerBtn"
|
||||
onPress={onPressAvi}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`Open navigation`)}
|
||||
accessibilityHint={_(
|
||||
msg`Access profile and other navigation links`,
|
||||
)}
|
||||
hitSlop={HITSLOP_10}>
|
||||
<FontAwesomeIcon
|
||||
icon="bars"
|
||||
size={18}
|
||||
color={t.atoms.text_contrast_medium.color}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
) : null}
|
||||
</View>
|
||||
<View>
|
||||
<Logo width={30} />
|
||||
@@ -68,7 +90,7 @@ export function HomeHeaderLayoutMobile({
|
||||
atoms.justify_end,
|
||||
atoms.align_center,
|
||||
atoms.gap_md,
|
||||
pal.view,
|
||||
t.atoms.bg,
|
||||
{width: 100},
|
||||
]}>
|
||||
{IS_DEV && (
|
||||
@@ -85,7 +107,7 @@ export function HomeHeaderLayoutMobile({
|
||||
accessibilityHint="">
|
||||
<FontAwesomeIcon
|
||||
icon="sliders"
|
||||
style={pal.textLight as FontAwesomeIconStyle}
|
||||
color={t.atoms.text_contrast_medium.color}
|
||||
/>
|
||||
</Link>
|
||||
</View>
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
import * as React from 'react'
|
||||
import {
|
||||
LayoutChangeEvent,
|
||||
NativeScrollEvent,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
useWindowDimensions,
|
||||
View,
|
||||
NativeScrollEvent,
|
||||
} from 'react-native'
|
||||
import Animated, {
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
AnimatedRef,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
scrollTo,
|
||||
useAnimatedRef,
|
||||
AnimatedRef,
|
||||
SharedValue,
|
||||
useAnimatedRef,
|
||||
useAnimatedStyle,
|
||||
useSharedValue,
|
||||
} from 'react-native-reanimated'
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {TabBar} from './TabBar'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
import {ListMethods} from '../util/List'
|
||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||
import {isNativeTablet} from '#/platform/detection'
|
||||
import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
||||
import {useTheme} from '#/alf'
|
||||
import {ListMethods} from '../util/List'
|
||||
import {TabBar} from './TabBar'
|
||||
|
||||
export interface PagerWithHeaderChildParams {
|
||||
headerHeight: number
|
||||
@@ -234,10 +238,24 @@ let PagerTabBar = ({
|
||||
],
|
||||
}))
|
||||
const headerRef = React.useRef(null)
|
||||
const {width} = useWindowDimensions()
|
||||
const t = useTheme()
|
||||
|
||||
let tabBarTablet
|
||||
if (isNativeTablet && width > 677) {
|
||||
tabBarTablet = {
|
||||
marginLeft: (width - 600) / 2,
|
||||
width: 600,
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
...t.atoms.border_contrast_medium,
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
pointerEvents="box-none"
|
||||
style={[styles.tabBarMobile, headerTransform]}>
|
||||
style={[styles.tabBarMobile, tabBarTablet, headerTransform]}>
|
||||
<View ref={headerRef} pointerEvents="box-none" collapsable={false}>
|
||||
{renderHeader?.()}
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React, {useRef, useMemo, useEffect, useState, useCallback} from 'react'
|
||||
import {StyleSheet, View, ScrollView, LayoutChangeEvent} from 'react-native'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {PressableWithHover} from '../util/PressableWithHover'
|
||||
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
||||
import {LayoutChangeEvent, ScrollView, StyleSheet, View} from 'react-native'
|
||||
|
||||
import {isNative, isNativeTablet} from '#/platform/detection'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {PressableWithHover} from '../util/PressableWithHover'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {DraggableScrollView} from './DraggableScrollView'
|
||||
import {isNative} from '#/platform/detection'
|
||||
|
||||
export interface TabBarProps {
|
||||
testID?: string
|
||||
@@ -36,8 +37,9 @@ export function TabBar({
|
||||
() => ({borderBottomColor: indicatorColor || pal.colors.link}),
|
||||
[indicatorColor, pal],
|
||||
)
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const styles =
|
||||
isTabletOrDesktop && !isNativeTablet ? desktopStyles : mobileStyles
|
||||
|
||||
useEffect(() => {
|
||||
if (isNative) {
|
||||
@@ -137,7 +139,7 @@ export function TabBar({
|
||||
onPress={() => onPressItem(i)}>
|
||||
<View style={[styles.itemInner, selected && indicatorStyle]}>
|
||||
<Text
|
||||
type={isDesktop || isTablet ? 'xl-bold' : 'lg-bold'}
|
||||
type={isTabletOrDesktop ? 'xl-bold' : 'lg-bold'}
|
||||
testID={testID ? `${testID}-${item}` : undefined}
|
||||
style={selected ? pal.text : pal.textLight}>
|
||||
{item}
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import React from 'react'
|
||||
import {Pressable, StyleSheet, View} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {ImagesLightbox, useLightboxControls} from '#/state/lightbox'
|
||||
import {useSetDrawerOpen} from '#/state/shell'
|
||||
import {BACK_HITSLOP} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {TextLink} from '../util/Link'
|
||||
import {UserAvatar, UserAvatarType} from '../util/UserAvatar'
|
||||
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||
import {CenteredView} from '../util/Views'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {BACK_HITSLOP} from 'lib/constants'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {useLightboxControls, ImagesLightbox} from '#/state/lightbox'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans, msg} from '@lingui/macro'
|
||||
import {useSetDrawerOpen} from '#/state/shell'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {isNative, isNativeTablet} from 'platform/detection'
|
||||
import {TextLink} from '../util/Link'
|
||||
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {UserAvatar, UserAvatarType} from '../util/UserAvatar'
|
||||
import {CenteredView} from '../util/Views'
|
||||
|
||||
export function ProfileSubpageHeader({
|
||||
isLoading,
|
||||
@@ -71,9 +72,11 @@ export function ProfileSubpageHeader({
|
||||
}
|
||||
}, [openLightbox, avatar])
|
||||
|
||||
const isMobileLayout = isMobile || isNativeTablet
|
||||
|
||||
return (
|
||||
<CenteredView style={pal.view}>
|
||||
{isMobile && (
|
||||
{isMobileLayout && (
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
@@ -82,7 +85,7 @@ export function ProfileSubpageHeader({
|
||||
borderBottomWidth: 1,
|
||||
paddingTop: isNative ? 0 : 8,
|
||||
paddingBottom: 8,
|
||||
paddingHorizontal: isMobile ? 12 : 14,
|
||||
paddingHorizontal: isMobileLayout ? 12 : 14,
|
||||
},
|
||||
pal.border,
|
||||
]}>
|
||||
@@ -119,7 +122,7 @@ export function ProfileSubpageHeader({
|
||||
gap: 10,
|
||||
paddingTop: 14,
|
||||
paddingBottom: 6,
|
||||
paddingHorizontal: isMobile ? 12 : 14,
|
||||
paddingHorizontal: isMobileLayout ? 12 : 14,
|
||||
}}>
|
||||
<Pressable
|
||||
testID="headerAviButton"
|
||||
@@ -170,7 +173,7 @@ export function ProfileSubpageHeader({
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
{!isMobile && (
|
||||
{!isMobileLayout && (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React, {memo} from 'react'
|
||||
import {FlatListProps, RefreshControl} from 'react-native'
|
||||
import {FlatList_INTERNAL} from './Views'
|
||||
import {addStyle} from 'lib/styles'
|
||||
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||
import {FlatListProps, RefreshControl, useWindowDimensions} from 'react-native'
|
||||
import {runOnJS, useSharedValue} from 'react-native-reanimated'
|
||||
|
||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||
import {isNativeTablet} from '#/platform/detection'
|
||||
import {addStyle} from 'lib/styles'
|
||||
import {useTheme} from '#/alf'
|
||||
import {FlatList_INTERNAL} from './Views'
|
||||
|
||||
export type ListMethods = FlatList_INTERNAL
|
||||
export type ListProps<ItemT> = Omit<
|
||||
@@ -30,13 +32,15 @@ function ListImpl<ItemT>(
|
||||
onRefresh,
|
||||
headerOffset,
|
||||
style,
|
||||
contentContainerStyle,
|
||||
...props
|
||||
}: ListProps<ItemT>,
|
||||
ref: React.Ref<ListMethods>,
|
||||
) {
|
||||
const isScrolledDown = useSharedValue(false)
|
||||
const contextScrollHandlers = useScrollHandlers()
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
const {width} = useWindowDimensions()
|
||||
|
||||
function handleScrolledDownChange(didScrollDown: boolean) {
|
||||
onScrolledDownChange?.(didScrollDown)
|
||||
@@ -68,8 +72,8 @@ function ListImpl<ItemT>(
|
||||
<RefreshControl
|
||||
refreshing={refreshing ?? false}
|
||||
onRefresh={onRefresh}
|
||||
tintColor={pal.colors.text}
|
||||
titleColor={pal.colors.text}
|
||||
tintColor={t.atoms.text.color}
|
||||
titleColor={t.atoms.text.color}
|
||||
progressViewOffset={headerOffset}
|
||||
/>
|
||||
)
|
||||
@@ -83,6 +87,16 @@ function ListImpl<ItemT>(
|
||||
contentOffset = {x: 0, y: headerOffset * -1}
|
||||
}
|
||||
|
||||
if (isNativeTablet && width > 677) {
|
||||
contentContainerStyle = addStyle(contentContainerStyle, {
|
||||
marginLeft: (width - 600) / 2,
|
||||
width: 600,
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
...t.atoms.border_contrast_medium,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList_INTERNAL
|
||||
{...props}
|
||||
@@ -92,6 +106,7 @@ function ListImpl<ItemT>(
|
||||
onScroll={scrollHandler}
|
||||
scrollEventThrottle={1}
|
||||
style={style}
|
||||
contentContainerStyle={contentContainerStyle}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -8,13 +8,14 @@ import {
|
||||
} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {CenteredView} from './Views'
|
||||
|
||||
import {isNativeTablet, isWeb} from '#/platform/detection'
|
||||
import {useSetDrawerOpen} from '#/state/shell'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
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'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {CenteredView} from './Views'
|
||||
|
||||
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
|
||||
|
||||
@@ -71,13 +72,13 @@ export function SimpleViewHeader({
|
||||
icon="angle-left"
|
||||
style={[styles.backIcon, pal.text]}
|
||||
/>
|
||||
) : (
|
||||
) : !isNativeTablet ? (
|
||||
<FontAwesomeIcon
|
||||
size={18}
|
||||
icon="bars"
|
||||
style={[styles.backIcon, pal.textLight]}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
</TouchableOpacity>
|
||||
) : null}
|
||||
{children}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {FABInner, FABProps} from './FABInner'
|
||||
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {FABInner, FABProps} from './FABInner'
|
||||
|
||||
export const FAB = (_opts: FABProps) => {
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react'
|
||||
import {ScrollView, StyleSheet, View} from 'react-native'
|
||||
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
@@ -73,9 +72,7 @@ export const LoggedOutLayout = ({
|
||||
contentContainerStyle={styles.scrollViewContentContainer}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
keyboardDismissMode="on-drag">
|
||||
<View style={[styles.contentWrapper, isWeb && a.my_auto]}>
|
||||
{children}
|
||||
</View>
|
||||
<View style={[styles.contentWrapper]}>{children}</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
) : (
|
||||
@@ -92,6 +89,7 @@ const styles = StyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
// @ts-ignore web only
|
||||
height: '100vh',
|
||||
flex: 1,
|
||||
},
|
||||
side: {
|
||||
flex: 1,
|
||||
@@ -111,8 +109,9 @@ const styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
},
|
||||
scrollViewContentContainer: {
|
||||
flex: 1,
|
||||
flexGrow: 1,
|
||||
paddingHorizontal: 40,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
leadinText: {
|
||||
fontSize: 36,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import {isNative} from 'platform/detection'
|
||||
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
export const withBreakpoints = <P extends object>(
|
||||
@@ -8,12 +8,12 @@ export const withBreakpoints = <P extends object>(
|
||||
Desktop: React.ComponentType<P>,
|
||||
): React.FC<P> =>
|
||||
function WithBreakpoints(props: P) {
|
||||
const {isMobile, isTabletOrMobile} = useWebMediaQueries()
|
||||
const {isMobile, isTablet} = useWebMediaQueries()
|
||||
|
||||
if (isMobile || isNative) {
|
||||
if (isMobile) {
|
||||
return <Mobile {...props} />
|
||||
}
|
||||
if (isTabletOrMobile) {
|
||||
if (isTablet) {
|
||||
return <Tablet {...props} />
|
||||
}
|
||||
return <Desktop {...props} />
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {useMediaQuery} from 'react-responsive'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {colors} from 'lib/styles'
|
||||
import {HITSLOP_20} from 'lib/constants'
|
||||
import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
|
||||
|
||||
import {HITSLOP_20} from '#/lib/constants'
|
||||
import {useMinimalShellMode} from '#/lib/hooks/useMinimalShellMode'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {colors} from '#/lib/styles'
|
||||
import {isNativeTablet, isWeb} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useTheme} from '#/alf'
|
||||
|
||||
const AnimatedTouchableOpacity =
|
||||
Animated.createAnimatedComponent(TouchableOpacity)
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {useSession} from 'state/session'
|
||||
|
||||
export function LoadLatestBtn({
|
||||
onPress,
|
||||
@@ -22,7 +24,7 @@ export function LoadLatestBtn({
|
||||
label: string
|
||||
showIndicator: boolean
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
const {hasSession} = useSession()
|
||||
const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
|
||||
const {fabMinimalShellTransform} = useMinimalShellMode()
|
||||
@@ -42,9 +44,9 @@ export function LoadLatestBtn({
|
||||
(isTallViewport
|
||||
? styles.loadLatestOutOfLine
|
||||
: styles.loadLatestInline),
|
||||
isTablet && styles.loadLatestInline,
|
||||
pal.borderDark,
|
||||
pal.view,
|
||||
isTablet && !isNativeTablet && styles.loadLatestInline,
|
||||
t.atoms.border_contrast_high,
|
||||
t.atoms.bg,
|
||||
showBottomBar && fabMinimalShellTransform,
|
||||
]}
|
||||
onPress={onPress}
|
||||
@@ -52,8 +54,10 @@ export function LoadLatestBtn({
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={label}
|
||||
accessibilityHint="">
|
||||
<FontAwesomeIcon icon="angle-up" color={pal.colors.text} size={19} />
|
||||
{showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
|
||||
<FontAwesomeIcon icon="angle-up" color={t.atoms.text.color} size={19} />
|
||||
{showIndicator && (
|
||||
<View style={[styles.indicator, t.atoms.border_contrast_high]} />
|
||||
)}
|
||||
</AnimatedTouchableOpacity>
|
||||
)
|
||||
}
|
||||
@@ -72,10 +76,12 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
loadLatestInline: {
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw - 282px)',
|
||||
},
|
||||
// @ts-ignore web only
|
||||
loadLatestInline: isWeb
|
||||
? {
|
||||
left: 'calc(50vw - 282px)',
|
||||
}
|
||||
: {},
|
||||
loadLatestOutOfLine: {
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw - 382px)',
|
||||
|
||||
@@ -461,7 +461,7 @@ export function SearchScreen(
|
||||
const moderationOpts = useModerationOpts()
|
||||
const search = useActorAutocompleteFn()
|
||||
const setMinimalShellMode = useSetMinimalShellMode()
|
||||
const {isTabletOrDesktop, isTabletOrMobile} = useWebMediaQueries()
|
||||
const {isTabletOrDesktop, isMobile} = useWebMediaQueries()
|
||||
|
||||
const searchDebounceTimeout = React.useRef<NodeJS.Timeout | undefined>(
|
||||
undefined,
|
||||
@@ -637,8 +637,8 @@ export function SearchScreen(
|
||||
pal.view,
|
||||
isTabletOrDesktop && {paddingTop: 10},
|
||||
]}
|
||||
sideBorders={isTabletOrDesktop}>
|
||||
{isTabletOrMobile && (
|
||||
sideBorders={isMobile}>
|
||||
{isMobile && (
|
||||
<Pressable
|
||||
testID="viewHeaderBackOrMenuBtn"
|
||||
onPress={onPressMenu}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import * as React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {PWI_ENABLED, NEW_ONBOARDING_ENABLED} from '#/lib/build-flags'
|
||||
|
||||
// Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts
|
||||
// MIT License
|
||||
// Copyright (c) 2017 React Navigation Contributors
|
||||
|
||||
import {
|
||||
createNavigatorFactory,
|
||||
EventArg,
|
||||
@@ -21,24 +18,25 @@ import type {
|
||||
NativeStackNavigationEventMap,
|
||||
NativeStackNavigationOptions,
|
||||
} from '@react-navigation/native-stack'
|
||||
import type {NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types'
|
||||
import {NativeStackView} from '@react-navigation/native-stack'
|
||||
import type {NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types'
|
||||
|
||||
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
||||
import {DesktopLeftNav} from './desktop/LeftNav'
|
||||
import {DesktopRightNav} from './desktop/RightNav'
|
||||
import {NEW_ONBOARDING_ENABLED, PWI_ENABLED} from '#/lib/build-flags'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useOnboardingState} from '#/state/shell'
|
||||
import {
|
||||
useLoggedOutView,
|
||||
useLoggedOutViewControls,
|
||||
} from '#/state/shell/logged-out'
|
||||
import {useSession} from '#/state/session'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {Deactivated} from '#/screens/Deactivated'
|
||||
import {Onboarding as NewOnboarding} from '#/screens/Onboarding'
|
||||
import {LoggedOut} from '../com/auth/LoggedOut'
|
||||
import {Onboarding} from '../com/auth/Onboarding'
|
||||
import {Onboarding as NewOnboarding} from '#/screens/Onboarding'
|
||||
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
||||
import {LeftNav} from './desktop/LeftNav'
|
||||
import {DesktopRightNav} from './desktop/RightNav'
|
||||
|
||||
type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & {
|
||||
requireAuth?: boolean
|
||||
@@ -149,7 +147,7 @@ function NativeStackNavigator({
|
||||
{isWeb && showBottomBar && <BottomBarWeb />}
|
||||
{isWeb && !showBottomBar && (
|
||||
<>
|
||||
<DesktopLeftNav />
|
||||
<LeftNav />
|
||||
<DesktopRightNav routeName={activeRoute.name} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,52 +1,55 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {PressableWithHover} from 'view/com/util/PressableWithHover'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {
|
||||
useLinkProps,
|
||||
useNavigation,
|
||||
useNavigationState,
|
||||
} from '@react-navigation/native'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||
import {Link} from 'view/com/util/Link'
|
||||
import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
||||
|
||||
import {isInvalidHandle} from '#/lib/strings/handles'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {useFetchHandle} from '#/state/queries/handle'
|
||||
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {
|
||||
HomeIcon,
|
||||
HomeIconSolid,
|
||||
MagnifyingGlassIcon2,
|
||||
MagnifyingGlassIcon2Solid,
|
||||
BellIcon,
|
||||
BellIconSolid,
|
||||
UserIcon,
|
||||
UserIconSolid,
|
||||
CogIcon,
|
||||
CogIconSolid,
|
||||
ComposeIcon2,
|
||||
ListIcon,
|
||||
HashtagIcon,
|
||||
HandIcon,
|
||||
HashtagIcon,
|
||||
HomeIcon,
|
||||
HomeIconSolid,
|
||||
ListIcon,
|
||||
MagnifyingGlassIcon2,
|
||||
MagnifyingGlassIcon2Solid,
|
||||
UserIcon,
|
||||
UserIconSolid,
|
||||
} from 'lib/icons'
|
||||
import {getCurrentRoute, isTab, isStateAtTabRoot} from 'lib/routes/helpers'
|
||||
import {NavigationProp, CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {router} from '../../../routes'
|
||||
import {getCurrentRoute, isStateAtTabRoot, isTab} from 'lib/routes/helpers'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Trans, msg} from '@lingui/macro'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useFetchHandle} from '#/state/queries/handle'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
|
||||
import {colors, s} from 'lib/styles'
|
||||
import {NavSignupCard} from '#/view/shell/NavSignupCard'
|
||||
import {isInvalidHandle} from '#/lib/strings/handles'
|
||||
import {Link} from 'view/com/util/Link'
|
||||
import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
||||
import {PressableWithHover} from 'view/com/util/PressableWithHover'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||
import {router} from '../../../routes'
|
||||
|
||||
function ProfileCard() {
|
||||
const {currentAccount} = useSession()
|
||||
@@ -266,12 +269,13 @@ function ComposeBtn() {
|
||||
)
|
||||
}
|
||||
|
||||
export function DesktopLeftNav() {
|
||||
export function LeftNav() {
|
||||
const {hasSession, currentAccount} = useSession()
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
const numUnread = useUnreadNotifications()
|
||||
const {top} = useSafeAreaInsets()
|
||||
|
||||
if (!hasSession && !isDesktop) {
|
||||
return null
|
||||
@@ -281,7 +285,7 @@ export function DesktopLeftNav() {
|
||||
<View
|
||||
style={[
|
||||
styles.leftNav,
|
||||
isTablet && styles.leftNavTablet,
|
||||
isTablet && [styles.leftNavTablet, {top}],
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
@@ -445,25 +449,27 @@ export function DesktopLeftNav() {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
leftNav: {
|
||||
// @ts-ignore web only
|
||||
position: 'fixed',
|
||||
top: 10,
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw - 300px - 220px - 20px)',
|
||||
width: 220,
|
||||
// @ts-ignore web only
|
||||
maxHeight: 'calc(100vh - 10px)',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
// @ts-ignore web only
|
||||
leftNav: isWeb
|
||||
? {
|
||||
position: 'fixed',
|
||||
top: 10,
|
||||
left: 'calc(50vw - 300px - 220px - 20px)',
|
||||
width: 220,
|
||||
maxHeight: 'calc(100vh - 10px)',
|
||||
overflowY: 'auto',
|
||||
}
|
||||
: {
|
||||
paddingTop: 12,
|
||||
},
|
||||
leftNavTablet: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 'auto',
|
||||
borderRightWidth: 1,
|
||||
height: '100%',
|
||||
width: 76,
|
||||
alignItems: 'center',
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
},
|
||||
|
||||
profileCard: {
|
||||
@@ -513,6 +519,7 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
paddingHorizontal: 4,
|
||||
borderRadius: 6,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
navItemCountTablet: {
|
||||
left: 18,
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {DesktopSearch} from './Search'
|
||||
import {DesktopFeeds} from './Feeds'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {TextLink} from 'view/com/util/Link'
|
||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
|
||||
import {s} from 'lib/styles'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {useSession} from '#/state/session'
|
||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {s} from 'lib/styles'
|
||||
import {TextLink} from 'view/com/util/Link'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {DesktopFeeds} from './Feeds'
|
||||
import {DesktopSearch} from './Search'
|
||||
|
||||
export function DesktopRightNav({routeName}: {routeName: string}) {
|
||||
const pal = usePalette('default')
|
||||
@@ -97,15 +98,18 @@ export function DesktopRightNav({routeName}: {routeName: string}) {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
rightNav: {
|
||||
// @ts-ignore web only
|
||||
position: 'fixed',
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw + 300px + 20px)',
|
||||
width: 300,
|
||||
maxHeight: '100%',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
// @ts-ignore web only
|
||||
rightNav: isWeb
|
||||
? {
|
||||
position: 'fixed',
|
||||
left: 'calc(50vw + 300px + 20px)',
|
||||
width: 300,
|
||||
maxHeight: '100%',
|
||||
overflowY: 'auto',
|
||||
}
|
||||
: {
|
||||
width: 300,
|
||||
},
|
||||
|
||||
message: {
|
||||
paddingVertical: 18,
|
||||
|
||||
+31
-26
@@ -1,37 +1,38 @@
|
||||
import React from 'react'
|
||||
import {StatusBar} from 'expo-status-bar'
|
||||
import {
|
||||
BackHandler,
|
||||
DimensionValue,
|
||||
StyleSheet,
|
||||
useWindowDimensions,
|
||||
View,
|
||||
BackHandler,
|
||||
} from 'react-native'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {Drawer} from 'react-native-drawer-layout'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {StatusBar} from 'expo-status-bar'
|
||||
import {useNavigationState} from '@react-navigation/native'
|
||||
import {ModalsContainer} from 'view/com/modals/Modal'
|
||||
import {Lightbox} from 'view/com/lightbox/Lightbox'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {DrawerContent} from './Drawer'
|
||||
import {Composer} from './Composer'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {RoutesContainer, TabsNavigator} from '../../Navigation'
|
||||
import {isStateAtTabRoot} from 'lib/routes/helpers'
|
||||
|
||||
import {useSession} from '#/state/session'
|
||||
import {
|
||||
useIsDrawerOpen,
|
||||
useSetDrawerOpen,
|
||||
useIsDrawerSwipeDisabled,
|
||||
useSetDrawerOpen,
|
||||
} from '#/state/shell'
|
||||
import {isAndroid} from 'platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useCloseAnyActiveElement} from '#/state/util'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import * as notifications from 'lib/notifications/notifications'
|
||||
import {Outlet as PortalOutlet} from '#/components/Portal'
|
||||
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
||||
import {isStateAtTabRoot} from 'lib/routes/helpers'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {isAndroid, isNativeTablet} from 'platform/detection'
|
||||
import {useDialogStateContext} from 'state/dialogs'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {Lightbox} from 'view/com/lightbox/Lightbox'
|
||||
import {ModalsContainer} from 'view/com/modals/Modal'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
|
||||
import {Outlet as PortalOutlet} from '#/components/Portal'
|
||||
import {RoutesContainer, TabsNavigator} from '../../Navigation'
|
||||
import {Composer} from './Composer'
|
||||
import {DrawerContent} from './Drawer'
|
||||
|
||||
function ShellInner() {
|
||||
const isDrawerOpen = useIsDrawerOpen()
|
||||
@@ -87,15 +88,19 @@ function ShellInner() {
|
||||
style={containerPadding}
|
||||
importantForAccessibility={importantForAccessibility}>
|
||||
<ErrorBoundary>
|
||||
<Drawer
|
||||
renderDrawerContent={renderDrawerContent}
|
||||
open={isDrawerOpen}
|
||||
onOpen={onOpenDrawer}
|
||||
onClose={onCloseDrawer}
|
||||
swipeEdgeWidth={winDim.width / 2}
|
||||
swipeEnabled={!canGoBack && hasSession && !isDrawerSwipeDisabled}>
|
||||
{!isNativeTablet ? (
|
||||
<Drawer
|
||||
renderDrawerContent={renderDrawerContent}
|
||||
open={isDrawerOpen}
|
||||
onOpen={onOpenDrawer}
|
||||
onClose={onCloseDrawer}
|
||||
swipeEdgeWidth={winDim.width / 2}
|
||||
swipeEnabled={!canGoBack && hasSession && !isDrawerSwipeDisabled}>
|
||||
<TabsNavigator />
|
||||
</Drawer>
|
||||
) : (
|
||||
<TabsNavigator />
|
||||
</Drawer>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
</Animated.View>
|
||||
<Composer winHeight={winDim.height} />
|
||||
|
||||
Reference in New Issue
Block a user