Hide footer on scroll down (minimal shell mode)
parent
470f444eed
commit
1aec0ee156
|
@ -74,6 +74,7 @@ export interface ComposerOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ShellUiModel {
|
export class ShellUiModel {
|
||||||
|
minimalShellMode = false
|
||||||
isMainMenuOpen = false
|
isMainMenuOpen = false
|
||||||
isModalActive = false
|
isModalActive = false
|
||||||
activeModal:
|
activeModal:
|
||||||
|
@ -91,6 +92,10 @@ export class ShellUiModel {
|
||||||
makeAutoObservable(this)
|
makeAutoObservable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMinimalShellMode(v: boolean) {
|
||||||
|
this.minimalShellMode = v
|
||||||
|
}
|
||||||
|
|
||||||
setMainMenuOpen(v: boolean) {
|
setMainMenuOpen(v: boolean) {
|
||||||
this.isMainMenuOpen = v
|
this.isMainMenuOpen = v
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,18 @@ import {FeedItem} from './FeedItem'
|
||||||
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {ErrorMessage} from '../util/ErrorMessage'
|
import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
import {EmptyState} from '../util/EmptyState'
|
import {EmptyState} from '../util/EmptyState'
|
||||||
|
import {OnScrollCb} from '../../lib/useOnMainScroll'
|
||||||
|
|
||||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||||
|
|
||||||
export const Feed = observer(function Feed({
|
export const Feed = observer(function Feed({
|
||||||
view,
|
view,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
|
onScroll,
|
||||||
}: {
|
}: {
|
||||||
view: NotificationsViewModel
|
view: NotificationsViewModel
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
|
onScroll?: OnScrollCb
|
||||||
}) {
|
}) {
|
||||||
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
||||||
// VirtualizedList: You have a large list that is slow to update - make sure your
|
// VirtualizedList: You have a large list that is slow to update - make sure your
|
||||||
|
@ -65,6 +68,7 @@ export const Feed = observer(function Feed({
|
||||||
refreshing={view.isRefreshing}
|
refreshing={view.isRefreshing}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
|
onScroll={onScroll}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {ErrorMessage} from '../util/ErrorMessage'
|
||||||
import {FeedModel} from '../../../state/models/feed-view'
|
import {FeedModel} from '../../../state/models/feed-view'
|
||||||
import {FeedItem} from './FeedItem'
|
import {FeedItem} from './FeedItem'
|
||||||
import {ComposePrompt} from '../composer/Prompt'
|
import {ComposePrompt} from '../composer/Prompt'
|
||||||
|
import {OnScrollCb} from '../../lib/useOnMainScroll'
|
||||||
|
|
||||||
const COMPOSE_PROMPT_ITEM = {_reactKey: '__prompt__'}
|
const COMPOSE_PROMPT_ITEM = {_reactKey: '__prompt__'}
|
||||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||||
|
@ -23,12 +24,14 @@ export const Feed = observer(function Feed({
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
onPressCompose,
|
onPressCompose,
|
||||||
onPressTryAgain,
|
onPressTryAgain,
|
||||||
|
onScroll,
|
||||||
}: {
|
}: {
|
||||||
feed: FeedModel
|
feed: FeedModel
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
scrollElRef?: MutableRefObject<FlatList<any> | null>
|
||||||
onPressCompose: () => void
|
onPressCompose: () => void
|
||||||
onPressTryAgain?: () => void
|
onPressTryAgain?: () => void
|
||||||
|
onScroll?: OnScrollCb
|
||||||
}) {
|
}) {
|
||||||
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
// TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
|
||||||
// VirtualizedList: You have a large list that is slow to update - make sure your
|
// VirtualizedList: You have a large list that is slow to update - make sure your
|
||||||
|
@ -92,6 +95,7 @@ export const Feed = observer(function Feed({
|
||||||
ListFooterComponent={FeedFooter}
|
ListFooterComponent={FeedFooter}
|
||||||
refreshing={feed.isRefreshing}
|
refreshing={feed.isRefreshing}
|
||||||
contentContainerStyle={{paddingBottom: 100}}
|
contentContainerStyle={{paddingBottom: 100}}
|
||||||
|
onScroll={onScroll}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import React, {useEffect, useState} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {FlatList, View} from 'react-native'
|
import {
|
||||||
|
FlatList,
|
||||||
|
NativeSyntheticEvent,
|
||||||
|
NativeScrollEvent,
|
||||||
|
View,
|
||||||
|
} from 'react-native'
|
||||||
import {Selector} from './Selector'
|
import {Selector} from './Selector'
|
||||||
import {HorzSwipe} from './gestures/HorzSwipe'
|
import {HorzSwipe} from './gestures/HorzSwipe'
|
||||||
import {useAnimatedValue} from '../../lib/useAnimatedValue'
|
import {useAnimatedValue} from '../../lib/useAnimatedValue'
|
||||||
|
import {OnScrollCb} from '../../lib/useOnMainScroll'
|
||||||
|
|
||||||
const HEADER_ITEM = {_reactKey: '__header__'}
|
const HEADER_ITEM = {_reactKey: '__header__'}
|
||||||
const SELECTOR_ITEM = {_reactKey: '__selector__'}
|
const SELECTOR_ITEM = {_reactKey: '__selector__'}
|
||||||
|
@ -17,6 +23,7 @@ export function ViewSelector({
|
||||||
renderItem,
|
renderItem,
|
||||||
ListFooterComponent,
|
ListFooterComponent,
|
||||||
onSelectView,
|
onSelectView,
|
||||||
|
onScroll,
|
||||||
onRefresh,
|
onRefresh,
|
||||||
onEndReached,
|
onEndReached,
|
||||||
}: {
|
}: {
|
||||||
|
@ -32,6 +39,7 @@ export function ViewSelector({
|
||||||
| null
|
| null
|
||||||
| undefined
|
| undefined
|
||||||
onSelectView?: (viewIndex: number) => void
|
onSelectView?: (viewIndex: number) => void
|
||||||
|
onScroll?: OnScrollCb
|
||||||
onRefresh?: () => void
|
onRefresh?: () => void
|
||||||
onEndReached?: (info: {distanceFromEnd: number}) => void
|
onEndReached?: (info: {distanceFromEnd: number}) => void
|
||||||
}) {
|
}) {
|
||||||
|
@ -90,6 +98,7 @@ export function ViewSelector({
|
||||||
ListFooterComponent={ListFooterComponent}
|
ListFooterComponent={ListFooterComponent}
|
||||||
stickyHeaderIndices={STICKY_HEADER_INDICES}
|
stickyHeaderIndices={STICKY_HEADER_INDICES}
|
||||||
refreshing={refreshing}
|
refreshing={refreshing}
|
||||||
|
onScroll={onScroll}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import {useState} from 'react'
|
||||||
|
import {NativeSyntheticEvent, NativeScrollEvent} from 'react-native'
|
||||||
|
import {RootStoreModel} from '../../state'
|
||||||
|
|
||||||
|
export type OnScrollCb = (
|
||||||
|
event: NativeSyntheticEvent<NativeScrollEvent>,
|
||||||
|
) => void
|
||||||
|
|
||||||
|
export function useOnMainScroll(store: RootStoreModel) {
|
||||||
|
let [lastY, setLastY] = useState(0)
|
||||||
|
let isMinimal = store.shell.minimalShellMode
|
||||||
|
return function onMainScroll(event: NativeSyntheticEvent<NativeScrollEvent>) {
|
||||||
|
const y = event.nativeEvent.contentOffset.y
|
||||||
|
const dy = y - (lastY || 0)
|
||||||
|
setLastY(y)
|
||||||
|
|
||||||
|
if (!isMinimal && y > 10 && dy > 10) {
|
||||||
|
store.shell.setMinimalShellMode(true)
|
||||||
|
isMinimal = true
|
||||||
|
} else if (isMinimal && (y <= 10 || dy < -10)) {
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
|
isMinimal = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import {useStores} from '../../state'
|
||||||
import {FeedModel} from '../../state/models/feed-view'
|
import {FeedModel} from '../../state/models/feed-view'
|
||||||
import {ScreenParams} from '../routes'
|
import {ScreenParams} from '../routes'
|
||||||
import {s, colors} from '../lib/styles'
|
import {s, colors} from '../lib/styles'
|
||||||
|
import {useOnMainScroll} from '../lib/useOnMainScroll'
|
||||||
|
|
||||||
const HITSLOP = {left: 20, top: 20, right: 20, bottom: 20}
|
const HITSLOP = {left: 20, top: 20, right: 20, bottom: 20}
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ export const Home = observer(function Home({
|
||||||
scrollElRef,
|
scrollElRef,
|
||||||
}: ScreenParams) {
|
}: ScreenParams) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const onMainScroll = useOnMainScroll(store)
|
||||||
const [hasSetup, setHasSetup] = useState<boolean>(false)
|
const [hasSetup, setHasSetup] = useState<boolean>(false)
|
||||||
const {appState} = useAppState({
|
const {appState} = useAppState({
|
||||||
onForeground: () => doPoll(true),
|
onForeground: () => doPoll(true),
|
||||||
|
@ -95,6 +97,7 @@ export const Home = observer(function Home({
|
||||||
style={{flex: 1}}
|
style={{flex: 1}}
|
||||||
onPressCompose={onPressCompose}
|
onPressCompose={onPressCompose}
|
||||||
onPressTryAgain={onPressTryAgain}
|
onPressTryAgain={onPressTryAgain}
|
||||||
|
onScroll={onMainScroll}
|
||||||
/>
|
/>
|
||||||
{defaultFeedView.hasNewLatest ? (
|
{defaultFeedView.hasNewLatest ? (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
|
|
@ -5,9 +5,11 @@ import {Feed} from '../com/notifications/Feed'
|
||||||
import {useStores} from '../../state'
|
import {useStores} from '../../state'
|
||||||
import {NotificationsViewModel} from '../../state/models/notifications-view'
|
import {NotificationsViewModel} from '../../state/models/notifications-view'
|
||||||
import {ScreenParams} from '../routes'
|
import {ScreenParams} from '../routes'
|
||||||
|
import {useOnMainScroll} from '../lib/useOnMainScroll'
|
||||||
|
|
||||||
export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const onMainScroll = useOnMainScroll(store)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
|
@ -33,7 +35,11 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<ViewHeader title="Notifications" />
|
<ViewHeader title="Notifications" />
|
||||||
<Feed view={store.me.notifications} onPressTryAgain={onPressTryAgain} />
|
<Feed
|
||||||
|
view={store.me.notifications}
|
||||||
|
onPressTryAgain={onPressTryAgain}
|
||||||
|
onScroll={onMainScroll}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ export const PostDownvotedBy = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
store.nav.setTitle(navIdx, 'Downvoted by')
|
store.nav.setTitle(navIdx, 'Downvoted by')
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [store, visible])
|
}, [store, visible])
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ export const PostRepostedBy = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
store.nav.setTitle(navIdx, 'Reposted by')
|
store.nav.setTitle(navIdx, 'Reposted by')
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [store, visible])
|
}, [store, visible])
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const PostThread = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setTitle()
|
setTitle()
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
if (!view.hasLoaded && !view.isLoading) {
|
if (!view.hasLoaded && !view.isLoading) {
|
||||||
console.log('Fetching post thread', uri)
|
console.log('Fetching post thread', uri)
|
||||||
view.setup().then(
|
view.setup().then(
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {EmptyState} from '../com/util/EmptyState'
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import * as Toast from '../com/util/Toast'
|
import * as Toast from '../com/util/Toast'
|
||||||
import {s, colors} from '../lib/styles'
|
import {s, colors} from '../lib/styles'
|
||||||
|
import {useOnMainScroll} from '../lib/useOnMainScroll'
|
||||||
|
|
||||||
const LOADING_ITEM = {_reactKey: '__loading__'}
|
const LOADING_ITEM = {_reactKey: '__loading__'}
|
||||||
const END_ITEM = {_reactKey: '__end__'}
|
const END_ITEM = {_reactKey: '__end__'}
|
||||||
|
@ -25,6 +26,7 @@ const EMPTY_ITEM = {_reactKey: '__empty__'}
|
||||||
|
|
||||||
export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const onMainScroll = useOnMainScroll(store)
|
||||||
const [hasSetup, setHasSetup] = useState<boolean>(false)
|
const [hasSetup, setHasSetup] = useState<boolean>(false)
|
||||||
const uiState = useMemo(
|
const uiState = useMemo(
|
||||||
() => new ProfileUiModel(store, {user: params.name}),
|
() => new ProfileUiModel(store, {user: params.name}),
|
||||||
|
@ -252,6 +254,7 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
|
||||||
ListFooterComponent={Footer}
|
ListFooterComponent={Footer}
|
||||||
refreshing={uiState.isRefreshing || false}
|
refreshing={uiState.isRefreshing || false}
|
||||||
onSelectView={onSelectView}
|
onSelectView={onSelectView}
|
||||||
|
onScroll={onMainScroll}
|
||||||
onRefresh={onRefresh}
|
onRefresh={onRefresh}
|
||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const ProfileFollowers = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
store.nav.setTitle(navIdx, `Followers of ${name}`)
|
store.nav.setTitle(navIdx, `Followers of ${name}`)
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [store, visible, name])
|
}, [store, visible, name])
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const ProfileFollows = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
store.nav.setTitle(navIdx, `Followed by ${name}`)
|
store.nav.setTitle(navIdx, `Followed by ${name}`)
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [store, visible, name])
|
}, [store, visible, name])
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const ProfileMembers = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
store.nav.setTitle(navIdx, `Members of ${name}`)
|
store.nav.setTitle(navIdx, `Members of ${name}`)
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
}
|
}
|
||||||
}, [store, visible, name])
|
}, [store, visible, name])
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const Search = ({navIdx, visible, params}: ScreenParams) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
autocompleteView.setup()
|
autocompleteView.setup()
|
||||||
textInput.current?.focus()
|
textInput.current?.focus()
|
||||||
store.nav.setTitle(navIdx, `Search`)
|
store.nav.setTitle(navIdx, `Search`)
|
||||||
|
|
|
@ -18,6 +18,7 @@ export const Settings = observer(function Settings({
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
store.shell.setMinimalShellMode(false)
|
||||||
store.nav.setTitle(navIdx, 'Settings')
|
store.nav.setTitle(navIdx, 'Settings')
|
||||||
}, [visible, store])
|
}, [visible, store])
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
|
const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
|
||||||
const swipeGestureInterp = useAnimatedValue(0)
|
const swipeGestureInterp = useAnimatedValue(0)
|
||||||
|
const minimalShellInterp = useAnimatedValue(0)
|
||||||
const tabMenuInterp = useAnimatedValue(0)
|
const tabMenuInterp = useAnimatedValue(0)
|
||||||
const newTabInterp = useAnimatedValue(0)
|
const newTabInterp = useAnimatedValue(0)
|
||||||
const [isRunningNewTabAnim, setIsRunningNewTabAnim] = useState(false)
|
const [isRunningNewTabAnim, setIsRunningNewTabAnim] = useState(false)
|
||||||
|
@ -156,6 +157,27 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive)
|
const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive)
|
||||||
const doNewTab = (url: string) => () => store.nav.newTab(url)
|
const doNewTab = (url: string) => () => store.nav.newTab(url)
|
||||||
|
|
||||||
|
// minimal shell animation
|
||||||
|
// =
|
||||||
|
useEffect(() => {
|
||||||
|
if (store.shell.minimalShellMode) {
|
||||||
|
Animated.timing(minimalShellInterp, {
|
||||||
|
toValue: 1,
|
||||||
|
duration: 100,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start()
|
||||||
|
} else {
|
||||||
|
Animated.timing(minimalShellInterp, {
|
||||||
|
toValue: 0,
|
||||||
|
duration: 100,
|
||||||
|
useNativeDriver: true,
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
|
}, [minimalShellInterp, store.shell.minimalShellMode])
|
||||||
|
const footerMinimalShellTransform = {
|
||||||
|
transform: [{translateY: Animated.multiply(minimalShellInterp, 100)}],
|
||||||
|
}
|
||||||
|
|
||||||
// tab selector animation
|
// tab selector animation
|
||||||
// =
|
// =
|
||||||
const toggleTabsMenu = (active: boolean) => {
|
const toggleTabsMenu = (active: boolean) => {
|
||||||
|
@ -182,7 +204,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
}).start()
|
}).start()
|
||||||
}
|
}
|
||||||
}, [isTabsSelectorActive])
|
}, [tabMenuInterp, isTabsSelectorActive])
|
||||||
|
|
||||||
// new tab animation
|
// new tab animation
|
||||||
// =
|
// =
|
||||||
|
@ -190,7 +212,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
if (screenRenderDesc.hasNewTab && !isRunningNewTabAnim) {
|
if (screenRenderDesc.hasNewTab && !isRunningNewTabAnim) {
|
||||||
setIsRunningNewTabAnim(true)
|
setIsRunningNewTabAnim(true)
|
||||||
}
|
}
|
||||||
}, [screenRenderDesc.hasNewTab])
|
}, [isRunningNewTabAnim, screenRenderDesc.hasNewTab])
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isRunningNewTabAnim) {
|
if (isRunningNewTabAnim) {
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
|
@ -208,7 +230,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
} else {
|
} else {
|
||||||
newTabInterp.setValue(0)
|
newTabInterp.setValue(0)
|
||||||
}
|
}
|
||||||
}, [isRunningNewTabAnim])
|
}, [newTabInterp, store.nav.tab, isRunningNewTabAnim])
|
||||||
|
|
||||||
// navigation swipes
|
// navigation swipes
|
||||||
// =
|
// =
|
||||||
|
@ -396,10 +418,11 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
tabMenuInterp={tabMenuInterp}
|
tabMenuInterp={tabMenuInterp}
|
||||||
onClose={() => toggleTabsMenu(false)}
|
onClose={() => toggleTabsMenu(false)}
|
||||||
/>
|
/>
|
||||||
<View
|
<Animated.View
|
||||||
style={[
|
style={[
|
||||||
styles.bottomBar,
|
styles.bottomBar,
|
||||||
{paddingBottom: clamp(safeAreaInsets.bottom, 15, 40)},
|
{paddingBottom: clamp(safeAreaInsets.bottom, 15, 40)},
|
||||||
|
footerMinimalShellTransform,
|
||||||
]}>
|
]}>
|
||||||
<Btn
|
<Btn
|
||||||
icon={isAtHome ? 'home-solid' : 'home'}
|
icon={isAtHome ? 'home-solid' : 'home'}
|
||||||
|
@ -419,7 +442,7 @@ export const MobileShell: React.FC = observer(() => {
|
||||||
onLongPress={TABS_ENABLED ? doNewTab('/notifications') : undefined}
|
onLongPress={TABS_ENABLED ? doNewTab('/notifications') : undefined}
|
||||||
notificationCount={store.me.notificationCount}
|
notificationCount={store.me.notificationCount}
|
||||||
/>
|
/>
|
||||||
</View>
|
</Animated.View>
|
||||||
<Modal />
|
<Modal />
|
||||||
<Lightbox />
|
<Lightbox />
|
||||||
<Composer
|
<Composer
|
||||||
|
@ -565,6 +588,10 @@ const styles = StyleSheet.create({
|
||||||
paddingHorizontal: 6,
|
paddingHorizontal: 6,
|
||||||
},
|
},
|
||||||
bottomBar: {
|
bottomBar: {
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
backgroundColor: colors.white,
|
backgroundColor: colors.white,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
|
|
Loading…
Reference in New Issue