mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Use ky
instead of fetch
This commit is contained in:
parent
aa53533534
commit
698b54868e
67
package-lock.json
generated
67
package-lock.json
generated
@ -4631,6 +4631,11 @@
|
|||||||
"graceful-fs": "^4.1.9"
|
"graceful-fs": "^4.1.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ky": {
|
||||||
|
"version": "0.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ky/-/ky-0.24.0.tgz",
|
||||||
|
"integrity": "sha512-/vpuQguwV30jErrqLpoaU/YJAFALrUkqqWLILnSoBOj5/O/LKzro/pPNtxbLgY6m4w5XNM6YZ3v7/or8qLlFuw=="
|
||||||
|
},
|
||||||
"leven": {
|
"leven": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
|
||||||
@ -6020,6 +6025,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
|
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
|
||||||
},
|
},
|
||||||
|
"path-to-regexp": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
|
||||||
|
"requires": {
|
||||||
|
"isarray": "0.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"isarray": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||||
|
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"pify": {
|
"pify": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||||
@ -6717,6 +6737,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-3.1.4.tgz",
|
||||||
"integrity": "sha512-bXx3hqz4LovFoMnJIRGIWL2oJ/PHadXviBKvgZV9yNErtURQLJSn0yfQytVtiqslhaBMZOJwH4R6HiClyofvBg=="
|
"integrity": "sha512-bXx3hqz4LovFoMnJIRGIWL2oJ/PHadXviBKvgZV9yNErtURQLJSn0yfQytVtiqslhaBMZOJwH4R6HiClyofvBg=="
|
||||||
},
|
},
|
||||||
|
"react-native-safe-area-view": {
|
||||||
|
"version": "0.14.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-view/-/react-native-safe-area-view-0.14.9.tgz",
|
||||||
|
"integrity": "sha512-WII/ulhpVyL/qbYb7vydq7dJAfZRBcEhg4/UWt6F6nAKpLa3gAceMOxBxI914ppwSP/TdUsandFy6lkJQE0z4A==",
|
||||||
|
"requires": {
|
||||||
|
"hoist-non-react-statics": "^2.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-native-screens": {
|
"react-native-screens": {
|
||||||
"version": "2.10.1",
|
"version": "2.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-2.10.1.tgz",
|
||||||
@ -6754,6 +6782,45 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-navigation": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-navigation/-/react-navigation-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-tNBQQzbw0PVo9FLypQUUCISMcXW0wCW8oQeHtY0spWf35KC3IZHq/WcBm4E956wFsaqrDMGCUnyaVrxZNSuUGg==",
|
||||||
|
"requires": {
|
||||||
|
"@react-navigation/core": "^3.7.9",
|
||||||
|
"@react-navigation/native": "^3.8.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/core": {
|
||||||
|
"version": "3.7.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-3.7.9.tgz",
|
||||||
|
"integrity": "sha512-EknbzM8OI9A5alRxXtQRV5Awle68B+z1QAxNty5DxmlS3BNfmduWNGnim159ROyqxkuDffK9L/U/Tbd45mx+Jg==",
|
||||||
|
"requires": {
|
||||||
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
|
"path-to-regexp": "^1.8.0",
|
||||||
|
"query-string": "^6.13.6",
|
||||||
|
"react-is": "^16.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@react-navigation/native": {
|
||||||
|
"version": "3.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-3.8.3.tgz",
|
||||||
|
"integrity": "sha512-1yLd2pi8SK3wPC58mWZ5fjW5uYr1gmMN8YwjkA2qVjyVYfzzctRkoFDu8poO5UzxEIgf/4ns6ezBtKY1Q601UQ==",
|
||||||
|
"requires": {
|
||||||
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
|
"react-native-safe-area-view": "^0.14.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hoist-non-react-statics": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||||
|
"requires": {
|
||||||
|
"react-is": "^16.7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-redux": {
|
"react-redux": {
|
||||||
"version": "7.2.2",
|
"version": "7.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
|
||||||
|
12
package.json
12
package.json
@ -12,13 +12,18 @@
|
|||||||
"@react-native-async-storage/async-storage": "^1.13.0",
|
"@react-native-async-storage/async-storage": "^1.13.0",
|
||||||
"@react-native-community/masked-view": "0.1.10",
|
"@react-native-community/masked-view": "0.1.10",
|
||||||
"@react-native-community/segmented-control": "2.1.1",
|
"@react-native-community/segmented-control": "2.1.1",
|
||||||
|
"@react-native-community/viewpager": "4.1.6",
|
||||||
"@react-navigation/bottom-tabs": "^5.9.2",
|
"@react-navigation/bottom-tabs": "^5.9.2",
|
||||||
"@react-navigation/native": "^5.7.6",
|
"@react-navigation/native": "^5.7.6",
|
||||||
"@react-navigation/stack": "^5.9.3",
|
"@react-navigation/stack": "^5.9.3",
|
||||||
"@reduxjs/toolkit": "^1.4.0",
|
"@reduxjs/toolkit": "^1.4.0",
|
||||||
"expo": "~39.0.2",
|
"expo": "~39.0.2",
|
||||||
"expo-app-auth": "~9.2.0",
|
"expo-app-auth": "~9.2.0",
|
||||||
|
"expo-av": "~8.6.0",
|
||||||
|
"expo-secure-store": "~9.2.0",
|
||||||
|
"expo-splash-screen": "~0.6.1",
|
||||||
"expo-status-bar": "~1.0.2",
|
"expo-status-bar": "~1.0.2",
|
||||||
|
"ky": "^0.24.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
"react-dom": "16.13.1",
|
"react-dom": "16.13.1",
|
||||||
@ -33,11 +38,8 @@
|
|||||||
"react-native-screens": "~2.10.1",
|
"react-native-screens": "~2.10.1",
|
||||||
"react-native-web": "~0.13.7",
|
"react-native-web": "~0.13.7",
|
||||||
"react-native-webview": "10.7.0",
|
"react-native-webview": "10.7.0",
|
||||||
"react-redux": "^7.2.1",
|
"react-navigation": "^4.4.3",
|
||||||
"expo-av": "~8.6.0",
|
"react-redux": "^7.2.1"
|
||||||
"expo-secure-store": "~9.2.0",
|
|
||||||
"expo-splash-screen": "~0.6.1",
|
|
||||||
"@react-native-community/viewpager": "4.1.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "~7.9.0",
|
"@babel/core": "~7.9.0",
|
||||||
|
@ -1,43 +1,40 @@
|
|||||||
export async function client (url, query, { body, ...customConfig } = {}) {
|
import store from 'src/stacks/common/store'
|
||||||
if (!url) {
|
import ky from 'ky'
|
||||||
return Promise.reject('Missing URL.')
|
|
||||||
}
|
|
||||||
const headers = { 'Content-Type': 'application/json' }
|
|
||||||
|
|
||||||
const config = {
|
export default async function client ({
|
||||||
method: body ? 'POST' : 'GET',
|
method, // * get / post
|
||||||
...customConfig,
|
instance, // * local / remote
|
||||||
headers: {
|
endpoint, // * if url is empty
|
||||||
...headers,
|
query, // object
|
||||||
...customConfig.headers
|
body // object
|
||||||
}
|
}) {
|
||||||
}
|
const state = store.getState().instanceInfo
|
||||||
|
|
||||||
const queryString = query
|
let response
|
||||||
? `?${query.map(({ key, value }) => `${key}=${value}`).join('&')}`
|
|
||||||
: ''
|
|
||||||
|
|
||||||
if (body) {
|
|
||||||
config.body = JSON.stringify(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
let data
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${url}${queryString}`, config)
|
response = await ky(endpoint, {
|
||||||
data = await response.json()
|
method: method,
|
||||||
if (response.ok) {
|
prefixUrl: `https://${state[instance]}/api/v1`,
|
||||||
return { headers: response.headers, body: data }
|
searchParams: query,
|
||||||
}
|
headers: {
|
||||||
throw new Error(response.statusText)
|
'Content-Type': 'application/json',
|
||||||
} catch (err) {
|
...(instance === 'local' && {
|
||||||
return Promise.reject(err.message ? err.message : data)
|
Authorization: `Bearer ${state.localToken}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
...(body && { json: body })
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
return Promise.reject('ky error')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
return Promise.resolve({
|
||||||
|
headers: response.headers,
|
||||||
|
body: await response.json()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(response.error)
|
||||||
|
return Promise.reject({ body: response.error_message })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
client.get = function (instance, endpoint, query, customConfig = {}) {
|
|
||||||
return client(instance, endpoint, query, { ...customConfig, method: 'GET' })
|
|
||||||
}
|
|
||||||
|
|
||||||
client.post = function (instance, endpoint, query, body, customConfig = {}) {
|
|
||||||
return client(instance, endpoint, query, { ...customConfig, body })
|
|
||||||
}
|
|
||||||
|
61
src/api/client.js.backup
Normal file
61
src/api/client.js.backup
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import store from 'src/stacks/common/store'
|
||||||
|
|
||||||
|
export async function client (instance, query, { body, ...customConfig } = {}) {
|
||||||
|
const state = store.getState().instanceInfo
|
||||||
|
|
||||||
|
let url
|
||||||
|
let authHeader
|
||||||
|
switch (instance.type) {
|
||||||
|
case 'local':
|
||||||
|
url = `https://${state.local}/${instance.endpoint}`
|
||||||
|
authHeader = {
|
||||||
|
Authorization: `Bearer ${state.localToken}`
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'remote':
|
||||||
|
url = `https://${state.remote}/${instance.endpoint}`
|
||||||
|
authHeader = {}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return Promise.reject('Instance type is not defined.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = { 'Content-Type': 'application/json', ...authHeader }
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
method: body ? 'POST' : 'GET',
|
||||||
|
...customConfig,
|
||||||
|
headers: {
|
||||||
|
...headers,
|
||||||
|
...customConfig.headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryString = query
|
||||||
|
? `?${query.map(({ key, value }) => `${key}=${value}`).join('&')}`
|
||||||
|
: ''
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
config.body = JSON.stringify(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
let data
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${url}${queryString}`, config)
|
||||||
|
data = await response.json()
|
||||||
|
if (response.ok) {
|
||||||
|
return { headers: response.headers, body: data }
|
||||||
|
}
|
||||||
|
throw new Error(response.statusText)
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err.message ? err.message : data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.get = function (instance, endpoint, query, customConfig = {}) {
|
||||||
|
return client(instance, endpoint, query, { ...customConfig, method: 'GET' })
|
||||||
|
}
|
||||||
|
|
||||||
|
client.post = function (instance, endpoint, query, body, customConfig = {}) {
|
||||||
|
return client(instance, endpoint, query, { ...customConfig, body })
|
||||||
|
}
|
@ -3,7 +3,10 @@ import PropTypes from 'prop-types'
|
|||||||
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
import { Pressable, StyleSheet, Text, View } from 'react-native'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
|
import action from 'src/components/action'
|
||||||
|
|
||||||
export default function Actions ({
|
export default function Actions ({
|
||||||
|
id,
|
||||||
replies_count,
|
replies_count,
|
||||||
reblogs_count,
|
reblogs_count,
|
||||||
reblogged,
|
reblogged,
|
||||||
@ -20,7 +23,7 @@ export default function Actions ({
|
|||||||
<Feather name='repeat' />
|
<Feather name='repeat' />
|
||||||
<Text>{reblogs_count}</Text>
|
<Text>{reblogs_count}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Pressable style={styles.action}>
|
<Pressable style={styles.action} onPress={() => action('favourite', id)}>
|
||||||
<Feather name='heart' />
|
<Feather name='heart' />
|
||||||
<Text>{favourites_count}</Text>
|
<Text>{favourites_count}</Text>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
@ -34,15 +37,23 @@ export default function Actions ({
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
actions: {
|
actions: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexDirection: 'row'
|
flexDirection: 'row',
|
||||||
|
marginTop: 4
|
||||||
},
|
},
|
||||||
action: {
|
action: {
|
||||||
width: '25%',
|
width: '25%',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center'
|
justifyContent: 'center',
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingBottom: 8
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Actions.propTypes = {
|
Actions.propTypes = {
|
||||||
// uri: PropTypes.string
|
id: PropTypes.string.isRequired,
|
||||||
// }
|
replies_count: PropTypes.number.isRequired,
|
||||||
|
reblogs_count: PropTypes.number.isRequired,
|
||||||
|
reblogged: PropTypes.bool.isRequired,
|
||||||
|
favourites_count: PropTypes.number.isRequired,
|
||||||
|
favourited: PropTypes.bool.isRequired
|
||||||
|
}
|
||||||
|
@ -35,7 +35,6 @@ export default function TootNotification ({ toot }) {
|
|||||||
account={actualAccount.acct}
|
account={actualAccount.acct}
|
||||||
created_at={toot.created_at}
|
created_at={toot.created_at}
|
||||||
/>
|
/>
|
||||||
{/* Can pass toot info to next page to speed up performance */}
|
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => navigation.navigate('Toot', { toot: toot.id })}
|
onPress={() => navigation.navigate('Toot', { toot: toot.id })}
|
||||||
>
|
>
|
||||||
@ -52,7 +51,7 @@ export default function TootNotification ({ toot }) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{toot.status.poll && <Poll poll={toot.status.poll} />}
|
{toot.status.poll && <Poll poll={toot.status.poll} />}
|
||||||
{toot.status.media_attachments && (
|
{toot.status.media_attachments.length > 0 && (
|
||||||
<Attachment
|
<Attachment
|
||||||
media_attachments={toot.status.media_attachments}
|
media_attachments={toot.status.media_attachments}
|
||||||
sensitive={toot.status.sensitive}
|
sensitive={toot.status.sensitive}
|
||||||
@ -67,6 +66,7 @@ export default function TootNotification ({ toot }) {
|
|||||||
</Pressable>
|
</Pressable>
|
||||||
{toot.status && (
|
{toot.status && (
|
||||||
<Actions
|
<Actions
|
||||||
|
id={toot.status.id}
|
||||||
replies_count={toot.status.replies_count}
|
replies_count={toot.status.replies_count}
|
||||||
reblogs_count={toot.status.reblogs_count}
|
reblogs_count={toot.status.reblogs_count}
|
||||||
reblogged={toot.status.reblogged}
|
reblogged={toot.status.reblogged}
|
||||||
@ -78,7 +78,7 @@ export default function TootNotification ({ toot }) {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
}, [toot])
|
||||||
|
|
||||||
return tootView
|
return tootView
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,9 @@ export default function TootTimeline ({ toot }) {
|
|||||||
/>
|
/>
|
||||||
{/* Can pass toot info to next page to speed up performance */}
|
{/* Can pass toot info to next page to speed up performance */}
|
||||||
<Pressable
|
<Pressable
|
||||||
// onPress={() =>
|
onPress={() =>
|
||||||
// navigation.navigate('Toot', { toot: actualContent.id })
|
navigation.navigate('Toot', { toot: actualContent.id })
|
||||||
// }
|
}
|
||||||
>
|
>
|
||||||
{actualContent.content ? (
|
{actualContent.content ? (
|
||||||
<Content
|
<Content
|
||||||
@ -77,6 +77,7 @@ export default function TootTimeline ({ toot }) {
|
|||||||
{actualContent.card && <Card card={actualContent.card} />}
|
{actualContent.card && <Card card={actualContent.card} />}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<Actions
|
<Actions
|
||||||
|
id={actualContent.id}
|
||||||
replies_count={actualContent.replies_count}
|
replies_count={actualContent.replies_count}
|
||||||
reblogs_count={actualContent.reblogs_count}
|
reblogs_count={actualContent.reblogs_count}
|
||||||
reblogged={actualContent.reblogged}
|
reblogged={actualContent.reblogged}
|
||||||
|
63
src/components/action.js
Normal file
63
src/components/action.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { Alert } from 'react-native'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
|
import { client } from 'src/api/client'
|
||||||
|
|
||||||
|
export default async function action (type, id) {
|
||||||
|
// If header if needed for remote server
|
||||||
|
const header = {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${useSelector(
|
||||||
|
state => state.instanceInfo.localToken
|
||||||
|
)}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const instance = `https://${useSelector(
|
||||||
|
state => state.instanceInfo.local
|
||||||
|
)}/api/v1/`
|
||||||
|
|
||||||
|
let endpoint
|
||||||
|
switch (type) {
|
||||||
|
case 'favourite':
|
||||||
|
endpoint = `${instance}statuses/${id}/favourite`
|
||||||
|
break
|
||||||
|
case 'unfavourite':
|
||||||
|
endpoint = `${instance}statuses/${id}/unfavourite`
|
||||||
|
break
|
||||||
|
case 'reblog':
|
||||||
|
endpoint = `${instance}statuses/${id}/reblog`
|
||||||
|
break
|
||||||
|
case 'unreblog':
|
||||||
|
endpoint = `${instance}statuses/${id}/unreblog`
|
||||||
|
break
|
||||||
|
case 'bookmark':
|
||||||
|
endpoint = `${instance}statuses/${id}/bookmark`
|
||||||
|
break
|
||||||
|
case 'unbookmark':
|
||||||
|
endpoint = `${instance}statuses/${id}/unbookmark`
|
||||||
|
break
|
||||||
|
case 'mute':
|
||||||
|
endpoint = `${instance}statuses/${id}/mute`
|
||||||
|
break
|
||||||
|
case 'unmute':
|
||||||
|
endpoint = `${instance}statuses/${id}/unmute`
|
||||||
|
break
|
||||||
|
case 'pin':
|
||||||
|
endpoint = `${instance}statuses/${id}/pin`
|
||||||
|
break
|
||||||
|
case 'unpin':
|
||||||
|
endpoint = `${instance}statuses/${id}/unpin`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await client.post(endpoint, [], header)
|
||||||
|
console.log(res)
|
||||||
|
|
||||||
|
const alert = {
|
||||||
|
title: 'This is a title',
|
||||||
|
message: 'This is a message'
|
||||||
|
}
|
||||||
|
Alert.alert(alert.title, alert.message, [
|
||||||
|
{ text: 'OK', onPress: () => console.log('OK Pressed') }
|
||||||
|
])
|
||||||
|
}
|
@ -6,7 +6,7 @@ const propTypesAttachment = PropTypes.shape({
|
|||||||
type: PropTypes.oneOf(['unknown', 'image', 'gifv', 'video', 'audio'])
|
type: PropTypes.oneOf(['unknown', 'image', 'gifv', 'video', 'audio'])
|
||||||
.isRequired,
|
.isRequired,
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
preview_url: PropTypes.string.isRequired,
|
preview_url: PropTypes.string,
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
remote_url: PropTypes.string,
|
remote_url: PropTypes.string,
|
||||||
|
@ -15,7 +15,7 @@ export default function Timeline ({
|
|||||||
list,
|
list,
|
||||||
toot,
|
toot,
|
||||||
account,
|
account,
|
||||||
disableRefresh
|
disableRefresh = false
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const state = useSelector(state => state.timelines[page])
|
const state = useSelector(state => state.timelines[page])
|
||||||
@ -50,11 +50,25 @@ export default function Timeline ({
|
|||||||
{...(state.pointer && { initialScrollIndex: state.pointer })}
|
{...(state.pointer && { initialScrollIndex: state.pointer })}
|
||||||
{...(!disableRefresh && {
|
{...(!disableRefresh && {
|
||||||
onRefresh: () =>
|
onRefresh: () =>
|
||||||
dispatch(fetch({ page, paginationDirection: 'prev' })),
|
dispatch(
|
||||||
|
fetch({
|
||||||
|
page,
|
||||||
|
hashtag,
|
||||||
|
list,
|
||||||
|
paginationDirection: 'prev'
|
||||||
|
})
|
||||||
|
),
|
||||||
refreshing: state.status === 'loading',
|
refreshing: state.status === 'loading',
|
||||||
onEndReached: () => {
|
onEndReached: () => {
|
||||||
if (!timelineReady) {
|
if (!timelineReady) {
|
||||||
dispatch(fetch({ page, paginationDirection: 'next' }))
|
dispatch(
|
||||||
|
fetch({
|
||||||
|
page,
|
||||||
|
hashtag,
|
||||||
|
list,
|
||||||
|
paginationDirection: 'next'
|
||||||
|
})
|
||||||
|
)
|
||||||
setTimelineReady(true)
|
setTimelineReady(true)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -101,7 +101,8 @@ TimelinesCombined.propTypes = {
|
|||||||
content: PropTypes.arrayOf(
|
content: PropTypes.arrayOf(
|
||||||
PropTypes.exact({
|
PropTypes.exact({
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
page: Timeline.propTypes.page
|
page: Timeline.propTypes.page,
|
||||||
|
instance: PropTypes.oneOf(['local', 'remote'])
|
||||||
})
|
})
|
||||||
).isRequired
|
).isRequired
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
import { client } from 'src/api/client'
|
import client from 'src/api/client'
|
||||||
|
|
||||||
export const fetch = createAsyncThunk(
|
export const fetch = createAsyncThunk(
|
||||||
'account/fetch',
|
'account/fetch',
|
||||||
async ({ id }, { getState }) => {
|
async ({ id }, { getState }) => {
|
||||||
const instanceLocal = `https://${getState().instanceInfo.local}/api/v1/`
|
const res = await client({
|
||||||
const res = await client.get(`${instanceLocal}accounts/${id}`)
|
method: 'get',
|
||||||
|
instance: 'local',
|
||||||
|
endpoint: `accounts/${id}`
|
||||||
|
})
|
||||||
return res.body
|
return res.body
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
|
||||||
|
|
||||||
import { client } from 'src/api/client'
|
import client from 'src/api/client'
|
||||||
|
|
||||||
// Naming convention
|
// Naming convention
|
||||||
// Following: timelines/home
|
// Following: timelines/home
|
||||||
@ -11,170 +11,161 @@ import { client } from 'src/api/client'
|
|||||||
// Hashtag: hastag
|
// Hashtag: hastag
|
||||||
// List: list
|
// 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(
|
export const fetch = createAsyncThunk(
|
||||||
'timeline/fetch',
|
'timeline/fetch',
|
||||||
async (
|
async (
|
||||||
{ page, paginationDirection, query = [], account, hashtag, list, toot },
|
{ page, paginationDirection, query = {}, account, hashtag, list, toot },
|
||||||
{ getState }
|
{ 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: {
|
|
||||||
Authorization: `Bearer ${getState().instanceInfo.localToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let res
|
let res
|
||||||
// For same page, but only pagination
|
|
||||||
if (paginationDirection) {
|
if (paginationDirection) {
|
||||||
res = await client.get(
|
const allToots = getState().timelines[page].toots
|
||||||
getState().timelines[page].pagination[paginationDirection],
|
switch (paginationDirection) {
|
||||||
query,
|
case 'prev':
|
||||||
header
|
query.min_id = allToots[0].id
|
||||||
)
|
break
|
||||||
return {
|
case 'next':
|
||||||
toots: res.body,
|
query.max_id = allToots[allToots.length - 1].id
|
||||||
pagination: getPagination(res.headers, paginationDirection)
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each page's first query
|
|
||||||
switch (page) {
|
switch (page) {
|
||||||
case 'Following':
|
case 'Following':
|
||||||
res = await client.get(`${instanceLocal}timelines/home`, query, header)
|
res = await client({
|
||||||
|
method: 'get',
|
||||||
|
instance: 'local',
|
||||||
|
endpoint: 'timelines/home',
|
||||||
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Local':
|
case 'Local':
|
||||||
query.push({ key: 'local', value: 'true' })
|
query.local = 'true'
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}timelines/public`,
|
method: 'get',
|
||||||
query,
|
instance: 'local',
|
||||||
header
|
endpoint: 'timelines/public',
|
||||||
)
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'LocalPublic':
|
case 'LocalPublic':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}timelines/public`,
|
method: 'get',
|
||||||
query,
|
instance: 'local',
|
||||||
header
|
endpoint: 'timelines/public',
|
||||||
)
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'RemotePublic':
|
case 'RemotePublic':
|
||||||
res = await client.get(`${instanceRemote}timelines/public`, query)
|
res = await client({
|
||||||
|
method: 'get',
|
||||||
|
instance: 'remote',
|
||||||
|
endpoint: 'timelines/public',
|
||||||
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Notifications':
|
case 'Notifications':
|
||||||
res = await client.get(`${instanceLocal}notifications`, query, header)
|
res = await client({
|
||||||
|
method: 'get',
|
||||||
|
instance: 'local',
|
||||||
|
endpoint: 'notifications',
|
||||||
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Account_Default':
|
case 'Account_Default':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}accounts/${account}/statuses`,
|
method: 'get',
|
||||||
[{ key: 'pinned', value: 'true' }],
|
instance: 'local',
|
||||||
header
|
endpoint: `accounts/${account}/statuses`,
|
||||||
)
|
query: {
|
||||||
|
pinned: 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
const toots = res.body
|
const toots = res.body
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}accounts/${account}/statuses`,
|
method: 'get',
|
||||||
[{ key: 'exclude_replies', value: 'true' }],
|
instance: 'local',
|
||||||
header
|
endpoint: `accounts/${account}/statuses`,
|
||||||
)
|
query: {
|
||||||
|
exclude_replies: 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
toots.push(...res.body)
|
toots.push(...res.body)
|
||||||
return { toots: toots }
|
return { toots: toots }
|
||||||
|
|
||||||
case 'Account_All':
|
case 'Account_All':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}accounts/${account}/statuses`,
|
method: 'get',
|
||||||
query,
|
instance: 'local',
|
||||||
header
|
endpoint: `accounts/${account}/statuses`,
|
||||||
)
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body
|
toots: res.body
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Account_Media':
|
case 'Account_Media':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}accounts/${account}/statuses`,
|
method: 'get',
|
||||||
[{ key: 'only_media', value: 'true' }],
|
instance: 'local',
|
||||||
header
|
endpoint: `accounts/${account}/statuses`,
|
||||||
)
|
query: {
|
||||||
|
only_media: 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body
|
toots: res.body
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Hashtag':
|
case 'Hashtag':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}timelines/tag/${hashtag}`,
|
method: 'get',
|
||||||
query,
|
instance: 'local',
|
||||||
header
|
endpoint: `timelines/tag/${hashtag}`,
|
||||||
)
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'List':
|
case 'List':
|
||||||
res = await client.get(
|
res = await client({
|
||||||
`${instanceLocal}timelines/list/${list}`,
|
method: 'get',
|
||||||
query,
|
instance: 'local',
|
||||||
header
|
endpoint: `timelines/list/${list}`,
|
||||||
)
|
query
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
toots: res.body,
|
toots: res.body
|
||||||
pagination: getPagination(res.headers)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'Toot':
|
case 'Toot':
|
||||||
const current = await client.get(
|
const current = await client({
|
||||||
`${instanceLocal}statuses/${toot}`,
|
method: 'get',
|
||||||
[],
|
instance: 'local',
|
||||||
header
|
endpoint: `statuses/${toot}`
|
||||||
)
|
})
|
||||||
const context = await client.get(
|
const context = await client({
|
||||||
`${instanceLocal}statuses/${toot}/context`,
|
method: 'get',
|
||||||
[],
|
instance: 'local',
|
||||||
header
|
endpoint: `statuses/${toot}/context`
|
||||||
)
|
})
|
||||||
return {
|
return {
|
||||||
toots: [...context.ancestors, current, ...context.descendants],
|
toots: [...context.ancestors, current, ...context.descendants],
|
||||||
pointer: context.ancestors.length
|
pointer: context.ancestors.length
|
||||||
@ -188,7 +179,6 @@ export const fetch = createAsyncThunk(
|
|||||||
|
|
||||||
const timelineInitState = {
|
const timelineInitState = {
|
||||||
toots: [],
|
toots: [],
|
||||||
pagination: { prev: undefined, next: undefined },
|
|
||||||
pointer: undefined,
|
pointer: undefined,
|
||||||
status: 'idle'
|
status: 'idle'
|
||||||
}
|
}
|
||||||
@ -226,12 +216,6 @@ export const timelineSlice = createSlice({
|
|||||||
state[action.meta.arg.page].toots.push(...action.payload.toots)
|
state[action.meta.arg.page].toots.push(...action.payload.toots)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.payload.pagination) {
|
|
||||||
state[action.meta.arg.page].pagination = {
|
|
||||||
...state[action.meta.arg.page].pagination,
|
|
||||||
...action.payload.pagination
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (action.payload.pointer) {
|
if (action.payload.pointer) {
|
||||||
state[action.meta.arg.page].pointer = action.payload.pointer
|
state[action.meta.arg.page].pointer = action.payload.pointer
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user