More custom-feed behavior fixes [APP-678] (#831)
* Remove extraneous custom-feed health check * Fixes to custom feed preference sync * Fix lint * Remove dead code (client-side suggested posts constructor) * Enforce the feed-fetch limit in the client if the generator fails to observe the parameter * Bump the number of items fetched in the multifeed per feed from 5 to 10 * Reset the currently active feed when the pinned feeds change * Some fixes to icons * Add a prompt to load latest to the multifeed * Remove debug
This commit is contained in:
parent
e9c84a192b
commit
3217c7ff32
8 changed files with 88 additions and 186 deletions
|
@ -1,137 +0,0 @@
|
|||
import {RootStoreModel} from 'state/index'
|
||||
import {
|
||||
AppBskyFeedDefs,
|
||||
AppBskyFeedGetAuthorFeed as GetAuthorFeed,
|
||||
} from '@atproto/api'
|
||||
type ReasonRepost = AppBskyFeedDefs.ReasonRepost
|
||||
|
||||
async function getMultipleAuthorsPosts(
|
||||
rootStore: RootStoreModel,
|
||||
authors: string[],
|
||||
cursor: string | undefined = undefined,
|
||||
limit: number = 10,
|
||||
) {
|
||||
const responses = await Promise.all(
|
||||
authors.map((actor, index) =>
|
||||
rootStore.agent
|
||||
.getAuthorFeed({
|
||||
actor,
|
||||
limit,
|
||||
cursor: cursor ? cursor.split(',')[index] : undefined,
|
||||
})
|
||||
.catch(_err => ({success: false, headers: {}, data: {feed: []}})),
|
||||
),
|
||||
)
|
||||
return responses
|
||||
}
|
||||
|
||||
function mergePosts(
|
||||
responses: GetAuthorFeed.Response[],
|
||||
{repostsOnly, bestOfOnly}: {repostsOnly?: boolean; bestOfOnly?: boolean},
|
||||
) {
|
||||
let posts: AppBskyFeedDefs.FeedViewPost[] = []
|
||||
|
||||
if (bestOfOnly) {
|
||||
for (const res of responses) {
|
||||
if (res.success) {
|
||||
// filter the feed down to the post with the most likes
|
||||
res.data.feed = res.data.feed.reduce(
|
||||
(acc: AppBskyFeedDefs.FeedViewPost[], v) => {
|
||||
if (
|
||||
!acc?.[0] &&
|
||||
!v.reason &&
|
||||
!v.reply &&
|
||||
isRecentEnough(v.post.indexedAt)
|
||||
) {
|
||||
return [v]
|
||||
}
|
||||
if (
|
||||
acc &&
|
||||
!v.reason &&
|
||||
!v.reply &&
|
||||
(v.post.likeCount || 0) > (acc[0]?.post.likeCount || 0) &&
|
||||
isRecentEnough(v.post.indexedAt)
|
||||
) {
|
||||
return [v]
|
||||
}
|
||||
return acc
|
||||
},
|
||||
[],
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// merge into one array
|
||||
for (const res of responses) {
|
||||
if (res.success) {
|
||||
posts = posts.concat(res.data.feed)
|
||||
}
|
||||
}
|
||||
|
||||
// filter down to reposts of other users
|
||||
const uris = new Set()
|
||||
posts = posts.filter(p => {
|
||||
if (repostsOnly && !isARepostOfSomeoneElse(p)) {
|
||||
return false
|
||||
}
|
||||
if (uris.has(p.post.uri)) {
|
||||
return false
|
||||
}
|
||||
uris.add(p.post.uri)
|
||||
return true
|
||||
})
|
||||
|
||||
// sort by index time
|
||||
posts.sort((a, b) => {
|
||||
return (
|
||||
Number(new Date(b.post.indexedAt)) - Number(new Date(a.post.indexedAt))
|
||||
)
|
||||
})
|
||||
|
||||
return posts
|
||||
}
|
||||
|
||||
function isARepostOfSomeoneElse(post: AppBskyFeedDefs.FeedViewPost): boolean {
|
||||
return (
|
||||
post.reason?.$type === 'app.bsky.feed.defs#reasonRepost' &&
|
||||
post.post.author.did !== (post.reason as ReasonRepost).by.did
|
||||
)
|
||||
}
|
||||
|
||||
function getCombinedCursors(responses: GetAuthorFeed.Response[]) {
|
||||
let hasCursor = false
|
||||
const cursors = responses.map(r => {
|
||||
if (r.data.cursor) {
|
||||
hasCursor = true
|
||||
return r.data.cursor
|
||||
}
|
||||
return ''
|
||||
})
|
||||
if (!hasCursor) {
|
||||
return undefined
|
||||
}
|
||||
const combinedCursors = cursors.join(',')
|
||||
return combinedCursors
|
||||
}
|
||||
|
||||
function isCombinedCursor(cursor: string) {
|
||||
return cursor.includes(',')
|
||||
}
|
||||
|
||||
const TWO_DAYS_AGO = Date.now() - 1e3 * 60 * 60 * 48
|
||||
function isRecentEnough(date: string) {
|
||||
try {
|
||||
const d = Number(new Date(date))
|
||||
return d > TWO_DAYS_AGO
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getMultipleAuthorsPosts,
|
||||
mergePosts,
|
||||
getCombinedCursors,
|
||||
isCombinedCursor,
|
||||
}
|
32
src/lib/hooks/useTimer.ts
Normal file
32
src/lib/hooks/useTimer.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import * as React from 'react'
|
||||
|
||||
/**
|
||||
* Helper hook to run persistent timers on views
|
||||
*/
|
||||
export function useTimer(time: number, handler: () => void) {
|
||||
const timer = React.useRef(undefined)
|
||||
|
||||
// function to restart the timer
|
||||
const reset = React.useCallback(() => {
|
||||
if (timer.current) {
|
||||
clearTimeout(timer.current)
|
||||
}
|
||||
timer.current = setTimeout(handler, time)
|
||||
}, [time, timer, handler])
|
||||
|
||||
// function to cancel the timer
|
||||
const cancel = React.useCallback(() => {
|
||||
if (timer.current) {
|
||||
clearTimeout(timer.current)
|
||||
timer.current = undefined
|
||||
}
|
||||
}, [timer])
|
||||
|
||||
// start the timer immediately
|
||||
React.useEffect(() => {
|
||||
reset()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [])
|
||||
|
||||
return [reset, cancel]
|
||||
}
|
|
@ -801,8 +801,8 @@ export function SquarePlusIcon({
|
|||
height={size || 24}
|
||||
style={style}>
|
||||
<Line
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
x1="12"
|
||||
y1="5.5"
|
||||
x2="12"
|
||||
|
@ -810,8 +810,8 @@ export function SquarePlusIcon({
|
|||
strokeWidth={strokeWidth * 1.5}
|
||||
/>
|
||||
<Line
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
x1="5.5"
|
||||
y1="12"
|
||||
x2="18.5"
|
||||
|
@ -943,11 +943,11 @@ export function SatelliteDishIcon({
|
|||
<Path d="M5.25593 8.3303L5.25609 8.33047L5.25616 8.33056L5.25621 8.33061L5.27377 8.35018L5.29289 8.3693L13.7929 16.8693L13.8131 16.8895L13.8338 16.908L13.834 16.9081L13.8342 16.9083L13.8342 16.9083L13.8345 16.9086L13.8381 16.9118L13.8574 16.9294C13.8752 16.9458 13.9026 16.9711 13.9377 17.0043C14.0081 17.0708 14.1088 17.1683 14.2258 17.2881C14.4635 17.5315 14.7526 17.8509 14.9928 18.1812C15.2067 18.4755 15.3299 18.7087 15.3817 18.8634C14.0859 19.5872 12.5926 20 11 20C6.02944 20 2 15.9706 2 11C2 9.4151 2.40883 7.9285 3.12619 6.63699C3.304 6.69748 3.56745 6.84213 3.89275 7.08309C4.24679 7.34534 4.58866 7.65673 4.84827 7.9106C4.97633 8.03583 5.08062 8.14337 5.152 8.21863C5.18763 8.25619 5.21487 8.28551 5.23257 8.30473L5.25178 8.32572L5.25571 8.33006L5.25593 8.3303ZM3.00217 6.60712C3.00217 6.6071 3.00267 6.6071 3.00372 6.60715C3.00271 6.60716 3.00218 6.60714 3.00217 6.60712Z" />
|
||||
<Path
|
||||
d="M8 1.62961C9.04899 1.22255 10.1847 1 11.3704 1C16.6887 1 21 5.47715 21 11C21 12.0452 20.8456 13.053 20.5592 14"
|
||||
stroke-linecap="round"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<Path
|
||||
d="M9 5.38745C9.64553 5.13695 10.3444 5 11.0741 5C14.3469 5 17 7.75517 17 11.1538C17 11.797 16.905 12.4172 16.7287 13"
|
||||
stroke-linecap="round"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<Path
|
||||
d="M12 12C12 12.7403 11.5978 13.3866 11 13.7324L8.26756 11C8.61337 10.4022 9.25972 10 10 10C11.1046 10 12 10.8954 12 12Z"
|
||||
|
|
|
@ -20,6 +20,7 @@ export function isStateAtTabRoot(state: State | undefined) {
|
|||
return (
|
||||
isTab(currentRoute.name, 'Home') ||
|
||||
isTab(currentRoute.name, 'Search') ||
|
||||
isTab(currentRoute.name, 'Feeds') ||
|
||||
isTab(currentRoute.name, 'Notifications') ||
|
||||
isTab(currentRoute.name, 'MyProfile')
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue