diff --git a/src/state/models/feeds/algo/saved.ts b/src/state/models/feeds/algo/saved.ts index bc36aaed..5d2f854d 100644 --- a/src/state/models/feeds/algo/saved.ts +++ b/src/state/models/feeds/algo/saved.ts @@ -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 // = diff --git a/src/view/com/algos/AlgoItem.tsx b/src/view/com/algos/AlgoItem.tsx index 51de89bd..04117e58 100644 --- a/src/view/com/algos/AlgoItem.tsx +++ b/src/view/com/algos/AlgoItem.tsx @@ -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}) => { + const store = useStores() const pal = usePalette('default') const navigation = useNavigation() @@ -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'} diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx index c3c44255..3d1ed2c1 100644 --- a/src/view/com/pager/FeedsTabBarMobile.tsx +++ b/src/view/com/pager/FeedsTabBarMobile.tsx @@ -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 ( diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index 5d2e18e3..3a7a5583 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -35,59 +35,59 @@ export function TabBar({ onPressSelected, }: TabBarProps) { const pal = usePalette('default') - const [itemLayouts, setItemLayouts] = useState( - items.map(() => ({x: 0, width: 0})), - ) + // const [itemLayouts, setItemLayouts] = useState( + // items.map(() => ({x: 0, width: 0})), + // ) const itemRefs = useMemo( () => Array.from({length: items.length}).map(() => createRef()), [items.length], ) - const panX = Animated.add(position, offset) + // const panX = Animated.add(position, offset) const containerRef = useRef(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(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(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({ - + {items.map((item, i) => { const selected = i === selectedPage return ( - onPressItem(i)}> - - {item} - - + + onPressItem(i)}> + + {item} + + + ) })} @@ -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, + }, })