about summary refs log tree commit diff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/api/feed/custom.ts27
-rw-r--r--src/lib/api/feed/home.ts89
-rw-r--r--src/lib/api/feed/merge.ts17
-rw-r--r--src/lib/themes.ts110
4 files changed, 174 insertions, 69 deletions
diff --git a/src/lib/api/feed/custom.ts b/src/lib/api/feed/custom.ts
index 94cbff130..41c5367e5 100644
--- a/src/lib/api/feed/custom.ts
+++ b/src/lib/api/feed/custom.ts
@@ -4,15 +4,20 @@ import {
 } from '@atproto/api'
 import {FeedAPI, FeedAPIResponse} from './types'
 import {getAgent} from '#/state/session'
+import {getContentLanguages} from '#/state/preferences/languages'
 
 export class CustomFeedAPI implements FeedAPI {
   constructor(public params: GetCustomFeed.QueryParams) {}
 
   async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
-    const res = await getAgent().app.bsky.feed.getFeed({
-      ...this.params,
-      limit: 1,
-    })
+    const contentLangs = getContentLanguages().join(',')
+    const res = await getAgent().app.bsky.feed.getFeed(
+      {
+        ...this.params,
+        limit: 1,
+      },
+      {headers: {'Accept-Language': contentLangs}},
+    )
     return res.data.feed[0]
   }
 
@@ -23,11 +28,15 @@ export class CustomFeedAPI implements FeedAPI {
     cursor: string | undefined
     limit: number
   }): Promise<FeedAPIResponse> {
-    const res = await getAgent().app.bsky.feed.getFeed({
-      ...this.params,
-      cursor,
-      limit,
-    })
+    const contentLangs = getContentLanguages().join(',')
+    const res = await getAgent().app.bsky.feed.getFeed(
+      {
+        ...this.params,
+        cursor,
+        limit,
+      },
+      {headers: {'Accept-Language': contentLangs}},
+    )
     if (res.success) {
       // NOTE
       // some custom feeds fail to enforce the pagination limit
diff --git a/src/lib/api/feed/home.ts b/src/lib/api/feed/home.ts
new file mode 100644
index 000000000..436a66d07
--- /dev/null
+++ b/src/lib/api/feed/home.ts
@@ -0,0 +1,89 @@
+import {AppBskyFeedDefs} from '@atproto/api'
+import {FeedAPI, FeedAPIResponse} from './types'
+import {FollowingFeedAPI} from './following'
+import {CustomFeedAPI} from './custom'
+import {PROD_DEFAULT_FEED} from '#/lib/constants'
+
+// HACK
+// the feed API does not include any facilities for passing down
+// non-post elements. adding that is a bit of a heavy lift, and we
+// have just one temporary usecase for it: flagging when the home feed
+// falls back to discover.
+// we use this fallback marker post to drive this instead. see Feed.tsx
+// for the usage.
+// -prf
+export const FALLBACK_MARKER_POST: AppBskyFeedDefs.FeedViewPost = {
+  post: {
+    uri: 'fallback-marker-post',
+    cid: 'fake',
+    record: {},
+    author: {
+      did: 'did:fake',
+      handle: 'fake.com',
+    },
+    indexedAt: new Date().toISOString(),
+  },
+}
+
+export class HomeFeedAPI implements FeedAPI {
+  following: FollowingFeedAPI
+  discover: CustomFeedAPI
+  usingDiscover = false
+  itemCursor = 0
+
+  constructor() {
+    this.following = new FollowingFeedAPI()
+    this.discover = new CustomFeedAPI({feed: PROD_DEFAULT_FEED('whats-hot')})
+  }
+
+  reset() {
+    this.following = new FollowingFeedAPI()
+    this.discover = new CustomFeedAPI({feed: PROD_DEFAULT_FEED('whats-hot')})
+    this.usingDiscover = false
+    this.itemCursor = 0
+  }
+
+  async peekLatest(): Promise<AppBskyFeedDefs.FeedViewPost> {
+    if (this.usingDiscover) {
+      return this.discover.peekLatest()
+    }
+    return this.following.peekLatest()
+  }
+
+  async fetch({
+    cursor,
+    limit,
+  }: {
+    cursor: string | undefined
+    limit: number
+  }): Promise<FeedAPIResponse> {
+    if (!cursor) {
+      this.reset()
+    }
+
+    let returnCursor
+    let posts: AppBskyFeedDefs.FeedViewPost[] = []
+
+    if (!this.usingDiscover) {
+      const res = await this.following.fetch({cursor, limit})
+      returnCursor = res.cursor
+      posts = posts.concat(res.feed)
+      if (!returnCursor) {
+        cursor = ''
+        posts.push(FALLBACK_MARKER_POST)
+        this.usingDiscover = true
+      }
+    }
+
+    if (this.usingDiscover) {
+      const res = await this.discover.fetch({cursor, limit})
+      returnCursor = res.cursor
+      posts = posts.concat(res.feed)
+    }
+
+    return {
+      cursor: returnCursor,
+      feed: posts,
+    }
+  }
+}
diff --git a/src/lib/api/feed/merge.ts b/src/lib/api/feed/merge.ts
index 2314e2b95..28bf143cb 100644
--- a/src/lib/api/feed/merge.ts
+++ b/src/lib/api/feed/merge.ts
@@ -8,6 +8,7 @@ import {FeedAPI, FeedAPIResponse, ReasonFeedSource} from './types'
 import {FeedParams} from '#/state/queries/post-feed'
 import {FeedTunerFn} from '../feed-manip'
 import {getAgent} from '#/state/session'
+import {getContentLanguages} from '#/state/preferences/languages'
 
 const REQUEST_WAIT_MS = 500 // 500ms
 const POST_AGE_CUTOFF = 60e3 * 60 * 24 // 24hours
@@ -25,7 +26,7 @@ export class MergeFeedAPI implements FeedAPI {
 
   reset() {
     this.following = new MergeFeedSource_Following(this.feedTuners)
-    this.customFeeds = [] // just empty the array, they will be captured in _fetchNext()
+    this.customFeeds = []
     this.feedCursor = 0
     this.itemCursor = 0
     this.sampleCursor = 0
@@ -231,11 +232,15 @@ class MergeFeedSource_Custom extends MergeFeedSource {
     limit: number,
   ): Promise<AppBskyFeedGetTimeline.Response> {
     try {
-      const res = await getAgent().app.bsky.feed.getFeed({
-        cursor,
-        limit,
-        feed: this.feedUri,
-      })
+      const contentLangs = getContentLanguages().join(',')
+      const res = await getAgent().app.bsky.feed.getFeed(
+        {
+          cursor,
+          limit,
+          feed: this.feedUri,
+        },
+        {headers: {'Accept-Language': contentLangs}},
+      )
       // NOTE
       // some custom feeds fail to enforce the pagination limit
       // so we manually truncate here
diff --git a/src/lib/themes.ts b/src/lib/themes.ts
index ad7574db6..2d4515c77 100644
--- a/src/lib/themes.ts
+++ b/src/lib/themes.ts
@@ -2,30 +2,32 @@ import {Platform} from 'react-native'
 import type {Theme} from './ThemeContext'
 import {colors} from './styles'
 
+import {darkPalette, lightPalette} from '#/alf/themes'
+
 export const defaultTheme: Theme = {
   colorScheme: 'light',
   palette: {
     default: {
-      background: colors.white,
-      backgroundLight: colors.gray1,
-      text: colors.black,
-      textLight: colors.gray5,
-      textInverted: colors.white,
-      link: colors.blue3,
-      border: '#f0e9e9',
-      borderDark: '#e0d9d9',
-      icon: colors.gray4,
+      background: lightPalette.white,
+      backgroundLight: lightPalette.contrast_50,
+      text: lightPalette.black,
+      textLight: lightPalette.contrast_700,
+      textInverted: lightPalette.white,
+      link: lightPalette.primary_500,
+      border: lightPalette.contrast_100,
+      borderDark: lightPalette.contrast_200,
+      icon: lightPalette.contrast_500,
 
       // non-standard
-      textVeryLight: colors.gray4,
-      replyLine: colors.gray2,
-      replyLineDot: colors.gray3,
-      unreadNotifBg: '#ebf6ff',
-      unreadNotifBorder: colors.blue1,
-      postCtrl: '#71768A',
-      brandText: '#0066FF',
-      emptyStateIcon: '#B6B6C9',
-      borderLinkHover: '#cac1c1',
+      textVeryLight: lightPalette.contrast_400,
+      replyLine: lightPalette.contrast_100,
+      replyLineDot: lightPalette.contrast_200,
+      unreadNotifBg: lightPalette.primary_25,
+      unreadNotifBorder: lightPalette.primary_100,
+      postCtrl: lightPalette.contrast_500,
+      brandText: lightPalette.primary_500,
+      emptyStateIcon: lightPalette.contrast_300,
+      borderLinkHover: lightPalette.contrast_300,
     },
     primary: {
       background: colors.blue3,
@@ -50,15 +52,15 @@ export const defaultTheme: Theme = {
       icon: colors.green4,
     },
     inverted: {
-      background: colors.black,
-      backgroundLight: colors.gray6,
-      text: colors.white,
-      textLight: colors.gray3,
-      textInverted: colors.black,
-      link: colors.blue2,
-      border: colors.gray3,
-      borderDark: colors.gray2,
-      icon: colors.gray5,
+      background: darkPalette.black,
+      backgroundLight: darkPalette.contrast_50,
+      text: darkPalette.white,
+      textLight: darkPalette.contrast_700,
+      textInverted: darkPalette.black,
+      link: darkPalette.primary_500,
+      border: darkPalette.contrast_100,
+      borderDark: darkPalette.contrast_200,
+      icon: darkPalette.contrast_500,
     },
     error: {
       background: colors.red3,
@@ -292,26 +294,26 @@ export const darkTheme: Theme = {
   palette: {
     ...defaultTheme.palette,
     default: {
-      background: colors.black,
-      backgroundLight: colors.gray7,
-      text: colors.white,
-      textLight: colors.gray3,
-      textInverted: colors.black,
-      link: colors.blue3,
-      border: colors.gray7,
-      borderDark: colors.gray6,
-      icon: colors.gray4,
+      background: darkPalette.black,
+      backgroundLight: darkPalette.contrast_50,
+      text: darkPalette.white,
+      textLight: darkPalette.contrast_700,
+      textInverted: darkPalette.black,
+      link: darkPalette.primary_500,
+      border: darkPalette.contrast_100,
+      borderDark: darkPalette.contrast_200,
+      icon: darkPalette.contrast_500,
 
       // non-standard
-      textVeryLight: colors.gray4,
-      replyLine: colors.gray5,
-      replyLineDot: colors.gray6,
-      unreadNotifBg: colors.blue7,
-      unreadNotifBorder: colors.blue6,
-      postCtrl: '#707489',
-      brandText: '#0085ff',
-      emptyStateIcon: colors.gray4,
-      borderLinkHover: colors.gray5,
+      textVeryLight: darkPalette.contrast_400,
+      replyLine: darkPalette.contrast_100,
+      replyLineDot: darkPalette.contrast_200,
+      unreadNotifBg: darkPalette.primary_975,
+      unreadNotifBorder: darkPalette.primary_900,
+      postCtrl: darkPalette.contrast_500,
+      brandText: darkPalette.primary_500,
+      emptyStateIcon: darkPalette.contrast_300,
+      borderLinkHover: darkPalette.contrast_300,
     },
     primary: {
       ...defaultTheme.palette.primary,
@@ -322,15 +324,15 @@ export const darkTheme: Theme = {
       textInverted: colors.green2,
     },
     inverted: {
-      background: colors.white,
-      backgroundLight: colors.gray2,
-      text: colors.black,
-      textLight: colors.gray5,
-      textInverted: colors.white,
-      link: colors.blue3,
-      border: colors.gray3,
-      borderDark: colors.gray4,
-      icon: colors.gray1,
+      background: lightPalette.white,
+      backgroundLight: lightPalette.contrast_50,
+      text: lightPalette.black,
+      textLight: lightPalette.contrast_700,
+      textInverted: lightPalette.white,
+      link: lightPalette.primary_500,
+      border: lightPalette.contrast_100,
+      borderDark: lightPalette.contrast_200,
+      icon: lightPalette.contrast_500,
     },
   },
 }