Basic attachment done

Switch from ky to axios
This commit is contained in:
Zhiyuan Zheng 2020-12-05 01:55:53 +01:00
parent 82d9cdf702
commit b274aef31a
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
21 changed files with 284 additions and 213 deletions

View File

@ -14,6 +14,7 @@
"@react-navigation/bottom-tabs": "^5.10.6", "@react-navigation/bottom-tabs": "^5.10.6",
"@react-navigation/native": "^5.8.6", "@react-navigation/native": "^5.8.6",
"@reduxjs/toolkit": "^1.4.0", "@reduxjs/toolkit": "^1.4.0",
"axios": "^0.21.0",
"expo": "~39.0.4", "expo": "~39.0.4",
"expo-auth-session": "~2.0.0", "expo-auth-session": "~2.0.0",
"expo-av": "~8.6.0", "expo-av": "~8.6.0",
@ -25,7 +26,6 @@
"expo-splash-screen": "~0.6.1", "expo-splash-screen": "~0.6.1",
"expo-status-bar": "~1.0.2", "expo-status-bar": "~1.0.2",
"i18next": "^19.8.4", "i18next": "^19.8.4",
"ky": "^0.24.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"react": "16.13.1", "react": "16.13.1",
"react-dom": "16.13.1", "react-dom": "16.13.1",

View File

@ -1,37 +1,38 @@
import axios from 'axios'
import { store, RootState } from 'src/store' import { store, RootState } from 'src/store'
import ky from 'ky'
const client = async ({ const client = async ({
version = 'v1',
method, method,
instance, instance,
instanceUrl, instanceDomain,
endpoint, version = 'v1',
url,
params,
headers, headers,
query, body,
body onUploadProgress
}: { }: {
version?: 'v1' | 'v2'
method: 'get' | 'post' | 'put' | 'delete' method: 'get' | 'post' | 'put' | 'delete'
instance: 'local' | 'remote' instance: 'local' | 'remote'
instanceUrl?: string instanceDomain?: string
endpoint: string version?: 'v1' | 'v2'
headers?: { [key: string]: string } url: string
query?: { params?: {
[key: string]: string | number | boolean [key: string]: string | number | boolean
} }
headers?: { [key: string]: string }
body?: FormData body?: FormData
onUploadProgress?: (progressEvent: any) => void
}): Promise<any> => { }): Promise<any> => {
const state: RootState['instances'] = store.getState().instances const state: RootState['instances'] = store.getState().instances
const url = const domain =
instance === 'remote' ? instanceUrl || state.remote.url : state.local.url instance === 'remote' ? instanceDomain || state.remote.url : state.local.url
let response return axios({
// try { method,
response = await ky(endpoint, { baseURL: `https://${domain}/api/${version}/`,
method: method, url,
prefixUrl: `https://${url}/api/${version}`, params,
searchParams: query,
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
...headers, ...headers,
@ -39,28 +40,35 @@ const client = async ({
Authorization: `Bearer ${state.local.token}` Authorization: `Bearer ${state.local.token}`
}) })
}, },
...(body && { body: body }), ...(body && { data: body }),
throwHttpErrors: false ...(onUploadProgress && { onUploadProgress: onUploadProgress })
}) })
// } catch (error) { .then(response =>
// return Promise.reject('ky error: ' + error.json()) Promise.resolve({
// } headers: response.headers,
console.log('Query: /' + endpoint) body: response.data
if (response.ok) { })
return Promise.resolve({ )
headers: response.headers, .catch(error => {
body: await response.json() if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.error('axios error', error.response)
return Promise.reject({
headers: error.response.headers,
body: error.response.data.error
})
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.error('axios error', error)
return Promise.reject()
} else {
console.error('axios error', error.message)
return Promise.reject({ body: error.message })
}
}) })
} else {
let errorResponse
try {
errorResponse = await response.json()
} catch (error) {
return Promise.reject({ body: 'Nothing found' })
}
console.error(response.status + ': ' + errorResponse.error)
return Promise.reject({ body: errorResponse.error })
}
} }
export default client export default client

View File

@ -27,7 +27,7 @@ const fireMutation = async ({
res = await client({ res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `statuses/${id}/${prevState ? 'un' : ''}${type}` url: `statuses/${id}/${prevState ? 'un' : ''}${type}`
}) // bug in response from Mastodon }) // bug in response from Mastodon
if (!res.body[stateKey] === prevState) { if (!res.body[stateKey] === prevState) {

View File

@ -20,7 +20,7 @@ const fireMutation = async ({
res = await client({ res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `accounts/${id}/${type}` url: `accounts/${id}/${type}`
}) })
if (res.body[stateKey!] === true) { if (res.body[stateKey!] === true) {
@ -35,8 +35,8 @@ const fireMutation = async ({
res = await client({ res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `reports`, url: `reports`,
query: { params: {
account_id: id! account_id: id!
} }
}) })

View File

@ -10,8 +10,8 @@ const fireMutation = async ({ domain }: { domain: string }) => {
const res = await client({ const res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `domain_blocks`, url: `domain_blocks`,
query: { params: {
domain: domain! domain: domain!
} }
}) })

View File

@ -22,7 +22,7 @@ const fireMutation = async ({
res = await client({ res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `statuses/${id}/${prevState ? 'un' : ''}${type}` url: `statuses/${id}/${prevState ? 'un' : ''}${type}`
}) // bug in response from Mastodon }) // bug in response from Mastodon
if (!res.body[stateKey] === prevState) { if (!res.body[stateKey] === prevState) {
@ -37,7 +37,7 @@ const fireMutation = async ({
res = await client({ res = await client({
method: 'delete', method: 'delete',
instance: 'local', instance: 'local',
endpoint: `statuses/${id}` url: `statuses/${id}`
}) })
if (res.body[stateKey] === id) { if (res.body[stateKey] === id) {

View File

@ -29,7 +29,7 @@ const fireMutation = async ({
const res = await client({ const res = await client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: `polls/${id}/votes`, url: `polls/${id}/votes`,
body: formData body: formData
}) })

View File

@ -62,8 +62,8 @@ const Login: React.FC = () => {
const res = await client({ const res = await client({
method: 'post', method: 'post',
instance: 'remote', instance: 'remote',
instanceUrl: instance, instanceDomain: instance,
endpoint: `apps`, url: `apps`,
body: formData body: formData
}) })
if (res.body?.client_id.length > 0) { if (res.body?.client_id.length > 0) {

View File

@ -34,11 +34,10 @@ export type PostState = {
active: boolean active: boolean
total: number total: number
options: { options: {
'1': string '1': string | undefined
'2': string '2': string | undefined
'3': string '3': string | undefined
'4': string '4': string | undefined
[key: string]: string
} }
multiple: boolean multiple: boolean
expire: expire:
@ -51,12 +50,8 @@ export type PostState = {
| '604800' | '604800'
| string | string
} }
attachments: { attachments: Mastodon.Attachment[]
id: string attachmentUploadProgress: { progress: number; aspect: number } | undefined
url: string
preview_url: string
description: string
}[]
visibility: 'public' | 'unlisted' | 'private' | 'direct' visibility: 'public' | 'unlisted' | 'private' | 'direct'
} }
@ -82,19 +77,12 @@ export type PostAction =
payload: PostState['poll'] payload: PostState['poll']
} }
| { | {
type: 'attachments/add' type: 'attachments'
payload: { payload: PostState['attachments']
id: string
url: string
preview_url: string
description: string
}
} }
| { | {
type: 'attachments/remove' type: 'attachmentUploadProgress'
payload: { payload: PostState['attachmentUploadProgress']
id: string
}
} }
| { | {
type: 'visibility' type: 'visibility'
@ -114,15 +102,16 @@ const postInitialState: PostState = {
active: false, active: false,
total: 2, total: 2,
options: { options: {
'1': '', '1': undefined,
'2': '', '2': undefined,
'3': '', '3': undefined,
'4': '' '4': undefined
}, },
multiple: false, multiple: false,
expire: '86400' expire: '86400'
}, },
attachments: [], attachments: [],
attachmentUploadProgress: undefined,
visibility: visibility:
getLocalAccountPreferences(store.getState())[ getLocalAccountPreferences(store.getState())[
'posting:default:visibility' 'posting:default:visibility'
@ -140,13 +129,10 @@ const postReducer = (state: PostState, action: PostAction): PostState => {
return { ...state, emoji: action.payload } return { ...state, emoji: action.payload }
case 'poll': case 'poll':
return { ...state, poll: action.payload } return { ...state, poll: action.payload }
case 'attachments/add': case 'attachments':
return { ...state, attachments: state.attachments.concat(action.payload) } return { ...state, attachments: action.payload }
case 'attachments/remove': case 'attachmentUploadProgress':
return { return { ...state, attachmentUploadProgress: action.payload }
...state,
attachments: state.attachments.filter(a => a.id !== action.payload.id)
}
case 'visibility': case 'visibility':
return { ...state, visibility: action.payload } return { ...state, visibility: action.payload }
default: default:
@ -186,27 +172,29 @@ const Compose: React.FC = () => {
]) ])
} else { } else {
const formData = new FormData() const formData = new FormData()
formData.append('status', postState.text.raw) formData.append('status', postState.text.raw)
if (postState.poll.active) { if (postState.poll.active) {
Object.values(postState.poll.options) Object.values(postState.poll.options)
.filter(e => e.length) .filter(e => e?.length)
.forEach(e => { .forEach(e => formData.append('poll[options][]', e!))
formData.append('poll[options][]', e)
})
formData.append('poll[expires_in]', postState.poll.expire) formData.append('poll[expires_in]', postState.poll.expire)
formData.append('poll[multiple]', postState.poll.multiple.toString()) formData.append('poll[multiple]', postState.poll.multiple.toString())
} }
if (postState.attachments.length > 0) {
postState.attachments.forEach(attachment => if (postState.attachments.length) {
formData.append('media_ids[]', attachment.id) postState.attachments.forEach(e =>
formData.append('media_ids[]', e!.id)
) )
} }
formData.append('visibility', postState.visibility) formData.append('visibility', postState.visibility)
client({ client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: 'statuses', url: 'statuses',
headers: { headers: {
'Idempotency-Key': Date.now().toString() + Math.random().toString() 'Idempotency-Key': Date.now().toString() + Math.random().toString()
}, },

View File

@ -8,6 +8,8 @@ import {
Text, Text,
TextInput TextInput
} from 'react-native' } from 'react-native'
import { useSelector } from 'react-redux'
import { getLocalToken, getLocalUrl } from 'src/utils/slices/instancesSlice'
import { StyleConstants } from 'src/utils/styles/constants' import { StyleConstants } from 'src/utils/styles/constants'
import { useTheme } from 'src/utils/styles/ThemeManager' import { useTheme } from 'src/utils/styles/ThemeManager'
import { PostAction, PostState } from '../Compose' import { PostAction, PostState } from '../Compose'
@ -25,6 +27,8 @@ const ComposeActions: React.FC<Props> = ({
postDispatch postDispatch
}) => { }) => {
const { theme } = useTheme() const { theme } = useTheme()
const localUrl = useSelector(getLocalUrl)
const localToken = useSelector(getLocalToken)
const getVisibilityIcon = () => { const getVisibilityIcon = () => {
switch (postState.visibility) { switch (postState.visibility) {
@ -50,20 +54,30 @@ const ComposeActions: React.FC<Props> = ({
<Feather <Feather
name='aperture' name='aperture'
size={24} size={24}
color={postState.poll.active ? theme.secondary : theme.primary} color={
onPress={async () => postState.poll.active || postState.attachments.length >= 4
!postState.poll.active && ? theme.secondary
(await addAttachments({ postState, postDispatch })) : theme.primary
} }
onPress={async () => {
if (!postState.poll.active && postState.attachments.length < 4) {
await addAttachments({ postState, postDispatch })
}
}}
/> />
<Feather <Feather
name='bar-chart-2' name='bar-chart-2'
size={24} size={24}
color={ color={
postState.attachments.length > 0 ? theme.secondary : theme.primary postState.attachments.length || postState.attachmentUploadProgress
? theme.secondary
: theme.primary
} }
onPress={() => { onPress={() => {
if (postState.attachments.length === 0) { if (
!postState.attachments.length &&
!postState.attachmentUploadProgress
) {
postDispatch({ postDispatch({
type: 'poll', type: 'poll',
payload: { ...postState.poll, active: !postState.poll.active } payload: { ...postState.poll, active: !postState.poll.active }

View File

@ -1,8 +1,15 @@
import React, { Dispatch } from 'react' import React, { Dispatch, useCallback } from 'react'
import { Image, StyleSheet, View } from 'react-native' import {
ActivityIndicator,
FlatList,
Image,
StyleSheet,
View
} from 'react-native'
import { Feather } from '@expo/vector-icons' import { Feather } from '@expo/vector-icons'
import { PostAction, PostState } from '../Compose' import { PostAction, PostState } from '../Compose'
import { StyleConstants } from 'src/utils/styles/constants'
export interface Props { export interface Props {
postState: PostState postState: PostState
@ -10,31 +17,66 @@ export interface Props {
} }
const ComposeAttachments: React.FC<Props> = ({ postState, postDispatch }) => { const ComposeAttachments: React.FC<Props> = ({ postState, postDispatch }) => {
const renderImage = useCallback(({ item, index }) => {
return (
<View key={index}>
<Image
style={[
styles.image,
{
width: (item.meta?.original?.aspect || 1) * 200
}
]}
source={{ uri: item!.preview_url }}
/>
<Feather
name='edit'
size={24}
color='white'
style={styles.buttonEdit}
/>
<Feather
name='trash-2'
size={24}
color='white'
style={styles.buttonRemove}
onPress={() =>
postDispatch({
type: 'attachments',
payload: postState.attachments.filter(e => e.id !== item.id)
})
}
/>
</View>
)
}, [])
const listFooter = useCallback(() => {
return postState.attachmentUploadProgress ? (
<View
style={{
width: postState.attachmentUploadProgress.aspect * 200,
height: 200,
flex: 1,
backgroundColor: 'gray',
marginLeft: StyleConstants.Spacing.Global.PagePadding,
marginTop: StyleConstants.Spacing.Global.PagePadding,
marginBottom: StyleConstants.Spacing.Global.PagePadding
}}
>
<ActivityIndicator />
</View>
) : null
}, [postState.attachmentUploadProgress])
return ( return (
<View style={styles.base}> <View style={styles.base}>
{postState.attachments.map((attachment, index) => ( <FlatList
<View key={index} style={styles.imageContainer}> horizontal
<Image data={postState.attachments}
style={styles.image} renderItem={renderImage}
source={{ uri: attachment.preview_url }} ListFooterComponent={listFooter}
/> />
<Feather
name='edit'
size={24}
color='white'
style={styles.buttonEdit}
/>
<Feather
name='trash-2'
size={24}
color='white'
style={styles.buttonRemove}
onPress={() =>
postDispatch({ type: 'attachments/remove', payload: attachment })
}
/>
</View>
))}
</View> </View>
) )
} }
@ -43,13 +85,14 @@ const styles = StyleSheet.create({
base: { base: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
backgroundColor: 'lightgreen' marginRight: StyleConstants.Spacing.Global.PagePadding,
}, height: 200
imageContainer: {
flexBasis: 100
}, },
image: { image: {
flex: 1 flex: 1,
marginLeft: StyleConstants.Spacing.Global.PagePadding,
marginTop: StyleConstants.Spacing.Global.PagePadding,
marginBottom: StyleConstants.Spacing.Global.PagePadding
}, },
buttonEdit: { buttonEdit: {
position: 'absolute', position: 'absolute',

View File

@ -73,7 +73,7 @@ const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => {
const textInputRef = useRef<TextInput>(null) const textInputRef = useRef<TextInput>(null)
const listFooter = useMemo(() => { const listFooter = () => {
return ( return (
<> <>
{postState.emoji.active && ( {postState.emoji.active && (
@ -86,7 +86,8 @@ const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => {
</View> </View>
)} )}
{postState.attachments.length > 0 && ( {(postState.attachments.length > 0 ||
postState.attachmentUploadProgress) && (
<View style={styles.attachments}> <View style={styles.attachments}>
<ComposeAttachments <ComposeAttachments
postState={postState} postState={postState}
@ -101,11 +102,7 @@ const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => {
)} )}
</> </>
) )
}, [ }
postState.emoji.active,
postState.attachments.length,
postState.poll.active
])
const listEmpty = useMemo(() => { const listEmpty = useMemo(() => {
if (isFetching) { if (isFetching) {
@ -215,8 +212,7 @@ const styles = StyleSheet.create({
contentView: { flex: 1 }, contentView: { flex: 1 },
attachments: { attachments: {
flex: 1, flex: 1
height: 100
}, },
poll: { poll: {
flex: 1, flex: 1,

View File

@ -1,35 +1,55 @@
import { Dispatch } from 'react' import { Dispatch } from 'react'
import { ActionSheetIOS, Alert } from 'react-native' import { ActionSheetIOS, Alert } from 'react-native'
import * as ImagePicker from 'expo-image-picker' import * as ImagePicker from 'expo-image-picker'
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
import { PostAction, PostState } from '../Compose' import { PostAction, PostState } from '../Compose'
import client from 'src/api/client' import client from 'src/api/client'
import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types'
const uploadAttachment = async (uri: ImageInfo['uri']) => { const uploadAttachment = async ({
const filename = uri.split('/').pop() result,
postState,
postDispatch
}: {
result: ImageInfo
postState: PostState
postDispatch: Dispatch<PostAction>
}) => {
const filename = result.uri.split('/').pop()
const match = /\.(\w+)$/.exec(filename!) const match = /\.(\w+)$/.exec(filename!)
const type = match ? `image/${match[1]}` : `image` const type = match ? `image/${match[1]}` : `image`
const formData = new FormData() const formData = new FormData()
formData.append('file', { uri: uri, name: filename, type: type }) // @ts-ignore
formData.append('file', { uri: result.uri, name: filename, type: type })
return client({ client({
method: 'post', method: 'post',
instance: 'local', instance: 'local',
endpoint: 'media', url: 'media',
body: formData body: formData,
onUploadProgress: p => {
postDispatch({
type: 'attachmentUploadProgress',
payload: {
progress: p.loaded / p.total,
aspect: result.width / result.height
}
})
}
}) })
.then(res => { .then(({ body }: { body: Mastodon.Attachment }) => {
if (res.body.id && res.body.type !== 'unknown') { postDispatch({
console.log('url: ' + res.body.preview_url) type: 'attachmentUploadProgress',
return Promise.resolve({ payload: undefined
id: res.body.id, })
url: res.body.url, if (body.id) {
preview_url: res.body.preview_url, postDispatch({
description: res.body.description type: 'attachments',
payload: postState.attachments.concat([body])
}) })
return Promise.resolve()
} else { } else {
Alert.alert('上传失败', '', [ Alert.alert('上传失败', '', [
{ {
@ -50,12 +70,11 @@ const uploadAttachment = async (uri: ImageInfo['uri']) => {
} }
const addAttachments = async ({ const addAttachments = async ({
postState, ...params
postDispatch
}: { }: {
postState: PostState postState: PostState
postDispatch: Dispatch<PostAction> postDispatch: Dispatch<PostAction>
}) => { }): Promise<any> => {
ActionSheetIOS.showActionSheetWithOptions( ActionSheetIOS.showActionSheetWithOptions(
{ {
options: ['从相册选取', '现照', '取消'], options: ['从相册选取', '现照', '取消'],
@ -63,19 +82,13 @@ const addAttachments = async ({
}, },
async buttonIndex => { async buttonIndex => {
if (buttonIndex === 0) { if (buttonIndex === 0) {
let result = await ImagePicker.launchImageLibraryAsync({ const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All, mediaTypes: ImagePicker.MediaTypeOptions.All,
exif: false exif: false
}) })
if (!result.cancelled) { if (!result.cancelled) {
const response = await uploadAttachment(result.uri) await uploadAttachment({ result, ...params })
if (response.id) {
postDispatch({
type: 'attachments/add',
payload: response
})
}
} }
} else if (buttonIndex === 1) { } else if (buttonIndex === 1) {
// setResult(Math.floor(Math.random() * 100) + 1) // setResult(Math.floor(Math.random() * 100) + 1)

View File

@ -4,7 +4,7 @@ export const accountFetch = async (key: string, { id }: { id: string }) => {
const res = await client({ const res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `accounts/${id}` url: `accounts/${id}`
}) })
return Promise.resolve(res.body) return Promise.resolve(res.body)
} }

View File

@ -4,7 +4,7 @@ export const emojisFetch = async () => {
const res = await client({ const res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'custom_emojis' url: 'custom_emojis'
}) })
return Promise.resolve(res.body) return Promise.resolve(res.body)
} }

View File

@ -7,8 +7,8 @@ export const instanceFetch = async (
const res = await client({ const res = await client({
method: 'get', method: 'get',
instance: 'remote', instance: 'remote',
instanceUrl: instance, instanceDomain: instance,
endpoint: `instance` url: `instance`
}) })
return Promise.resolve(res.body) return Promise.resolve(res.body)
} }

View File

@ -4,7 +4,7 @@ export const listsFetch = async () => {
const res = await client({ const res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'lists' url: 'lists'
}) })
return Promise.resolve(res.body) return Promise.resolve(res.body)
} }

View File

@ -16,8 +16,8 @@ export const searchFetch = async (
version: 'v2', version: 'v2',
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'search', url: 'search',
query: { type, q: term, limit } params: { type, q: term, limit }
}) })
return Promise.resolve(res.body) return Promise.resolve(res.body)
} }

View File

@ -6,14 +6,14 @@ export const timelineFetch = async (
key: string, key: string,
{ {
page, page,
query = {}, params = {},
account, account,
hashtag, hashtag,
list, list,
toot toot
}: { }: {
page: string page: string
query?: { params?: {
[key: string]: string | number | boolean [key: string]: string | number | boolean
} }
account?: string account?: string
@ -31,10 +31,10 @@ export const timelineFetch = async (
if (pagination && pagination.id) { if (pagination && pagination.id) {
switch (pagination.direction) { switch (pagination.direction) {
case 'prev': case 'prev':
query.min_id = pagination.id params.min_id = pagination.id
break break
case 'next': case 'next':
query.max_id = pagination.id params.max_id = pagination.id
break break
} }
} }
@ -44,18 +44,18 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'timelines/home', url: 'timelines/home',
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
case 'Local': case 'Local':
query.local = 'true' params.local = 'true'
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'timelines/public', url: 'timelines/public',
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -63,8 +63,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'timelines/public', url: 'timelines/public',
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -72,8 +72,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'remote', instance: 'remote',
endpoint: 'timelines/public', url: 'timelines/public',
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -81,8 +81,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: 'notifications', url: 'notifications',
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -90,8 +90,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `accounts/${account}/statuses`, url: `accounts/${account}/statuses`,
query: { params: {
pinned: 'true' pinned: 'true'
} }
}) })
@ -99,8 +99,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `accounts/${account}/statuses`, url: `accounts/${account}/statuses`,
query: { params: {
exclude_replies: 'true' exclude_replies: 'true'
} }
}) })
@ -111,8 +111,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `accounts/${account}/statuses`, url: `accounts/${account}/statuses`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -120,8 +120,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `accounts/${account}/statuses`, url: `accounts/${account}/statuses`,
query: { params: {
only_media: 'true' only_media: 'true'
} }
}) })
@ -131,8 +131,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `timelines/tag/${hashtag}`, url: `timelines/tag/${hashtag}`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -140,8 +140,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `conversations`, url: `conversations`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -149,8 +149,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `bookmarks`, url: `bookmarks`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -158,8 +158,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `favourites`, url: `favourites`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -167,8 +167,8 @@ export const timelineFetch = async (
res = await client({ res = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `timelines/list/${list}`, url: `timelines/list/${list}`,
query params
}) })
return Promise.resolve({ toots: res.body, pointer: null }) return Promise.resolve({ toots: res.body, pointer: null })
@ -176,12 +176,12 @@ export const timelineFetch = async (
const current = await client({ const current = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `statuses/${toot}` url: `statuses/${toot}`
}) })
const context = await client({ const context = await client({
method: 'get', method: 'get',
instance: 'local', instance: 'local',
endpoint: `statuses/${toot}/context` url: `statuses/${toot}/context`
}) })
return Promise.resolve({ return Promise.resolve({
toots: [ toots: [

View File

@ -50,16 +50,16 @@ export const updateLocal = createAsyncThunk(
} = await client({ } = await client({
method: 'get', method: 'get',
instance: 'remote', instance: 'remote',
instanceUrl: url, instanceDomain: url,
endpoint: `accounts/verify_credentials`, url: `accounts/verify_credentials`,
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
const { body: preferences } = await client({ const { body: preferences } = await client({
method: 'get', method: 'get',
instance: 'remote', instance: 'remote',
instanceUrl: url, instanceDomain: url,
endpoint: `preferences`, url: `preferences`,
headers: { Authorization: `Bearer ${token}` } headers: { Authorization: `Bearer ${token}` }
}) })
@ -91,14 +91,11 @@ const instancesSlice = createSlice({
}) })
export const getLocalUrl = (state: RootState) => state.instances.local.url export const getLocalUrl = (state: RootState) => state.instances.local.url
export const getLocalToken = (state: RootState) => state.instances.local.token
export const getRemoteUrl = (state: RootState) => state.instances.remote.url export const getRemoteUrl = (state: RootState) => state.instances.remote.url
export const getLocalAccountId = (state: RootState) => export const getLocalAccountId = (state: RootState) =>
state.instances.local.account.id state.instances.local.account.id
export const getLocalAccountPreferences = (state: RootState) => export const getLocalAccountPreferences = (state: RootState) =>
state.instances.local.account.preferences state.instances.local.account.preferences
// export const {
// updateLocalInstance,
// updateLocalAccount
// } = instancesSlice.actions
export default instancesSlice.reducer export default instancesSlice.reducer

View File

@ -1740,6 +1740,13 @@ available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2:
dependencies: dependencies:
array-filter "^1.0.0" array-filter "^1.0.0"
axios@^0.21.0:
version "0.21.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca"
integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw==
dependencies:
follow-redirects "^1.10.0"
babel-plugin-dynamic-import-node@^2.3.3: babel-plugin-dynamic-import-node@^2.3.3:
version "2.3.3" version "2.3.3"
resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
@ -3060,6 +3067,11 @@ find-up@^4.1.0:
locate-path "^5.0.0" locate-path "^5.0.0"
path-exists "^4.0.0" path-exists "^4.0.0"
follow-redirects@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
fontfaceobserver@^2.1.0: fontfaceobserver@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991" resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991"