remove tab bar underline animation

zio/stable
Ansh Nanda 2023-05-15 12:31:27 -07:00
parent d7e39bde12
commit 6249bb16ca
4 changed files with 111 additions and 68 deletions

View File

@ -89,6 +89,36 @@ export class SavedFeedsModel {
}
})
removeFeed(uri: string) {
this.feeds = this.feeds.filter(f => f.data.uri !== uri)
}
addFeed(algoItem: AlgoItemModel) {
this.feeds.push(new AlgoItemModel(this.rootStore, algoItem.data))
}
async save(algoItem: AlgoItemModel) {
try {
await this.rootStore.agent.app.bsky.feed.saveFeed({
feed: algoItem.getUri,
})
this.addFeed(algoItem)
} catch (e: any) {
this.rootStore.log.error('Failed to save feed', e)
}
}
async unsave(uri: string) {
try {
await this.rootStore.agent.app.bsky.feed.unsaveFeed({
feed: uri,
})
this.removeFeed(uri)
} catch (e: any) {
this.rootStore.log.error('Failed to unsanve feed', e)
}
}
// state transitions
// =

View File

@ -15,9 +15,11 @@ import {observer} from 'mobx-react-lite'
import {AlgoItemModel} from 'state/models/feeds/algo/algo-item'
import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types'
import {useStores} from 'state/index'
const AlgoItem = observer(
({item, style}: {item: AlgoItemModel; style?: StyleProp<ViewStyle>}) => {
const store = useStores()
const pal = usePalette('default')
const navigation = useNavigation<NavigationProp>()
@ -64,8 +66,10 @@ const AlgoItem = observer(
onPress={() => {
if (item.data.viewer?.saved) {
item.unsave()
store.me.savedFeeds.removeFeed(item.data.uri)
} else {
item.save()
store.me.savedFeeds.addFeed(item)
}
}}
label={item.data.viewer?.saved ? 'Unsave' : 'Save'}

View File

@ -1,4 +1,4 @@
import React from 'react'
import React, {useMemo} from 'react'
import {Animated, StyleSheet, TouchableOpacity} from 'react-native'
import {observer} from 'mobx-react-lite'
import {TabBar} from 'view/com/pager/TabBar'
@ -32,6 +32,11 @@ export const FeedsTabBar = observer(
store.shell.openDrawer()
}, [store])
const items = useMemo(
() => ['Following', "What's hot", ...store.me.savedFeeds.listOfFeedNames],
[store.me.savedFeeds.listOfFeedNames],
)
return (
<Animated.View style={[pal.view, pal.border, styles.tabBar, transform]}>
<TouchableOpacity
@ -45,11 +50,7 @@ export const FeedsTabBar = observer(
</TouchableOpacity>
<TabBar
{...props}
items={[
'Following',
"What's hot",
...store.me.savedFeeds.listOfFeedNames,
]}
items={items}
indicatorPosition="bottom"
indicatorColor={pal.colors.link}
/>

View File

@ -35,59 +35,59 @@ export function TabBar({
onPressSelected,
}: TabBarProps) {
const pal = usePalette('default')
const [itemLayouts, setItemLayouts] = useState<Layout[]>(
items.map(() => ({x: 0, width: 0})),
)
// const [itemLayouts, setItemLayouts] = useState<Layout[]>(
// items.map(() => ({x: 0, width: 0})),
// )
const itemRefs = useMemo(
() => Array.from({length: items.length}).map(() => createRef<View>()),
[items.length],
)
const panX = Animated.add(position, offset)
// const panX = Animated.add(position, offset)
const containerRef = useRef<View>(null)
const indicatorStyle = {
backgroundColor: indicatorColor || pal.colors.link,
bottom:
indicatorPosition === 'bottom' ? (isDesktopWeb ? 0 : -1) : undefined,
top: indicatorPosition === 'top' ? (isDesktopWeb ? 0 : -1) : undefined,
transform: [
{
translateX: panX.interpolate({
inputRange: items.map((_item, i) => i),
outputRange: itemLayouts.map(l => l.x + l.width / 2),
}),
},
{
scaleX: panX.interpolate({
inputRange: items.map((_item, i) => i),
outputRange: itemLayouts.map(l => l.width),
}),
},
],
}
// const indicatorStyle = {
// backgroundColor: indicatorColor || pal.colors.link,
// bottom:
// indicatorPosition === 'bottom' ? (isDesktopWeb ? 0 : -1) : undefined,
// top: indicatorPosition === 'top' ? (isDesktopWeb ? 0 : -1) : undefined,
// transform: [
// {
// translateX: panX.interpolate({
// inputRange: items.map((_item, i) => i),
// outputRange: itemLayouts.map(l => l.x + l.width / 2),
// }),
// },
// {
// scaleX: panX.interpolate({
// inputRange: items.map((_item, i) => i),
// outputRange: itemLayouts.map(l => l.width),
// }),
// },
// ],
// }
const onLayout = () => {
const promises = []
for (let i = 0; i < items.length; i++) {
promises.push(
new Promise<Layout>(resolve => {
if (!containerRef.current || !itemRefs[i].current) {
return resolve({x: 0, width: 0})
}
// const onLayout = () => {
// const promises = []
// for (let i = 0; i < items.length; i++) {
// promises.push(
// new Promise<Layout>(resolve => {
// if (!containerRef.current || !itemRefs[i].current) {
// return resolve({x: 0, width: 0})
// }
itemRefs[i].current?.measureLayout(
containerRef.current,
(x: number, _y: number, width: number) => {
resolve({x, width})
},
)
}),
)
}
Promise.all(promises).then((layouts: Layout[]) => {
setItemLayouts(layouts)
})
}
// itemRefs[i].current?.measureLayout(
// containerRef.current,
// (x: number, _y: number, width: number) => {
// resolve({x, width})
// },
// )
// }),
// )
// }
// Promise.all(promises).then((layouts: Layout[]) => {
// setItemLayouts(layouts)
// })
// }
const onPressItem = (index: number) => {
onSelect?.(index)
@ -100,28 +100,31 @@ export function TabBar({
<View
testID={testID}
style={[pal.view, styles.outer]}
onLayout={onLayout}
// onLayout={onLayout}
ref={containerRef}>
<Animated.View style={[styles.indicator, indicatorStyle]} />
<Animated.View style={[styles.indicator]} />
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
{items.map((item, i) => {
const selected = i === selectedPage
return (
<PressableWithHover
ref={itemRefs[i]}
key={item}
style={
indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom
}
hoverStyle={pal.viewLight}
onPress={() => onPressItem(i)}>
<Text
type="xl-bold"
testID={testID ? `${testID}-${item}` : undefined}
style={selected ? pal.text : pal.textLight}>
{item}
</Text>
</PressableWithHover>
<Animated.View key={item} style={selected ? styles.active : []}>
<PressableWithHover
ref={itemRefs[i]}
style={[
indicatorPosition === 'top'
? styles.itemTop
: styles.itemBottom,
]}
hoverStyle={pal.viewLight}
onPress={() => onPressItem(i)}>
<Text
type="xl-bold"
testID={testID ? `${testID}-${item}` : undefined}
style={selected ? pal.text : pal.textLight}>
{item}
</Text>
</PressableWithHover>
</Animated.View>
)
})}
</ScrollView>
@ -152,6 +155,7 @@ const styles = isDesktopWeb
height: 3,
zIndex: 1,
},
active: {},
})
: StyleSheet.create({
outer: {
@ -174,4 +178,8 @@ const styles = isDesktopWeb
width: 1,
height: 3,
},
active: {
borderBottomColor: 'blue',
borderBottomWidth: 3,
},
})