mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Basic attachment done
Switch from ky to axios
This commit is contained in:
		| @@ -14,6 +14,7 @@ | ||||
|     "@react-navigation/bottom-tabs": "^5.10.6", | ||||
|     "@react-navigation/native": "^5.8.6", | ||||
|     "@reduxjs/toolkit": "^1.4.0", | ||||
|     "axios": "^0.21.0", | ||||
|     "expo": "~39.0.4", | ||||
|     "expo-auth-session": "~2.0.0", | ||||
|     "expo-av": "~8.6.0", | ||||
| @@ -25,7 +26,6 @@ | ||||
|     "expo-splash-screen": "~0.6.1", | ||||
|     "expo-status-bar": "~1.0.2", | ||||
|     "i18next": "^19.8.4", | ||||
|     "ky": "^0.24.0", | ||||
|     "lodash": "^4.17.20", | ||||
|     "react": "16.13.1", | ||||
|     "react-dom": "16.13.1", | ||||
|   | ||||
| @@ -1,37 +1,38 @@ | ||||
| import axios from 'axios' | ||||
| import { store, RootState } from 'src/store' | ||||
| import ky from 'ky' | ||||
|  | ||||
| const client = async ({ | ||||
|   version = 'v1', | ||||
|   method, | ||||
|   instance, | ||||
|   instanceUrl, | ||||
|   endpoint, | ||||
|   instanceDomain, | ||||
|   version = 'v1', | ||||
|   url, | ||||
|   params, | ||||
|   headers, | ||||
|   query, | ||||
|   body | ||||
|   body, | ||||
|   onUploadProgress | ||||
| }: { | ||||
|   version?: 'v1' | 'v2' | ||||
|   method: 'get' | 'post' | 'put' | 'delete' | ||||
|   instance: 'local' | 'remote' | ||||
|   instanceUrl?: string | ||||
|   endpoint: string | ||||
|   headers?: { [key: string]: string } | ||||
|   query?: { | ||||
|   instanceDomain?: string | ||||
|   version?: 'v1' | 'v2' | ||||
|   url: string | ||||
|   params?: { | ||||
|     [key: string]: string | number | boolean | ||||
|   } | ||||
|   headers?: { [key: string]: string } | ||||
|   body?: FormData | ||||
|   onUploadProgress?: (progressEvent: any) => void | ||||
| }): Promise<any> => { | ||||
|   const state: RootState['instances'] = store.getState().instances | ||||
|   const url = | ||||
|     instance === 'remote' ? instanceUrl || state.remote.url : state.local.url | ||||
|   const domain = | ||||
|     instance === 'remote' ? instanceDomain || state.remote.url : state.local.url | ||||
|  | ||||
|   let response | ||||
|   // try { | ||||
|   response = await ky(endpoint, { | ||||
|     method: method, | ||||
|     prefixUrl: `https://${url}/api/${version}`, | ||||
|     searchParams: query, | ||||
|   return axios({ | ||||
|     method, | ||||
|     baseURL: `https://${domain}/api/${version}/`, | ||||
|     url, | ||||
|     params, | ||||
|     headers: { | ||||
|       'Content-Type': 'application/json', | ||||
|       ...headers, | ||||
| @@ -39,28 +40,35 @@ const client = async ({ | ||||
|         Authorization: `Bearer ${state.local.token}` | ||||
|       }) | ||||
|     }, | ||||
|     ...(body && { body: body }), | ||||
|     throwHttpErrors: false | ||||
|     ...(body && { data: body }), | ||||
|     ...(onUploadProgress && { onUploadProgress: onUploadProgress }) | ||||
|   }) | ||||
|   // } catch (error) { | ||||
|   //   return Promise.reject('ky error: ' + error.json()) | ||||
|   // } | ||||
|   console.log('Query: /' + endpoint) | ||||
|   if (response.ok) { | ||||
|     return Promise.resolve({ | ||||
|     .then(response => | ||||
|       Promise.resolve({ | ||||
|         headers: response.headers, | ||||
|       body: await response.json() | ||||
|         body: response.data | ||||
|       }) | ||||
|     ) | ||||
|     .catch(error => { | ||||
|       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 { | ||||
|     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 }) | ||||
|         console.error('axios error', error.message) | ||||
|         return Promise.reject({ body: error.message }) | ||||
|       } | ||||
|     }) | ||||
| } | ||||
|  | ||||
| export default client | ||||
|   | ||||
| @@ -27,7 +27,7 @@ const fireMutation = async ({ | ||||
|       res = await client({ | ||||
|         method: 'post', | ||||
|         instance: 'local', | ||||
|         endpoint: `statuses/${id}/${prevState ? 'un' : ''}${type}` | ||||
|         url: `statuses/${id}/${prevState ? 'un' : ''}${type}` | ||||
|       }) // bug in response from Mastodon | ||||
|  | ||||
|       if (!res.body[stateKey] === prevState) { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ const fireMutation = async ({ | ||||
|       res = await client({ | ||||
|         method: 'post', | ||||
|         instance: 'local', | ||||
|         endpoint: `accounts/${id}/${type}` | ||||
|         url: `accounts/${id}/${type}` | ||||
|       }) | ||||
|  | ||||
|       if (res.body[stateKey!] === true) { | ||||
| @@ -35,8 +35,8 @@ const fireMutation = async ({ | ||||
|       res = await client({ | ||||
|         method: 'post', | ||||
|         instance: 'local', | ||||
|         endpoint: `reports`, | ||||
|         query: { | ||||
|         url: `reports`, | ||||
|         params: { | ||||
|           account_id: id! | ||||
|         } | ||||
|       }) | ||||
|   | ||||
| @@ -10,8 +10,8 @@ const fireMutation = async ({ domain }: { domain: string }) => { | ||||
|   const res = await client({ | ||||
|     method: 'post', | ||||
|     instance: 'local', | ||||
|     endpoint: `domain_blocks`, | ||||
|     query: { | ||||
|     url: `domain_blocks`, | ||||
|     params: { | ||||
|       domain: domain! | ||||
|     } | ||||
|   }) | ||||
|   | ||||
| @@ -22,7 +22,7 @@ const fireMutation = async ({ | ||||
|       res = await client({ | ||||
|         method: 'post', | ||||
|         instance: 'local', | ||||
|         endpoint: `statuses/${id}/${prevState ? 'un' : ''}${type}` | ||||
|         url: `statuses/${id}/${prevState ? 'un' : ''}${type}` | ||||
|       }) // bug in response from Mastodon | ||||
|  | ||||
|       if (!res.body[stateKey] === prevState) { | ||||
| @@ -37,7 +37,7 @@ const fireMutation = async ({ | ||||
|       res = await client({ | ||||
|         method: 'delete', | ||||
|         instance: 'local', | ||||
|         endpoint: `statuses/${id}` | ||||
|         url: `statuses/${id}` | ||||
|       }) | ||||
|  | ||||
|       if (res.body[stateKey] === id) { | ||||
|   | ||||
| @@ -29,7 +29,7 @@ const fireMutation = async ({ | ||||
|   const res = await client({ | ||||
|     method: 'post', | ||||
|     instance: 'local', | ||||
|     endpoint: `polls/${id}/votes`, | ||||
|     url: `polls/${id}/votes`, | ||||
|     body: formData | ||||
|   }) | ||||
|  | ||||
|   | ||||
| @@ -62,8 +62,8 @@ const Login: React.FC = () => { | ||||
|     const res = await client({ | ||||
|       method: 'post', | ||||
|       instance: 'remote', | ||||
|       instanceUrl: instance, | ||||
|       endpoint: `apps`, | ||||
|       instanceDomain: instance, | ||||
|       url: `apps`, | ||||
|       body: formData | ||||
|     }) | ||||
|     if (res.body?.client_id.length > 0) { | ||||
|   | ||||
| @@ -34,11 +34,10 @@ export type PostState = { | ||||
|     active: boolean | ||||
|     total: number | ||||
|     options: { | ||||
|       '1': string | ||||
|       '2': string | ||||
|       '3': string | ||||
|       '4': string | ||||
|       [key: string]: string | ||||
|       '1': string | undefined | ||||
|       '2': string | undefined | ||||
|       '3': string | undefined | ||||
|       '4': string | undefined | ||||
|     } | ||||
|     multiple: boolean | ||||
|     expire: | ||||
| @@ -51,12 +50,8 @@ export type PostState = { | ||||
|       | '604800' | ||||
|       | string | ||||
|   } | ||||
|   attachments: { | ||||
|     id: string | ||||
|     url: string | ||||
|     preview_url: string | ||||
|     description: string | ||||
|   }[] | ||||
|   attachments: Mastodon.Attachment[] | ||||
|   attachmentUploadProgress: { progress: number; aspect: number } | undefined | ||||
|   visibility: 'public' | 'unlisted' | 'private' | 'direct' | ||||
| } | ||||
|  | ||||
| @@ -82,19 +77,12 @@ export type PostAction = | ||||
|       payload: PostState['poll'] | ||||
|     } | ||||
|   | { | ||||
|       type: 'attachments/add' | ||||
|       payload: { | ||||
|         id: string | ||||
|         url: string | ||||
|         preview_url: string | ||||
|         description: string | ||||
|       } | ||||
|       type: 'attachments' | ||||
|       payload: PostState['attachments'] | ||||
|     } | ||||
|   | { | ||||
|       type: 'attachments/remove' | ||||
|       payload: { | ||||
|         id: string | ||||
|       } | ||||
|       type: 'attachmentUploadProgress' | ||||
|       payload: PostState['attachmentUploadProgress'] | ||||
|     } | ||||
|   | { | ||||
|       type: 'visibility' | ||||
| @@ -114,15 +102,16 @@ const postInitialState: PostState = { | ||||
|     active: false, | ||||
|     total: 2, | ||||
|     options: { | ||||
|       '1': '', | ||||
|       '2': '', | ||||
|       '3': '', | ||||
|       '4': '' | ||||
|       '1': undefined, | ||||
|       '2': undefined, | ||||
|       '3': undefined, | ||||
|       '4': undefined | ||||
|     }, | ||||
|     multiple: false, | ||||
|     expire: '86400' | ||||
|   }, | ||||
|   attachments: [], | ||||
|   attachmentUploadProgress: undefined, | ||||
|   visibility: | ||||
|     getLocalAccountPreferences(store.getState())[ | ||||
|       'posting:default:visibility' | ||||
| @@ -140,13 +129,10 @@ const postReducer = (state: PostState, action: PostAction): PostState => { | ||||
|       return { ...state, emoji: action.payload } | ||||
|     case 'poll': | ||||
|       return { ...state, poll: action.payload } | ||||
|     case 'attachments/add': | ||||
|       return { ...state, attachments: state.attachments.concat(action.payload) } | ||||
|     case 'attachments/remove': | ||||
|       return { | ||||
|         ...state, | ||||
|         attachments: state.attachments.filter(a => a.id !== action.payload.id) | ||||
|       } | ||||
|     case 'attachments': | ||||
|       return { ...state, attachments: action.payload } | ||||
|     case 'attachmentUploadProgress': | ||||
|       return { ...state, attachmentUploadProgress: action.payload } | ||||
|     case 'visibility': | ||||
|       return { ...state, visibility: action.payload } | ||||
|     default: | ||||
| @@ -186,27 +172,29 @@ const Compose: React.FC = () => { | ||||
|       ]) | ||||
|     } else { | ||||
|       const formData = new FormData() | ||||
|  | ||||
|       formData.append('status', postState.text.raw) | ||||
|  | ||||
|       if (postState.poll.active) { | ||||
|         Object.values(postState.poll.options) | ||||
|           .filter(e => e.length) | ||||
|           .forEach(e => { | ||||
|             formData.append('poll[options][]', e) | ||||
|           }) | ||||
|           .filter(e => e?.length) | ||||
|           .forEach(e => formData.append('poll[options][]', e!)) | ||||
|         formData.append('poll[expires_in]', postState.poll.expire) | ||||
|         formData.append('poll[multiple]', postState.poll.multiple.toString()) | ||||
|       } | ||||
|       if (postState.attachments.length > 0) { | ||||
|         postState.attachments.forEach(attachment => | ||||
|           formData.append('media_ids[]', attachment.id) | ||||
|  | ||||
|       if (postState.attachments.length) { | ||||
|         postState.attachments.forEach(e => | ||||
|           formData.append('media_ids[]', e!.id) | ||||
|         ) | ||||
|       } | ||||
|  | ||||
|       formData.append('visibility', postState.visibility) | ||||
|  | ||||
|       client({ | ||||
|         method: 'post', | ||||
|         instance: 'local', | ||||
|         endpoint: 'statuses', | ||||
|         url: 'statuses', | ||||
|         headers: { | ||||
|           'Idempotency-Key': Date.now().toString() + Math.random().toString() | ||||
|         }, | ||||
|   | ||||
| @@ -8,6 +8,8 @@ import { | ||||
|   Text, | ||||
|   TextInput | ||||
| } from 'react-native' | ||||
| import { useSelector } from 'react-redux' | ||||
| import { getLocalToken, getLocalUrl } from 'src/utils/slices/instancesSlice' | ||||
| import { StyleConstants } from 'src/utils/styles/constants' | ||||
| import { useTheme } from 'src/utils/styles/ThemeManager' | ||||
| import { PostAction, PostState } from '../Compose' | ||||
| @@ -25,6 +27,8 @@ const ComposeActions: React.FC<Props> = ({ | ||||
|   postDispatch | ||||
| }) => { | ||||
|   const { theme } = useTheme() | ||||
|   const localUrl = useSelector(getLocalUrl) | ||||
|   const localToken = useSelector(getLocalToken) | ||||
|  | ||||
|   const getVisibilityIcon = () => { | ||||
|     switch (postState.visibility) { | ||||
| @@ -50,20 +54,30 @@ const ComposeActions: React.FC<Props> = ({ | ||||
|       <Feather | ||||
|         name='aperture' | ||||
|         size={24} | ||||
|         color={postState.poll.active ? theme.secondary : theme.primary} | ||||
|         onPress={async () => | ||||
|           !postState.poll.active && | ||||
|           (await addAttachments({ postState, postDispatch })) | ||||
|         color={ | ||||
|           postState.poll.active || postState.attachments.length >= 4 | ||||
|             ? theme.secondary | ||||
|             : theme.primary | ||||
|         } | ||||
|         onPress={async () => { | ||||
|           if (!postState.poll.active && postState.attachments.length < 4) { | ||||
|             await addAttachments({ postState, postDispatch }) | ||||
|           } | ||||
|         }} | ||||
|       /> | ||||
|       <Feather | ||||
|         name='bar-chart-2' | ||||
|         size={24} | ||||
|         color={ | ||||
|           postState.attachments.length > 0 ? theme.secondary : theme.primary | ||||
|           postState.attachments.length || postState.attachmentUploadProgress | ||||
|             ? theme.secondary | ||||
|             : theme.primary | ||||
|         } | ||||
|         onPress={() => { | ||||
|           if (postState.attachments.length === 0) { | ||||
|           if ( | ||||
|             !postState.attachments.length && | ||||
|             !postState.attachmentUploadProgress | ||||
|           ) { | ||||
|             postDispatch({ | ||||
|               type: 'poll', | ||||
|               payload: { ...postState.poll, active: !postState.poll.active } | ||||
|   | ||||
| @@ -1,8 +1,15 @@ | ||||
| import React, { Dispatch } from 'react' | ||||
| import { Image, StyleSheet, View } from 'react-native' | ||||
| import React, { Dispatch, useCallback } from 'react' | ||||
| import { | ||||
|   ActivityIndicator, | ||||
|   FlatList, | ||||
|   Image, | ||||
|   StyleSheet, | ||||
|   View | ||||
| } from 'react-native' | ||||
| import { Feather } from '@expo/vector-icons' | ||||
|  | ||||
| import { PostAction, PostState } from '../Compose' | ||||
| import { StyleConstants } from 'src/utils/styles/constants' | ||||
|  | ||||
| export interface Props { | ||||
|   postState: PostState | ||||
| @@ -10,13 +17,17 @@ export interface Props { | ||||
| } | ||||
|  | ||||
| const ComposeAttachments: React.FC<Props> = ({ postState, postDispatch }) => { | ||||
|   const renderImage = useCallback(({ item, index }) => { | ||||
|     return ( | ||||
|     <View style={styles.base}> | ||||
|       {postState.attachments.map((attachment, index) => ( | ||||
|         <View key={index} style={styles.imageContainer}> | ||||
|       <View key={index}> | ||||
|         <Image | ||||
|             style={styles.image} | ||||
|             source={{ uri: attachment.preview_url }} | ||||
|           style={[ | ||||
|             styles.image, | ||||
|             { | ||||
|               width: (item.meta?.original?.aspect || 1) * 200 | ||||
|             } | ||||
|           ]} | ||||
|           source={{ uri: item!.preview_url }} | ||||
|         /> | ||||
|         <Feather | ||||
|           name='edit' | ||||
| @@ -30,11 +41,42 @@ const ComposeAttachments: React.FC<Props> = ({ postState, postDispatch }) => { | ||||
|           color='white' | ||||
|           style={styles.buttonRemove} | ||||
|           onPress={() => | ||||
|               postDispatch({ type: 'attachments/remove', payload: attachment }) | ||||
|             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 ( | ||||
|     <View style={styles.base}> | ||||
|       <FlatList | ||||
|         horizontal | ||||
|         data={postState.attachments} | ||||
|         renderItem={renderImage} | ||||
|         ListFooterComponent={listFooter} | ||||
|       /> | ||||
|     </View> | ||||
|   ) | ||||
| } | ||||
| @@ -43,13 +85,14 @@ const styles = StyleSheet.create({ | ||||
|   base: { | ||||
|     flex: 1, | ||||
|     flexDirection: 'row', | ||||
|     backgroundColor: 'lightgreen' | ||||
|   }, | ||||
|   imageContainer: { | ||||
|     flexBasis: 100 | ||||
|     marginRight: StyleConstants.Spacing.Global.PagePadding, | ||||
|     height: 200 | ||||
|   }, | ||||
|   image: { | ||||
|     flex: 1 | ||||
|     flex: 1, | ||||
|     marginLeft: StyleConstants.Spacing.Global.PagePadding, | ||||
|     marginTop: StyleConstants.Spacing.Global.PagePadding, | ||||
|     marginBottom: StyleConstants.Spacing.Global.PagePadding | ||||
|   }, | ||||
|   buttonEdit: { | ||||
|     position: 'absolute', | ||||
|   | ||||
| @@ -73,7 +73,7 @@ const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => { | ||||
|  | ||||
|   const textInputRef = useRef<TextInput>(null) | ||||
|  | ||||
|   const listFooter = useMemo(() => { | ||||
|   const listFooter = () => { | ||||
|     return ( | ||||
|       <> | ||||
|         {postState.emoji.active && ( | ||||
| @@ -86,7 +86,8 @@ const ComposeRoot: React.FC<Props> = ({ postState, postDispatch }) => { | ||||
|           </View> | ||||
|         )} | ||||
|  | ||||
|         {postState.attachments.length > 0 && ( | ||||
|         {(postState.attachments.length > 0 || | ||||
|           postState.attachmentUploadProgress) && ( | ||||
|           <View style={styles.attachments}> | ||||
|             <ComposeAttachments | ||||
|               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(() => { | ||||
|     if (isFetching) { | ||||
| @@ -215,8 +212,7 @@ const styles = StyleSheet.create({ | ||||
|   contentView: { flex: 1 }, | ||||
|  | ||||
|   attachments: { | ||||
|     flex: 1, | ||||
|     height: 100 | ||||
|     flex: 1 | ||||
|   }, | ||||
|   poll: { | ||||
|     flex: 1, | ||||
|   | ||||
| @@ -1,35 +1,55 @@ | ||||
| import { Dispatch } from 'react' | ||||
| import { ActionSheetIOS, Alert } from 'react-native' | ||||
| import * as ImagePicker from 'expo-image-picker' | ||||
| import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types' | ||||
|  | ||||
| import { PostAction, PostState } from '../Compose' | ||||
| import client from 'src/api/client' | ||||
| import { ImageInfo } from 'expo-image-picker/build/ImagePicker.types' | ||||
|  | ||||
| const uploadAttachment = async (uri: ImageInfo['uri']) => { | ||||
|   const filename = uri.split('/').pop() | ||||
| const uploadAttachment = async ({ | ||||
|   result, | ||||
|   postState, | ||||
|   postDispatch | ||||
| }: { | ||||
|   result: ImageInfo | ||||
|   postState: PostState | ||||
|   postDispatch: Dispatch<PostAction> | ||||
| }) => { | ||||
|   const filename = result.uri.split('/').pop() | ||||
|  | ||||
|   const match = /\.(\w+)$/.exec(filename!) | ||||
|   const type = match ? `image/${match[1]}` : `image` | ||||
|  | ||||
|   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', | ||||
|     instance: 'local', | ||||
|     endpoint: 'media', | ||||
|     body: formData | ||||
|     url: 'media', | ||||
|     body: formData, | ||||
|     onUploadProgress: p => { | ||||
|       postDispatch({ | ||||
|         type: 'attachmentUploadProgress', | ||||
|         payload: { | ||||
|           progress: p.loaded / p.total, | ||||
|           aspect: result.width / result.height | ||||
|         } | ||||
|       }) | ||||
|     .then(res => { | ||||
|       if (res.body.id && res.body.type !== 'unknown') { | ||||
|         console.log('url: ' + res.body.preview_url) | ||||
|         return Promise.resolve({ | ||||
|           id: res.body.id, | ||||
|           url: res.body.url, | ||||
|           preview_url: res.body.preview_url, | ||||
|           description: res.body.description | ||||
|     } | ||||
|   }) | ||||
|     .then(({ body }: { body: Mastodon.Attachment }) => { | ||||
|       postDispatch({ | ||||
|         type: 'attachmentUploadProgress', | ||||
|         payload: undefined | ||||
|       }) | ||||
|       if (body.id) { | ||||
|         postDispatch({ | ||||
|           type: 'attachments', | ||||
|           payload: postState.attachments.concat([body]) | ||||
|         }) | ||||
|         return Promise.resolve() | ||||
|       } else { | ||||
|         Alert.alert('上传失败', '', [ | ||||
|           { | ||||
| @@ -50,12 +70,11 @@ const uploadAttachment = async (uri: ImageInfo['uri']) => { | ||||
| } | ||||
|  | ||||
| const addAttachments = async ({ | ||||
|   postState, | ||||
|   postDispatch | ||||
|   ...params | ||||
| }: { | ||||
|   postState: PostState | ||||
|   postDispatch: Dispatch<PostAction> | ||||
| }) => { | ||||
| }): Promise<any> => { | ||||
|   ActionSheetIOS.showActionSheetWithOptions( | ||||
|     { | ||||
|       options: ['从相册选取', '现照', '取消'], | ||||
| @@ -63,19 +82,13 @@ const addAttachments = async ({ | ||||
|     }, | ||||
|     async buttonIndex => { | ||||
|       if (buttonIndex === 0) { | ||||
|         let result = await ImagePicker.launchImageLibraryAsync({ | ||||
|         const result = await ImagePicker.launchImageLibraryAsync({ | ||||
|           mediaTypes: ImagePicker.MediaTypeOptions.All, | ||||
|           exif: false | ||||
|         }) | ||||
|  | ||||
|         if (!result.cancelled) { | ||||
|           const response = await uploadAttachment(result.uri) | ||||
|           if (response.id) { | ||||
|             postDispatch({ | ||||
|               type: 'attachments/add', | ||||
|               payload: response | ||||
|             }) | ||||
|           } | ||||
|           await uploadAttachment({ result, ...params }) | ||||
|         } | ||||
|       } else if (buttonIndex === 1) { | ||||
|         // setResult(Math.floor(Math.random() * 100) + 1) | ||||
|   | ||||
| @@ -4,7 +4,7 @@ export const accountFetch = async (key: string, { id }: { id: string }) => { | ||||
|   const res = await client({ | ||||
|     method: 'get', | ||||
|     instance: 'local', | ||||
|     endpoint: `accounts/${id}` | ||||
|     url: `accounts/${id}` | ||||
|   }) | ||||
|   return Promise.resolve(res.body) | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ export const emojisFetch = async () => { | ||||
|   const res = await client({ | ||||
|     method: 'get', | ||||
|     instance: 'local', | ||||
|     endpoint: 'custom_emojis' | ||||
|     url: 'custom_emojis' | ||||
|   }) | ||||
|   return Promise.resolve(res.body) | ||||
| } | ||||
|   | ||||
| @@ -7,8 +7,8 @@ export const instanceFetch = async ( | ||||
|   const res = await client({ | ||||
|     method: 'get', | ||||
|     instance: 'remote', | ||||
|     instanceUrl: instance, | ||||
|     endpoint: `instance` | ||||
|     instanceDomain: instance, | ||||
|     url: `instance` | ||||
|   }) | ||||
|   return Promise.resolve(res.body) | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ export const listsFetch = async () => { | ||||
|   const res = await client({ | ||||
|     method: 'get', | ||||
|     instance: 'local', | ||||
|     endpoint: 'lists' | ||||
|     url: 'lists' | ||||
|   }) | ||||
|   return Promise.resolve(res.body) | ||||
| } | ||||
|   | ||||
| @@ -16,8 +16,8 @@ export const searchFetch = async ( | ||||
|     version: 'v2', | ||||
|     method: 'get', | ||||
|     instance: 'local', | ||||
|     endpoint: 'search', | ||||
|     query: { type, q: term, limit } | ||||
|     url: 'search', | ||||
|     params: { type, q: term, limit } | ||||
|   }) | ||||
|   return Promise.resolve(res.body) | ||||
| } | ||||
|   | ||||
| @@ -6,14 +6,14 @@ export const timelineFetch = async ( | ||||
|   key: string, | ||||
|   { | ||||
|     page, | ||||
|     query = {}, | ||||
|     params = {}, | ||||
|     account, | ||||
|     hashtag, | ||||
|     list, | ||||
|     toot | ||||
|   }: { | ||||
|     page: string | ||||
|     query?: { | ||||
|     params?: { | ||||
|       [key: string]: string | number | boolean | ||||
|     } | ||||
|     account?: string | ||||
| @@ -31,10 +31,10 @@ export const timelineFetch = async ( | ||||
|   if (pagination && pagination.id) { | ||||
|     switch (pagination.direction) { | ||||
|       case 'prev': | ||||
|         query.min_id = pagination.id | ||||
|         params.min_id = pagination.id | ||||
|         break | ||||
|       case 'next': | ||||
|         query.max_id = pagination.id | ||||
|         params.max_id = pagination.id | ||||
|         break | ||||
|     } | ||||
|   } | ||||
| @@ -44,18 +44,18 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: 'timelines/home', | ||||
|         query | ||||
|         url: 'timelines/home', | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
|     case 'Local': | ||||
|       query.local = 'true' | ||||
|       params.local = 'true' | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: 'timelines/public', | ||||
|         query | ||||
|         url: 'timelines/public', | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -63,8 +63,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: 'timelines/public', | ||||
|         query | ||||
|         url: 'timelines/public', | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -72,8 +72,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'remote', | ||||
|         endpoint: 'timelines/public', | ||||
|         query | ||||
|         url: 'timelines/public', | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -81,8 +81,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: 'notifications', | ||||
|         query | ||||
|         url: 'notifications', | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -90,8 +90,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `accounts/${account}/statuses`, | ||||
|         query: { | ||||
|         url: `accounts/${account}/statuses`, | ||||
|         params: { | ||||
|           pinned: 'true' | ||||
|         } | ||||
|       }) | ||||
| @@ -99,8 +99,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `accounts/${account}/statuses`, | ||||
|         query: { | ||||
|         url: `accounts/${account}/statuses`, | ||||
|         params: { | ||||
|           exclude_replies: 'true' | ||||
|         } | ||||
|       }) | ||||
| @@ -111,8 +111,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `accounts/${account}/statuses`, | ||||
|         query | ||||
|         url: `accounts/${account}/statuses`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -120,8 +120,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `accounts/${account}/statuses`, | ||||
|         query: { | ||||
|         url: `accounts/${account}/statuses`, | ||||
|         params: { | ||||
|           only_media: 'true' | ||||
|         } | ||||
|       }) | ||||
| @@ -131,8 +131,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `timelines/tag/${hashtag}`, | ||||
|         query | ||||
|         url: `timelines/tag/${hashtag}`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -140,8 +140,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `conversations`, | ||||
|         query | ||||
|         url: `conversations`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -149,8 +149,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `bookmarks`, | ||||
|         query | ||||
|         url: `bookmarks`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -158,8 +158,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `favourites`, | ||||
|         query | ||||
|         url: `favourites`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -167,8 +167,8 @@ export const timelineFetch = async ( | ||||
|       res = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `timelines/list/${list}`, | ||||
|         query | ||||
|         url: `timelines/list/${list}`, | ||||
|         params | ||||
|       }) | ||||
|       return Promise.resolve({ toots: res.body, pointer: null }) | ||||
|  | ||||
| @@ -176,12 +176,12 @@ export const timelineFetch = async ( | ||||
|       const current = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `statuses/${toot}` | ||||
|         url: `statuses/${toot}` | ||||
|       }) | ||||
|       const context = await client({ | ||||
|         method: 'get', | ||||
|         instance: 'local', | ||||
|         endpoint: `statuses/${toot}/context` | ||||
|         url: `statuses/${toot}/context` | ||||
|       }) | ||||
|       return Promise.resolve({ | ||||
|         toots: [ | ||||
|   | ||||
| @@ -50,16 +50,16 @@ export const updateLocal = createAsyncThunk( | ||||
|     } = await client({ | ||||
|       method: 'get', | ||||
|       instance: 'remote', | ||||
|       instanceUrl: url, | ||||
|       endpoint: `accounts/verify_credentials`, | ||||
|       instanceDomain: url, | ||||
|       url: `accounts/verify_credentials`, | ||||
|       headers: { Authorization: `Bearer ${token}` } | ||||
|     }) | ||||
|  | ||||
|     const { body: preferences } = await client({ | ||||
|       method: 'get', | ||||
|       instance: 'remote', | ||||
|       instanceUrl: url, | ||||
|       endpoint: `preferences`, | ||||
|       instanceDomain: url, | ||||
|       url: `preferences`, | ||||
|       headers: { Authorization: `Bearer ${token}` } | ||||
|     }) | ||||
|  | ||||
| @@ -91,14 +91,11 @@ const instancesSlice = createSlice({ | ||||
| }) | ||||
|  | ||||
| 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 getLocalAccountId = (state: RootState) => | ||||
|   state.instances.local.account.id | ||||
| export const getLocalAccountPreferences = (state: RootState) => | ||||
|   state.instances.local.account.preferences | ||||
|  | ||||
| // export const { | ||||
| //   updateLocalInstance, | ||||
| //   updateLocalAccount | ||||
| // } = instancesSlice.actions | ||||
| export default instancesSlice.reducer | ||||
|   | ||||
							
								
								
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -1740,6 +1740,13 @@ available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: | ||||
|   dependencies: | ||||
|     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: | ||||
|   version "2.3.3" | ||||
|   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" | ||||
|     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: | ||||
|   version "2.1.0" | ||||
|   resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user