import React, {createRef, useRef, useMemo, useState} from 'react' import {observer} from 'mobx-react-lite' import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View, } from 'react-native' import Animated, { useSharedValue, useAnimatedStyle, withTiming, runOnJS, } from 'react-native-reanimated' import {IconProp} from '@fortawesome/fontawesome-svg-core' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import Swipeable from 'react-native-gesture-handler/Swipeable' import LinearGradient from 'react-native-linear-gradient' import {useStores} from '../../../state' import {s, colors, gradients} from '../../lib/styles' import {DEF_AVATAR} from '../../lib/assets' import {match} from '../../routes' import {LinkActionsModel} from '../../../state/models/shell' const TAB_HEIGHT = 42 export const snapPoints = [500] export const Component = observer(() => { const store = useStores() const [closingTabIndex, setClosingTabIndex] = useState( undefined, ) const closeInterp = useSharedValue(0) const tabsRef = useRef(null) const tabRefs = useMemo( () => Array.from({length: store.nav.tabs.length}).map(() => createRef(), ), [store.nav.tabs.length], ) // events // = const onPressNewTab = () => { store.nav.newTab('/') onClose() } const onPressCloneTab = () => { store.nav.newTab(store.nav.tab.current.url) onClose() } const onPressShareTab = () => { onClose() store.shell.openModal( new LinkActionsModel( store.nav.tab.current.url, store.nav.tab.current.title || 'This Page', {newTab: false}, ), ) } const onPressChangeTab = (tabIndex: number) => { store.nav.setActiveTab(tabIndex) onClose() } const doCloseTab = (index: number) => store.nav.closeTab(index) const onCloseTab = (tabIndex: number) => { setClosingTabIndex(tabIndex) closeInterp.value = 0 closeInterp.value = withTiming(1, {duration: 300}, () => { runOnJS(setClosingTabIndex)(undefined) runOnJS(doCloseTab)(tabIndex) }) } const onNavigate = (url: string) => { store.nav.navigate(url) onClose() } const onClose = () => { store.shell.closeModal() } const onLayout = () => { // focus the current tab const targetTab = tabRefs[store.nav.tabIndex] if (tabsRef.current && targetTab.current) { targetTab.current.measureLayout?.( tabsRef.current, (_left: number, top: number) => { tabsRef.current?.scrollTo({y: top, animated: false}) }, () => {}, ) } } // rendering // = const FatMenuItem = ({ icon, label, url, gradient, }: { icon: IconProp label: string url: string gradient: keyof typeof gradients }) => ( onNavigate(url)}> {label} ) const renderSwipeActions = () => { return } const currentTabIndex = store.nav.tabIndex const closingTabAnimStyle = useAnimatedStyle(() => ({ height: TAB_HEIGHT * (1 - closeInterp.value), opacity: 1 - closeInterp.value, marginBottom: 4 * (1 - closeInterp.value), })) return ( onNavigate(`/profile/${store.me.name || ''}`)}> {store.me.displayName || store.me.name || 'My profile'} 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)}> onPressChangeTab(tabIndex)}> {tab.current.title || tab.current.url} onCloseTab(tabIndex)}> ) })} ) }) const styles = StyleSheet.create({ section: { borderBottomColor: colors.gray2, borderBottomWidth: 1, }, sectionGrayBg: { backgroundColor: colors.gray1, }, fatMenuItems: { flexDirection: 'row', marginTop: 10, marginBottom: 10, }, fatMenuItem: { width: 80, alignItems: 'center', marginRight: 6, }, fatMenuItemMargin: { marginRight: 14, }, fatMenuItemIconWrapper: { borderRadius: 6, width: 60, height: 60, justifyContent: 'center', alignItems: 'center', marginBottom: 5, shadowColor: '#000', shadowOpacity: 0.2, shadowOffset: {width: 0, height: 2}, shadowRadius: 2, }, fatMenuItemIcon: { color: colors.white, }, fatMenuImage: { borderRadius: 30, width: 60, height: 60, marginBottom: 5, }, fatMenuItemLabel: { fontSize: 13, }, 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, }, })