about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/state/models/feeds/algo/algo-item.ts15
-rw-r--r--src/state/models/feeds/algo/saved.ts2
-rw-r--r--src/state/models/me.ts5
-rw-r--r--src/view/screens/CustomAlgorithms.tsx84
-rw-r--r--src/view/screens/MutedAccounts.tsx2
5 files changed, 91 insertions, 17 deletions
diff --git a/src/state/models/feeds/algo/algo-item.ts b/src/state/models/feeds/algo/algo-item.ts
index 555d1d56d..88e9c0662 100644
--- a/src/state/models/feeds/algo/algo-item.ts
+++ b/src/state/models/feeds/algo/algo-item.ts
@@ -1,8 +1,7 @@
 import {AppBskyFeedDefs} from '@atproto/api'
-import {makeAutoObservable, makeObservable} from 'mobx'
+import {makeAutoObservable} from 'mobx'
 import {RootStoreModel} from 'state/models/root-store'
 
-// algoitemmodel implemented in mobx
 export class AlgoItemModel {
   // data
   data: AppBskyFeedDefs.GeneratorView
@@ -21,6 +20,8 @@ export class AlgoItemModel {
     )
   }
 
+  // local actions
+  // =
   set toggleSaved(value: boolean) {
     console.log('toggleSaved', this.data.viewer)
     if (this.data.viewer) {
@@ -28,12 +29,12 @@ export class AlgoItemModel {
     }
   }
 
+  // public apis
+  // =
   async save() {
     try {
-      // runInAction(() => {
       this.toggleSaved = true
-      // })
-      const res = await this.rootStore.agent.app.bsky.feed.saveFeed({
+      await this.rootStore.agent.app.bsky.feed.saveFeed({
         feed: this.data.uri,
       })
     } catch (e: any) {
@@ -43,10 +44,8 @@ export class AlgoItemModel {
 
   async unsave() {
     try {
-      // runInAction(() => {
       this.toggleSaved = false
-      // })
-      const res = await this.rootStore.agent.app.bsky.feed.unsaveFeed({
+      await this.rootStore.agent.app.bsky.feed.unsaveFeed({
         feed: this.data.uri,
       })
     } catch (e: any) {
diff --git a/src/state/models/feeds/algo/saved.ts b/src/state/models/feeds/algo/saved.ts
index fabb75ae0..86b97cf67 100644
--- a/src/state/models/feeds/algo/saved.ts
+++ b/src/state/models/feeds/algo/saved.ts
@@ -110,7 +110,7 @@ export class SavedFeedsModel {
     this.loadMoreCursor = res.data.cursor
     this.hasMore = !!this.loadMoreCursor
     for (const f of res.data.feeds) {
-      this.feeds.push(new AlgoItemModel(f))
+      this.feeds.push(new AlgoItemModel(this.rootStore, f))
     }
   }
 }
diff --git a/src/state/models/me.ts b/src/state/models/me.ts
index ba2dc6f32..314e76b9c 100644
--- a/src/state/models/me.ts
+++ b/src/state/models/me.ts
@@ -8,6 +8,7 @@ import {PostsFeedModel} from './feeds/posts'
 import {NotificationsFeedModel} from './feeds/notifications'
 import {MyFollowsCache} from './cache/my-follows'
 import {isObj, hasProp} from 'lib/type-guards'
+import {SavedFeedsModel} from './feeds/algo/saved'
 
 const PROFILE_UPDATE_INTERVAL = 10 * 60 * 1e3 // 10min
 const NOTIFS_UPDATE_INTERVAL = 30 * 1e3 // 30sec
@@ -21,6 +22,7 @@ export class MeModel {
   followsCount: number | undefined
   followersCount: number | undefined
   mainFeed: PostsFeedModel
+  savedFeeds: SavedFeedsModel
   notifications: NotificationsFeedModel
   follows: MyFollowsCache
   invites: ComAtprotoServerDefs.InviteCode[] = []
@@ -43,12 +45,14 @@ export class MeModel {
     })
     this.notifications = new NotificationsFeedModel(this.rootStore)
     this.follows = new MyFollowsCache(this.rootStore)
+    this.savedFeeds = new SavedFeedsModel(this.rootStore)
   }
 
   clear() {
     this.mainFeed.clear()
     this.notifications.clear()
     this.follows.clear()
+    this.savedFeeds.clear()
     this.did = ''
     this.handle = ''
     this.displayName = ''
@@ -110,6 +114,7 @@ export class MeModel {
       /* dont await */ this.notifications.setup().catch(e => {
         this.rootStore.log.error('Failed to setup notifications model', e)
       })
+      /* dont await */ this.savedFeeds.refresh()
       this.rootStore.emitSessionLoaded()
       await this.fetchInviteCodes()
       await this.fetchAppPasswords()
diff --git a/src/view/screens/CustomAlgorithms.tsx b/src/view/screens/CustomAlgorithms.tsx
index 3e2fa7e73..05951f98e 100644
--- a/src/view/screens/CustomAlgorithms.tsx
+++ b/src/view/screens/CustomAlgorithms.tsx
@@ -1,27 +1,97 @@
+import React, {useCallback, useMemo} from 'react'
+import {
+  RefreshControl,
+  StyleSheet,
+  View,
+  FlatList,
+  ActivityIndicator,
+} from 'react-native'
+import {useFocusEffect} from '@react-navigation/native'
 import {NativeStackScreenProps} from '@react-navigation/native-stack'
+import {useAnalytics} from 'lib/analytics'
 import {usePalette} from 'lib/hooks/usePalette'
 import {CommonNavigatorParams} from 'lib/routes/types'
 import {observer} from 'mobx-react-lite'
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
+import {useStores} from 'state/index'
+import {SavedFeedsModel} from 'state/models/feeds/algo/saved'
+import AlgoItem from 'view/com/algos/AlgoItem'
 import {withAuthRequired} from 'view/com/auth/withAuthRequired'
 import {ViewHeader} from 'view/com/util/ViewHeader'
+import {CenteredView} from 'view/com/util/Views'
 import {Text} from 'view/com/util/text/Text'
+import {isDesktopWeb} from 'platform/detection'
+import {s} from 'lib/styles'
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'CustomAlgorithms'>
 
 const CustomAlgorithms = withAuthRequired(
-  observer((props: Props) => {
+  observer(({}: Props) => {
     const pal = usePalette('default')
+    const rootStore = useStores()
+    const {screen} = useAnalytics()
+
+    const savedFeeds = useMemo(
+      () => new SavedFeedsModel(rootStore),
+      [rootStore],
+    )
+
+    useFocusEffect(
+      useCallback(() => {
+        screen('SavedFeeds')
+        rootStore.shell.setMinimalShellMode(false)
+        savedFeeds.refresh()
+      }, [screen, rootStore, savedFeeds]),
+    )
+
     return (
-      <View>
+      <CenteredView style={{flex: 1}}>
         <ViewHeader title="Custom Algorithms" showOnDesktop />
-        <Text>CustomAlgorithms</Text>
-      </View>
+        {!savedFeeds.hasContent || savedFeeds.isEmpty ? (
+          <View style={[pal.border, !isDesktopWeb && s.flex1]}>
+            <View style={[pal.viewLight]}>
+              <Text type="lg" style={[pal.text]}>
+                You don't have any saved feeds. To save a feed, click the save
+                button when a custom feed or algorithm shows up.
+              </Text>
+            </View>
+          </View>
+        ) : (
+          <FlatList
+            style={[!isDesktopWeb && s.flex1]}
+            data={savedFeeds.feeds}
+            keyExtractor={item => item.data.uri}
+            refreshControl={
+              <RefreshControl
+                refreshing={savedFeeds.isRefreshing}
+                onRefresh={() => savedFeeds.refresh()}
+                tintColor={pal.colors.text}
+                titleColor={pal.colors.text}
+              />
+            }
+            onEndReached={() => savedFeeds.loadMore()}
+            renderItem={({item}) => (
+              <AlgoItem key={item.data.uri} item={item} />
+            )}
+            initialNumToRender={15}
+            ListFooterComponent={() => (
+              <View style={styles.footer}>
+                {savedFeeds.isLoading && <ActivityIndicator />}
+              </View>
+            )}
+            extraData={savedFeeds.isLoading}
+            // @ts-ignore our .web version only -prf
+            desktopFixedHeight
+          />
+        )}
+      </CenteredView>
     )
   }),
 )
 
 export default CustomAlgorithms
 
-const styles = StyleSheet.create({})
+const styles = StyleSheet.create({
+  footer: {
+    paddingVertical: 20,
+  },
+})
diff --git a/src/view/screens/MutedAccounts.tsx b/src/view/screens/MutedAccounts.tsx
index f7120051f..8f3d1f8a5 100644
--- a/src/view/screens/MutedAccounts.tsx
+++ b/src/view/screens/MutedAccounts.tsx
@@ -97,7 +97,7 @@ export const MutedAccounts = withAuthRequired(
           <FlatList
             style={[!isDesktopWeb && styles.flex1]}
             data={mutedAccounts.mutes}
-            keyExtractor={(item: ActorDefs.ProfileView) => item.did}
+            keyExtractor={item => item.did}
             refreshControl={
               <RefreshControl
                 refreshing={mutedAccounts.isRefreshing}