From eeac64cc88f37fe561e3c4361f40681fbe2f6d99 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 6 Mar 2023 10:54:56 -0600 Subject: Look & feel updates: replace the "FAB" with a footer menu item, update the side menu (#263) * Remove old tab controls from the mobile shell * Add 'compose' and 'profile' to the footer; remove the FAB * Fix lint * Tune the footer icons * Tune the 'current' state of footer icons * Add 2xl text styles * Tune the footer icons a bit more * Fix lint * More footer tuning --- src/lib/ThemeContext.tsx | 5 + src/lib/icons.tsx | 202 +++++++++++++++++++- src/lib/styles.ts | 1 + src/lib/themes.ts | 25 +++ src/view/index.ts | 2 + src/view/screens/Debug.tsx | 15 ++ src/view/screens/Home.tsx | 12 +- src/view/screens/Profile.tsx | 6 - src/view/shell/mobile/Menu.tsx | 253 ++++++++++++++----------- src/view/shell/mobile/TabsSelector.tsx | 327 --------------------------------- src/view/shell/mobile/index.tsx | 288 +++++++++++------------------ 11 files changed, 498 insertions(+), 638 deletions(-) delete mode 100644 src/view/shell/mobile/TabsSelector.tsx (limited to 'src') diff --git a/src/lib/ThemeContext.tsx b/src/lib/ThemeContext.tsx index bcfc076f4..ef17c1e7a 100644 --- a/src/lib/ThemeContext.tsx +++ b/src/lib/ThemeContext.tsx @@ -28,6 +28,11 @@ export type ShapeName = 'button' | 'bigButton' | 'smallButton' export type Shapes = Record export type TypographyVariant = + | '2xl-thin' + | '2xl' + | '2xl-medium' + | '2xl-bold' + | '2xl-heavy' | 'xl-thin' | 'xl' | 'xl-medium' diff --git a/src/lib/icons.tsx b/src/lib/icons.tsx index 931e3c721..e763ed1b2 100644 --- a/src/lib/icons.tsx +++ b/src/lib/icons.tsx @@ -1,6 +1,6 @@ import React from 'react' import {StyleProp, TextStyle, ViewStyle} from 'react-native' -import Svg, {Path, Rect} from 'react-native-svg' +import Svg, {Path, Rect, Line, Ellipse} from 'react-native-svg' export function GridIcon({ style, @@ -72,9 +72,13 @@ export function HomeIcon({ export function HomeIconSolid({ style, size, + strokeWidth = 4, + fillOpacity = 1, }: { style?: StyleProp size?: string | number + strokeWidth?: number + fillOpacity?: number }) { return ( + @@ -121,37 +130,74 @@ export function MagnifyingGlassIcon({ ) } -// https://github.com/Remix-Design/RemixIcon/blob/master/License -export function BellIcon({ +export function MagnifyingGlassIcon2({ style, size, + strokeWidth = 2, }: { style?: StyleProp size?: string | number + strokeWidth?: number }) { return ( - - + + + ) +} + +export function MagnifyingGlassIcon2Solid({ + style, + size, + strokeWidth = 2, + fillOpacity = 1, +}: { + style?: StyleProp + size?: string | number + strokeWidth?: number + fillOpacity?: number +}) { + return ( + + + + ) } // https://github.com/Remix-Design/RemixIcon/blob/master/License -export function BellIconSolid({ +export function BellIcon({ style, size, + strokeWidth = 1.5, }: { style?: StyleProp size?: string | number + strokeWidth?: number }) { return ( + + + + ) +} + +// https://github.com/Remix-Design/RemixIcon/blob/master/License +export function BellIconSolid({ + style, + size, + strokeWidth = 1.5, + fillOpacity = 1, +}: { + style?: StyleProp + size?: string | number + strokeWidth?: number + fillOpacity?: number +}) { + return ( + - + + ) } @@ -527,6 +604,7 @@ export function RectTallIcon({ ) } + export function ComposeIcon({ style, size, @@ -553,3 +631,107 @@ export function ComposeIcon({ ) } + +export function ComposeIcon2({ + style, + size, + strokeWidth = 1.5, + backgroundColor, +}: { + style?: StyleProp + size?: string | number + strokeWidth?: number + backgroundColor: string +}) { + return ( + + + + + + + ) +} + +export function SquarePlusIcon({ + style, + size, + strokeWidth = 1.5, +}: { + style?: StyleProp + size?: string | number + strokeWidth?: number +}) { + return ( + + + + + + ) +} diff --git a/src/lib/styles.ts b/src/lib/styles.ts index f6e26d53f..d307e9ba8 100644 --- a/src/lib/styles.ts +++ b/src/lib/styles.ts @@ -23,6 +23,7 @@ export const colors = { blue3: '#0085ff', blue4: '#0062bd', blue5: '#034581', + blue6: '#012561', red1: '#ffe6f2', red2: '#fba2ce', diff --git a/src/lib/themes.ts b/src/lib/themes.ts index c544eebf2..aa166e323 100644 --- a/src/lib/themes.ts +++ b/src/lib/themes.ts @@ -82,6 +82,31 @@ export const defaultTheme: Theme = { }, }, typography: { + '2xl-thin': { + fontSize: 18, + letterSpacing: 0.25, + fontWeight: '300', + }, + '2xl': { + fontSize: 18, + letterSpacing: 0.25, + fontWeight: '400', + }, + '2xl-medium': { + fontSize: 18, + letterSpacing: 0.25, + fontWeight: '500', + }, + '2xl-bold': { + fontSize: 18, + letterSpacing: 0.25, + fontWeight: '700', + }, + '2xl-heavy': { + fontSize: 18, + letterSpacing: 0.25, + fontWeight: '800', + }, 'xl-thin': { fontSize: 17, letterSpacing: 0.25, diff --git a/src/view/index.ts b/src/view/index.ts index d1e9d2036..17e9dbbed 100644 --- a/src/view/index.ts +++ b/src/view/index.ts @@ -56,6 +56,7 @@ import {faPlus} from '@fortawesome/free-solid-svg-icons/faPlus' import {faShare} from '@fortawesome/free-solid-svg-icons/faShare' import {faShareFromSquare} from '@fortawesome/free-solid-svg-icons/faShareFromSquare' import {faShield} from '@fortawesome/free-solid-svg-icons/faShield' +import {faSquarePlus} from '@fortawesome/free-regular-svg-icons/faSquarePlus' import {faSignal} from '@fortawesome/free-solid-svg-icons/faSignal' import {faReply} from '@fortawesome/free-solid-svg-icons/faReply' import {faRetweet} from '@fortawesome/free-solid-svg-icons/faRetweet' @@ -131,6 +132,7 @@ export function setup() { faShare, faShareFromSquare, faShield, + faSquarePlus, faSignal, faUser, faUsers, diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx index 52a84c649..657f38d57 100644 --- a/src/view/screens/Debug.tsx +++ b/src/view/screens/Debug.tsx @@ -207,6 +207,21 @@ function TypographyView() { const pal = usePalette('default') return ( + + '2xl-thin' lorem ipsum dolor + + + '2xl' lorem ipsum dolor + + + '2xl-medium' lorem ipsum dolor + + + '2xl-bold' lorem ipsum dolor + + + '2xl-heavy' lorem ipsum dolor + 'xl-thin' lorem ipsum dolor diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 5b5699bcc..b9611757c 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -4,7 +4,6 @@ import {observer} from 'mobx-react-lite' import useAppState from 'react-native-appstate-hook' import {ViewHeader} from '../com/util/ViewHeader' import {Feed} from '../com/posts/Feed' -import {FAB} from '../com/util/FAB' import {LoadLatestBtn} from '../com/util/LoadLatestBtn' import {useStores} from 'state/index' import {ScreenParams} from '../routes' @@ -17,7 +16,7 @@ const HEADER_HEIGHT = 42 export const Home = observer(function Home({navIdx, visible}: ScreenParams) { const store = useStores() const onMainScroll = useOnMainScroll(store) - const {screen, track} = useAnalytics() + const {screen} = useAnalytics() const scrollElRef = React.useRef(null) const [wasVisible, setWasVisible] = React.useState(false) const {appState} = useAppState({ @@ -75,10 +74,6 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) { return cleanup }, [visible, store, store.me.mainFeed, navIdx, doPoll, wasVisible, scrollToTop, screen]) - const onPressCompose = (imagesOpen?: boolean) => { - track('Home:ComposeButtonPressed') - store.shell.openComposer({imagesOpen}) - } const onPressTryAgain = () => { store.me.mainFeed.refresh() } @@ -105,11 +100,6 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) { {store.me.mainFeed.hasNewLatest && !store.me.mainFeed.isRefreshing && ( )} - onPressCompose(false)} - /> ) }) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 03d973b96..7739814f5 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -13,7 +13,6 @@ import {ErrorScreen} from '../com/util/error/ErrorScreen' import {ErrorMessage} from '../com/util/error/ErrorMessage' import {EmptyState} from '../com/util/EmptyState' import {Text} from '../com/util/text/Text' -import {FAB} from '../com/util/FAB' import {s, colors} from 'lib/styles' import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' import {useAnalytics} from 'lib/analytics' @@ -87,10 +86,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { uiState.setup() } - const onPressCompose = () => { - store.shell.openComposer({}) - } - // rendering // = @@ -191,7 +186,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => { ) : ( {renderHeader()} )} - ) }) diff --git a/src/view/shell/mobile/Menu.tsx b/src/view/shell/mobile/Menu.tsx index ceeda8c58..23c09b82c 100644 --- a/src/view/shell/mobile/Menu.tsx +++ b/src/view/shell/mobile/Menu.tsx @@ -17,19 +17,23 @@ import {FEEDBACK_FORM_URL} from 'lib/constants' import {useStores} from 'state/index' import { HomeIcon, + HomeIconSolid, BellIcon, + BellIconSolid, UserIcon, CogIcon, - MagnifyingGlassIcon, + MagnifyingGlassIcon2, + MagnifyingGlassIcon2Solid, } from 'lib/icons' import {TabPurpose, TabPurposeMainPath} from 'state/models/navigation' import {UserAvatar} from '../../com/util/UserAvatar' import {Text} from '../../com/util/text/Text' -import {ToggleButton} from '../../com/util/forms/ToggleButton' +import {useTheme} from 'lib/ThemeContext' import {usePalette} from 'lib/hooks/usePalette' import {useAnalytics} from 'lib/analytics' export const Menu = observer(({onClose}: {onClose: () => void}) => { + const theme = useTheme() const pal = usePalette('default') const store = useStores() const {track} = useAnalytics() @@ -89,11 +93,8 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => { ) : undefined} {label} @@ -105,68 +106,114 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => { store.shell.setDarkMode(!store.shell.darkMode) } + const isAtHome = + store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Default] + const isAtSearch = + store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Search] + const isAtNotifications = + store.nav.tab.current.url === TabPurposeMainPath[TabPurpose.Notifs] + return ( onNavigate(`/profile/${store.me.handle}`)} - style={styles.profileCard}> + onPress={() => onNavigate(`/profile/${store.me.handle}`)}> - - - {store.me.displayName || store.me.handle} - - - @{store.me.handle} - - - - onNavigate('/search')}> - } - size={25} - /> - - Search + + {store.me.displayName || store.me.handle} + + + @{store.me.handle} - + + + } + size={24} + strokeWidth={1.7} + /> + ) : ( + } + size={24} + strokeWidth={1.7} + /> + ) + } + label="Search" + url="/search" + bold={isAtSearch} + /> } size="26" />} + icon={ + isAtHome ? ( + } + size="24" + strokeWidth={3.25} + fillOpacity={1} + /> + ) : ( + } + size="24" + strokeWidth={3.25} + /> + ) + } label="Home" url="/" + bold={isAtHome} /> } size="28" />} + icon={ + isAtNotifications ? ( + } + size="24" + strokeWidth={1.7} + fillOpacity={1} + /> + ) : ( + } + size="24" + strokeWidth={1.7} + /> + ) + } label="Notifications" url="/notifications" count={store.me.notifications.unreadCount} + bold={isAtNotifications} /> } - size="30" - strokeWidth={2} + size="26" + strokeWidth={1.5} /> } label="Profile" @@ -176,34 +223,46 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => { icon={ } - size="30" - strokeWidth={2} + size="26" + strokeWidth={1.75} /> } label="Settings" url="/settings" /> - - - - - } - label="Feedback" + + } + size="26" + strokeWidth={1.75} + /> + + + style={[ + styles.footerBtn, + styles.footerBtnFeedback, + theme.colorScheme === 'light' + ? styles.footerBtnFeedbackLight + : styles.footerBtnFeedbackDark, + ]}> + + + Feedback + + ) @@ -212,70 +271,37 @@ export const Menu = observer(({onClose}: {onClose: () => void}) => { const styles = StyleSheet.create({ view: { flex: 1, + paddingTop: 10, paddingBottom: 90, + paddingLeft: 30, + }, + viewDarkMode: { + backgroundColor: colors.gray8, }, viewMinimalShell: { paddingBottom: 50, }, - section: { - paddingHorizontal: 10, - paddingTop: 10, - paddingBottom: 10, - borderBottomWidth: 1, - }, - heading: { - paddingVertical: 8, - paddingHorizontal: 4, - }, - profileCard: { - flexDirection: 'row', - alignItems: 'center', - margin: 10, - marginBottom: 6, - }, profileCardDisplayName: { - marginLeft: 12, + marginTop: 20, }, profileCardHandle: { - marginLeft: 12, - }, - - searchBtn: { - flexDirection: 'row', - borderRadius: 8, - margin: 10, - marginBottom: 0, - paddingVertical: 10, - paddingHorizontal: 12, - }, - searchBtnLabel: { - marginLeft: 14, - fontWeight: 'normal', + marginTop: 4, }, menuItem: { flexDirection: 'row', alignItems: 'center', - paddingVertical: 6, - paddingLeft: 6, + paddingVertical: 16, paddingRight: 10, }, menuItemIconWrapper: { - width: 36, - height: 36, + width: 24, + height: 24, alignItems: 'center', justifyContent: 'center', marginRight: 12, }, - menuItemLabel: { - flex: 1, - fontWeight: 'normal', - }, - menuItemLabelBold: { - flex: 1, - fontWeight: 'bold', - }, menuItemCount: { position: 'absolute', right: -6, @@ -292,6 +318,27 @@ const styles = StyleSheet.create({ }, footer: { - paddingHorizontal: 10, + flexDirection: 'row', + justifyContent: 'space-between', + paddingRight: 30, + paddingTop: 20, + }, + footerBtn: { + flexDirection: 'row', + alignItems: 'center', + padding: 10, + borderRadius: 25, + }, + footerBtnDarkMode: { + backgroundColor: colors.black, + }, + footerBtnFeedback: { + paddingHorizontal: 24, + }, + footerBtnFeedbackLight: { + backgroundColor: '#DDEFFF', + }, + footerBtnFeedbackDark: { + backgroundColor: colors.blue6, }, }) diff --git a/src/view/shell/mobile/TabsSelector.tsx b/src/view/shell/mobile/TabsSelector.tsx deleted file mode 100644 index 92854e3b6..000000000 --- a/src/view/shell/mobile/TabsSelector.tsx +++ /dev/null @@ -1,327 +0,0 @@ -import React, {createRef, useRef, useMemo, useState} from 'react' -import {observer} from 'mobx-react-lite' -import { - Animated, - ScrollView, - Share, - StyleSheet, - TouchableWithoutFeedback, - View, -} from 'react-native' -import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {Text} from '../../com/util/text/Text' -import Swipeable from 'react-native-gesture-handler/Swipeable' -import {useStores} from 'state/index' -import {s, colors} from 'lib/styles' -import {toShareUrl} from 'lib/strings/url-helpers' -import {match} from '../../routes' -import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' - -const TAB_HEIGHT = 42 - -export const TabsSelector = observer( - ({ - active, - tabMenuInterp, - onClose, - }: { - active: boolean - tabMenuInterp: Animated.Value - onClose: () => void - }) => { - const store = useStores() - const insets = useSafeAreaInsets() - const [closingTabIndex, setClosingTabIndex] = useState( - undefined, - ) - const closeInterp = useAnimatedValue(0) - const tabsContainerRef = useRef(null) - const tabsRef = useRef(null) - const tabRefs = useMemo( - () => - Array.from({length: store.nav.tabs.length}).map(() => - createRef(), - ), - [store.nav.tabs.length], - ) - - const wrapperAnimStyle = { - transform: [ - { - translateY: tabMenuInterp.interpolate({ - inputRange: [0, 1.0], - outputRange: [320, 0], - }), - }, - ], - } - - // events - // = - - const onPressNewTab = () => { - store.nav.newTab('/') - onClose() - } - const onPressCloneTab = () => { - store.nav.newTab(store.nav.tab.current.url) - onClose() - } - const onPressShareTab = () => { - onClose() - Share.share({url: toShareUrl(store.nav.tab.current.url)}) - } - const onPressChangeTab = (tabIndex: number) => { - store.nav.setActiveTab(tabIndex) - onClose() - } - const onCloseTab = (tabIndex: number) => { - setClosingTabIndex(tabIndex) - closeInterp.setValue(0) - Animated.timing(closeInterp, { - toValue: 1, - duration: 300, - useNativeDriver: false, - }).start(() => { - setClosingTabIndex(undefined) - store.nav.closeTab(tabIndex) - }) - } - const onLayout = () => { - // focus the current tab - const targetTab = tabRefs[store.nav.tabIndex] - if (tabsContainerRef.current && tabsRef.current && targetTab.current) { - targetTab.current.measureLayout?.( - tabsContainerRef.current, - (_left: number, top: number) => { - tabsRef.current?.scrollTo({y: top, animated: false}) - }, - () => {}, - ) - } - } - - // rendering - // = - - const renderSwipeActions = () => { - return - } - - const currentTabIndex = store.nav.tabIndex - const closingTabAnimStyle = { - height: Animated.multiply(TAB_HEIGHT, Animated.subtract(1, closeInterp)), - opacity: Animated.subtract(1, closeInterp), - marginBottom: Animated.multiply(4, Animated.subtract(1, closeInterp)), - } - - if (!active) { - return - } - - return ( - - - - - - - - - - Share - - - - - - - - Clone tab - - - - - - - - New tab - - - - - - - {store.nav.tabs.map((tab, tabIndex) => { - const {icon} = match(tab.current.url) - const isActive = tabIndex === currentTabIndex - const isClosing = closingTabIndex === tabIndex - return ( - onCloseTab(tabIndex)}> - - (tabRefs[tabIndex] = ref)} - style={[ - styles.tab, - styles.existing, - isActive && styles.active, - ]}> - onPressChangeTab(tabIndex)}> - - - - - - {tab.current.title || tab.current.url} - - - - onCloseTab(tabIndex)}> - - - - - - - - ) - })} - - - - - ) - }, -) - -const styles = StyleSheet.create({ - wrapper: { - position: 'absolute', - width: '100%', - height: 320, - borderTopColor: colors.gray2, - borderTopWidth: 1, - backgroundColor: '#fff', - opacity: 1, - }, - section: { - borderBottomColor: colors.gray2, - borderBottomWidth: 1, - }, - sectionGrayBg: { - backgroundColor: colors.gray1, - }, - tabs: { - height: 240, - }, - tabOuter: { - height: TAB_HEIGHT + 4, - overflow: 'hidden', - }, - tab: { - flexDirection: 'row', - height: TAB_HEIGHT, - backgroundColor: colors.gray1, - alignItems: 'center', - borderRadius: 4, - }, - tabInner: { - flexDirection: 'row', - flex: 1, - alignItems: 'center', - paddingLeft: 12, - paddingVertical: 12, - }, - existing: { - borderColor: colors.gray4, - borderWidth: 1, - }, - active: { - backgroundColor: colors.white, - borderColor: colors.black, - borderWidth: 1, - }, - tabIcon: {}, - tabText: { - flex: 1, - paddingHorizontal: 10, - fontSize: 16, - }, - tabTextActive: { - fontWeight: '500', - }, - tabClose: { - paddingVertical: 16, - paddingRight: 16, - }, - tabCloseIcon: { - color: '#655', - }, - btns: { - flexDirection: 'row', - paddingTop: 2, - }, - btn: { - flexDirection: 'row', - flex: 1, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: colors.gray1, - borderRadius: 4, - marginRight: 5, - paddingLeft: 12, - paddingRight: 16, - paddingVertical: 10, - }, - btnIcon: { - marginRight: 8, - }, - btnText: { - fontWeight: '500', - fontSize: 16, - }, -}) diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx index 89a834ee1..6ab19d651 100644 --- a/src/view/shell/mobile/index.tsx +++ b/src/view/shell/mobile/index.tsx @@ -2,21 +2,17 @@ import React, {useState, useEffect} from 'react' import {observer} from 'mobx-react-lite' import { Animated, - Easing, GestureResponderEvent, StatusBar, StyleSheet, TouchableOpacity, TouchableWithoutFeedback, - useColorScheme, useWindowDimensions, View, } from 'react-native' import {ScreenContainer, Screen} from 'react-native-screens' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {IconProp} from '@fortawesome/fontawesome-svg-core' -import {TABS_ENABLED} from 'lib/build-flags' import {useStores} from 'state/index' import { NavigationModel, @@ -31,18 +27,18 @@ import {ModalsContainer} from '../../com/modals/Modal' import {Lightbox} from '../../com/lightbox/Lightbox' import {Text} from '../../com/util/text/Text' import {ErrorBoundary} from '../../com/util/ErrorBoundary' -import {TabsSelector} from './TabsSelector' import {Composer} from './Composer' import {s, colors} from 'lib/styles' import {clamp} from 'lib/numbers' import { - GridIcon, - GridIconSolid, HomeIcon, HomeIconSolid, - MagnifyingGlassIcon, + MagnifyingGlassIcon2, + MagnifyingGlassIcon2Solid, + ComposeIcon2, BellIcon, BellIconSolid, + UserIcon, } from 'lib/icons' import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' import {useTheme} from 'lib/ThemeContext' @@ -52,74 +48,14 @@ import {useAnalytics} from 'lib/analytics' const Btn = ({ icon, notificationCount, - tabCount, onPress, onLongPress, }: { - icon: - | IconProp - | 'menu' - | 'menu-solid' - | 'home' - | 'home-solid' - | 'search' - | 'search-solid' - | 'bell' - | 'bell-solid' + icon: JSX.Element notificationCount?: number - tabCount?: number onPress?: (event: GestureResponderEvent) => void onLongPress?: (event: GestureResponderEvent) => void }) => { - const pal = usePalette('default') - let iconEl - if (icon === 'menu') { - iconEl = - } else if (icon === 'menu-solid') { - iconEl = - } else if (icon === 'home') { - iconEl = - } else if (icon === 'home-solid') { - iconEl = - } else if (icon === 'search') { - iconEl = ( - - ) - } else if (icon === 'search-solid') { - iconEl = ( - - ) - } else if (icon === 'bell') { - iconEl = ( - - ) - } else if (icon === 'bell-solid') { - iconEl = ( - - ) - } else { - iconEl = ( - - ) - } - return ( {notificationCount} ) : undefined} - {tabCount && tabCount > 1 ? ( - - {tabCount} - - ) : undefined} - {iconEl} + {icon} ) } @@ -145,15 +76,10 @@ export const MobileShell: React.FC = observer(() => { const theme = useTheme() const pal = usePalette('default') const store = useStores() - const [isTabsSelectorActive, setTabsSelectorActive] = useState(false) const winDim = useWindowDimensions() const [menuSwipingDirection, setMenuSwipingDirection] = useState(0) const swipeGestureInterp = useAnimatedValue(0) const minimalShellInterp = useAnimatedValue(0) - const tabMenuInterp = useAnimatedValue(0) - const newTabInterp = useAnimatedValue(0) - const [isRunningNewTabAnim, setIsRunningNewTabAnim] = useState(false) - const colorScheme = useColorScheme() const safeAreaInsets = useSafeAreaInsets() const screenRenderDesc = constructScreenRenderDesc(store.nav) const {track} = useAnalytics() @@ -188,6 +114,10 @@ export const MobileShell: React.FC = observer(() => { } } } + const onPressCompose = () => { + track('MobileShell:ComposeButtonPressed') + store.shell.openComposer({}) + } const onPressNotifications = () => { track('MobileShell:NotificationsButtonPressed') if (store.nav.tab.fixedTabPurpose === TabPurpose.Notifs) { @@ -203,8 +133,10 @@ export const MobileShell: React.FC = observer(() => { } } } - const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive) - const doNewTab = (url: string) => () => store.nav.newTab(url) + const onPressProfile = () => { + track('MobileShell:ProfileButtonPressed') + store.nav.navigate(`/profile/${store.me.handle}`) + } // minimal shell animation // = @@ -229,60 +161,6 @@ export const MobileShell: React.FC = observer(() => { transform: [{translateY: Animated.multiply(minimalShellInterp, 100)}], } - // tab selector animation - // = - const toggleTabsMenu = (active: boolean) => { - if (active) { - // will trigger the animation below - setTabsSelectorActive(true) - } else { - Animated.timing(tabMenuInterp, { - toValue: 0, - duration: 100, - useNativeDriver: false, - }).start(() => { - // hide once the animation has finished - setTabsSelectorActive(false) - }) - } - } - useEffect(() => { - if (isTabsSelectorActive) { - // trigger the animation once the tabs selector is rendering - Animated.timing(tabMenuInterp, { - toValue: 1, - duration: 100, - useNativeDriver: false, - }).start() - } - }, [tabMenuInterp, isTabsSelectorActive]) - - // new tab animation - // = - useEffect(() => { - if (screenRenderDesc.hasNewTab && !isRunningNewTabAnim) { - setIsRunningNewTabAnim(true) - } - }, [isRunningNewTabAnim, screenRenderDesc.hasNewTab]) - useEffect(() => { - if (isRunningNewTabAnim) { - const reset = () => { - store.nav.tab.setIsNewTab(false) - setIsRunningNewTabAnim(false) - } - Animated.timing(newTabInterp, { - toValue: 1, - duration: 250, - easing: Easing.out(Easing.exp), - useNativeDriver: false, - }).start(() => { - reset() - }) - } else { - newTabInterp.setValue(0) - } - }, [newTabInterp, store.nav.tab, isRunningNewTabAnim]) - // navigation swipes // = const isMenuActive = store.shell.isMainMenuOpen @@ -495,20 +373,6 @@ export const MobileShell: React.FC = observer(() => { )} - {isTabsSelectorActive ? ( - - ) : undefined} - toggleTabsMenu(false)} - /> { footerMinimalShellTransform, ]}> + ) : ( + + ) + } onPress={onPressHome} - onLongPress={TABS_ENABLED ? doNewTab('/') : undefined} /> + ) : ( + + ) + } onPress={onPressSearch} - onLongPress={TABS_ENABLED ? doNewTab('/') : undefined} /> - {TABS_ENABLED ? ( - - ) : undefined} + + + } + onPress={onPressCompose} + /> + + ) : ( + + ) + } onPress={onPressNotifications} - onLongPress={TABS_ENABLED ? doNewTab('/notifications') : undefined} notificationCount={store.me.notifications.unreadCount} /> + + + + } + onPress={onPressProfile} + /> @@ -650,46 +571,51 @@ const styles = StyleSheet.create({ flexDirection: 'row', borderTopWidth: 1, paddingLeft: 5, - paddingRight: 25, + paddingRight: 10, }, ctrl: { flex: 1, - paddingTop: 12, - paddingBottom: 5, + paddingTop: 13, + paddingBottom: 4, }, notificationCount: { position: 'absolute', - left: '60%', + left: '56%', top: 10, - backgroundColor: colors.red3, + backgroundColor: colors.blue3, paddingHorizontal: 4, paddingBottom: 1, borderRadius: 8, + zIndex: 1, }, notificationCountLabel: { fontSize: 12, fontWeight: 'bold', color: colors.white, }, - tabCount: { - position: 'absolute', - left: 46, - top: 30, - }, - tabCountLabel: { - fontSize: 12, - fontWeight: 'bold', - color: colors.black, - }, ctrlIcon: { marginLeft: 'auto', marginRight: 'auto', }, + ctrlIconSizingWrapper: { + height: 27, + }, inactive: { color: colors.gray3, }, - bumpUpOnePixel: { - position: 'relative', - top: -1, + homeIcon: { + top: 0, + }, + searchIcon: { + top: -2, + }, + bellIcon: { + top: -2.5, + }, + composeIcon: { + top: -4.5, + }, + profileIcon: { + top: -4, }, }) -- cgit 1.4.1