mirror of
https://github.com/tooot-app/app
synced 2025-02-07 05:45:23 +01:00
Rewrite timeline pagination
Using Link in returned headers instead. Also, `since_id` is not the correct way to refresh. See https://mastodonpy.readthedocs.io/en/stable/index.html?highlight=pagination#a-note-about-pagination
This commit is contained in:
parent
9c30edcc65
commit
2ab227a370
@ -23,10 +23,10 @@ export async function client (url, query, { body, ...customConfig } = {}) {
|
||||
|
||||
let data
|
||||
try {
|
||||
const response = await fetch(`https://${url}${queryString}`, config)
|
||||
const response = await fetch(`${url}${queryString}`, config)
|
||||
data = await response.json()
|
||||
if (response.ok) {
|
||||
return data
|
||||
return { headers: response.headers, body: data }
|
||||
}
|
||||
throw new Error(response.statusText)
|
||||
} catch (err) {
|
||||
|
@ -43,26 +43,11 @@ export default function Timeline ({
|
||||
{...(state.pointer && { initialScrollIndex: state.pointer })}
|
||||
{...(!disableRefresh && {
|
||||
onRefresh: () =>
|
||||
dispatch(
|
||||
fetch({
|
||||
page,
|
||||
query: [{ key: 'since_id', value: state.toots[0].id }]
|
||||
})
|
||||
),
|
||||
dispatch(fetch({ page, paginationDirection: 'prev' })),
|
||||
refreshing: state.status === 'loading',
|
||||
onEndReached: () => {
|
||||
if (!timelineReady) {
|
||||
dispatch(
|
||||
fetch({
|
||||
page,
|
||||
query: [
|
||||
{
|
||||
key: 'max_id',
|
||||
value: state.toots[state.toots.length - 1].id
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
dispatch(fetch({ page, paginationDirection: 'next' }))
|
||||
setTimelineReady(true)
|
||||
}
|
||||
},
|
||||
|
@ -5,9 +5,9 @@ import { client } from 'src/api/client'
|
||||
export const fetch = createAsyncThunk(
|
||||
'account/fetch',
|
||||
async ({ id }, { getState }) => {
|
||||
const instanceLocal = getState().instanceInfo.local + '/api/v1/'
|
||||
|
||||
return await client.get(`${instanceLocal}accounts/${id}`)
|
||||
const instanceLocal = `https://${getState().instanceInfo.local}/api/v1/`
|
||||
const res = await client.get(`${instanceLocal}accounts/${id}`)
|
||||
return res.body
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -11,11 +11,35 @@ import { client } from 'src/api/client'
|
||||
// Hashtag: hastag
|
||||
// List: list
|
||||
|
||||
function getPagination (headers, direction) {
|
||||
if (!headers) console.error('Missing pagination headers')
|
||||
const paginationLinks = headers.get('Link')
|
||||
if (paginationLinks) {
|
||||
if (direction) {
|
||||
return {
|
||||
[direction]: paginationLinks.split(
|
||||
new RegExp(`<([^>]+)>; rel="${direction}"`)
|
||||
)[1]
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
prev: paginationLinks.split(new RegExp(/<([^>]+)>; rel="prev"/))[1],
|
||||
next: paginationLinks.split(new RegExp(/<([^>]+)>; rel="next"/))[1]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
export const fetch = createAsyncThunk(
|
||||
'timeline/fetch',
|
||||
async ({ page, query = [], account, hashtag, list, toot }, { getState }) => {
|
||||
const instanceLocal = getState().instanceInfo.local + '/api/v1/'
|
||||
const instanceRemote = getState().instanceInfo.remote + '/api/v1/'
|
||||
async (
|
||||
{ page, paginationDirection, query = [], account, hashtag, list, toot },
|
||||
{ getState }
|
||||
) => {
|
||||
const instanceLocal = `https://${getState().instanceInfo.local}/api/v1/`
|
||||
const instanceRemote = `https://${getState().instanceInfo.remote}/api/v1/`
|
||||
// If header if needed for remote server
|
||||
const header = {
|
||||
headers: {
|
||||
@ -23,90 +47,123 @@ export const fetch = createAsyncThunk(
|
||||
}
|
||||
}
|
||||
|
||||
let res
|
||||
// For same page, but only pagination
|
||||
if (paginationDirection) {
|
||||
res = await client.get(
|
||||
getState().timelines[page].pagination[paginationDirection],
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers, paginationDirection)
|
||||
}
|
||||
}
|
||||
|
||||
// For each page's first query
|
||||
switch (page) {
|
||||
case 'Following':
|
||||
res = await client.get(`${instanceLocal}timelines/home`, query, header)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}timelines/home`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'Local':
|
||||
query.push({ key: 'local', value: 'true' })
|
||||
res = await client.get(
|
||||
`${instanceLocal}timelines/public`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}timelines/public`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'LocalPublic':
|
||||
res = await client.get(
|
||||
`${instanceLocal}timelines/public`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}timelines/public`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'RemotePublic':
|
||||
res = await client.get(`${instanceRemote}timelines/public`, query)
|
||||
return {
|
||||
toots: await client.get(`${instanceRemote}timelines/public`, query)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'Notifications':
|
||||
res = await client.get(`${instanceLocal}notifications`, query, header)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}notifications`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'Account_Default':
|
||||
const toots = await client.get(
|
||||
res = await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
[{ key: 'pinned', value: 'true' }],
|
||||
header
|
||||
)
|
||||
toots.push(
|
||||
...(await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
[{ key: 'exclude_replies', value: 'true' }],
|
||||
header
|
||||
))
|
||||
const toots = res.body
|
||||
res = await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
[{ key: 'exclude_replies', value: 'true' }],
|
||||
header
|
||||
)
|
||||
toots.push(...res.body)
|
||||
return { toots: toots }
|
||||
|
||||
case 'Account_All':
|
||||
res = await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body
|
||||
}
|
||||
|
||||
case 'Account_Media':
|
||||
res = await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
[{ key: 'only_media', value: 'true' }],
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}accounts/${account}/statuses`,
|
||||
[{ key: 'only_media', value: 'true' }],
|
||||
header
|
||||
)
|
||||
toots: res.body
|
||||
}
|
||||
|
||||
case 'Hashtag':
|
||||
res = await client.get(
|
||||
`${instanceLocal}timelines/tag/${hashtag}`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}timelines/tag/${hashtag}`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'List':
|
||||
res = await client.get(
|
||||
`${instanceLocal}timelines/list/${list}`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
return {
|
||||
toots: await client.get(
|
||||
`${instanceLocal}timelines/list/${list}`,
|
||||
query,
|
||||
header
|
||||
)
|
||||
toots: res.body,
|
||||
pagination: getPagination(res.headers)
|
||||
}
|
||||
|
||||
case 'Toot':
|
||||
const current = await client.get(
|
||||
`${instanceLocal}statuses/${toot}`,
|
||||
@ -122,14 +179,16 @@ export const fetch = createAsyncThunk(
|
||||
toots: [...context.ancestors, current, ...context.descendants],
|
||||
pointer: context.ancestors.length
|
||||
}
|
||||
|
||||
default:
|
||||
console.error('Timeline type error')
|
||||
console.error('First time fetching timeline error')
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const timelineInitState = {
|
||||
toots: [],
|
||||
pagination: { prev: undefined, next: undefined },
|
||||
pointer: undefined,
|
||||
status: 'idle'
|
||||
}
|
||||
@ -160,15 +219,22 @@ export const timelineSlice = createSlice({
|
||||
},
|
||||
[fetch.fulfilled]: (state, action) => {
|
||||
state[action.meta.arg.page].status = 'succeeded'
|
||||
if (
|
||||
action.meta.arg.query &&
|
||||
action.meta.arg.query[0].key === 'since_id'
|
||||
) {
|
||||
|
||||
if (action.meta.arg.paginationDirection === 'prev') {
|
||||
state[action.meta.arg.page].toots.unshift(...action.payload.toots)
|
||||
} else {
|
||||
state[action.meta.arg.page].toots.push(...action.payload.toots)
|
||||
}
|
||||
state[action.meta.arg.page].pointer = action.payload.pointer
|
||||
|
||||
if (action.payload.pagination) {
|
||||
state[action.meta.arg.page].pagination = {
|
||||
...state[action.meta.arg.page].pagination,
|
||||
...action.payload.pagination
|
||||
}
|
||||
}
|
||||
if (action.payload.pointer) {
|
||||
state[action.meta.arg.page].pointer = action.payload.pointer
|
||||
}
|
||||
},
|
||||
[fetch.rejected]: (state, action) => {
|
||||
state[action.meta.arg.page].status = 'failed'
|
||||
|
Loading…
x
Reference in New Issue
Block a user