mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Try out connect
This commit is contained in:
		
							
								
								
									
										33
									
								
								src/App.tsx
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								src/App.tsx
									
									
									
									
									
								
							| @@ -2,6 +2,7 @@ import { ActionSheetProvider } from '@expo/react-native-action-sheet' | ||||
| import * as Sentry from '@sentry/react-native' | ||||
| import { QueryClientProvider } from '@tanstack/react-query' | ||||
| import AccessibilityManager from '@utils/accessibility/AccessibilityManager' | ||||
| import { connectVerify } from '@utils/api/helpers/connect' | ||||
| import getLanguage from '@utils/helpers/getLanguage' | ||||
| import { queryClient } from '@utils/queryHooks' | ||||
| import audio from '@utils/startup/audio' | ||||
| @@ -50,20 +51,28 @@ const App: React.FC = () => { | ||||
|           await migrateFromAsyncStorage() | ||||
|           setHasMigrated(true) | ||||
|         } catch {} | ||||
|       } | ||||
|  | ||||
|       const useConnect = getGlobalStorage.boolean('app.connect') | ||||
|       log('log', 'App', `connect: ${useConnect}`) | ||||
|       if (useConnect) { | ||||
|         await connectVerify() | ||||
|           .then(() => log('log', 'App', 'connected')) | ||||
|           .catch(() => log('warn', 'App', 'connect verify failed')) | ||||
|       } | ||||
|  | ||||
|       log('log', 'App', 'loading from MMKV') | ||||
|       const account = getGlobalStorage.string('account.active') | ||||
|       if (account) { | ||||
|         await setAccount(account) | ||||
|       } else { | ||||
|         log('log', 'App', 'loading from MMKV') | ||||
|         const account = getGlobalStorage.string('account.active') | ||||
|         if (account) { | ||||
|           await setAccount(account) | ||||
|         log('log', 'App', 'No active account available') | ||||
|         const accounts = getGlobalStorage.object('accounts') | ||||
|         if (accounts?.length) { | ||||
|           log('log', 'App', `Setting active account ${accounts[accounts.length - 1]}`) | ||||
|           await setAccount(accounts[accounts.length - 1]) | ||||
|         } else { | ||||
|           log('log', 'App', 'No active account available') | ||||
|           const accounts = getGlobalStorage.object('accounts') | ||||
|           if (accounts?.length) { | ||||
|             log('log', 'App', `Setting active account ${accounts[accounts.length - 1]}`) | ||||
|             await setAccount(accounts[accounts.length - 1]) | ||||
|           } else { | ||||
|             setGlobalStorage('account.active', undefined) | ||||
|           } | ||||
|           setGlobalStorage('account.active', undefined) | ||||
|         } | ||||
|       } | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import { emojis } from '@components/Emojis' | ||||
| import Icon from '@components/Icon' | ||||
| import CustomText from '@components/Text' | ||||
| import { useAccessibility } from '@utils/accessibility/AccessibilityManager' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import { StorageAccount } from '@utils/storage/account' | ||||
| import { getAccountStorage, setAccountStorage } from '@utils/storage/actions' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| @@ -133,7 +134,7 @@ const EmojisList = () => { | ||||
|                   emoji: emoji.shortcode | ||||
|                 })} | ||||
|                 accessibilityHint={t('screenCompose:content.root.footer.emojis.accessibilityHint')} | ||||
|                 source={{ uri }} | ||||
|                 source={connectImage({ uri })} | ||||
|                 style={{ width: 32, height: 32 }} | ||||
|               /> | ||||
|             </Pressable> | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { useAccessibility } from '@utils/accessibility/AccessibilityManager' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import React, { useEffect, useState } from 'react' | ||||
| import { | ||||
| @@ -56,7 +57,7 @@ const GracefullyImage = ({ | ||||
|   const [imageLoaded, setImageLoaded] = useState(false) | ||||
|  | ||||
|   const [currentUri, setCurrentUri] = useState<string | undefined>(uri.original || uri.remote) | ||||
|   const source = { | ||||
|   const source: { uri?: string } = { | ||||
|     uri: reduceMotionEnabled && uri.static ? uri.static : currentUri | ||||
|   } | ||||
|   useEffect(() => { | ||||
| @@ -90,12 +91,12 @@ const GracefullyImage = ({ | ||||
|     > | ||||
|       {uri.preview && !imageLoaded ? ( | ||||
|         <FastImage | ||||
|           source={{ uri: uri.preview }} | ||||
|           source={connectImage({ uri: uri.preview })} | ||||
|           style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]} | ||||
|         /> | ||||
|       ) : null} | ||||
|       <FastImage | ||||
|         source={source} | ||||
|         source={connectImage(source)} | ||||
|         style={[{ flex: 1 }, imageStyle]} | ||||
|         onLoad={() => { | ||||
|           setImageLoaded(true) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import CustomText from '@components/Text' | ||||
| import { useAccessibility } from '@utils/accessibility/AccessibilityManager' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import { useGlobalStorage } from '@utils/storage/actions' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import { adaptiveScale } from '@utils/styles/scaling' | ||||
| @@ -75,7 +76,7 @@ const ParseEmojis: React.FC<Props> = ({ | ||||
|                   <CustomText key={emojiShortcode + i}> | ||||
|                     {i === 0 ? ' ' : undefined} | ||||
|                     <FastImage | ||||
|                       source={{ uri: uri.trim() }} | ||||
|                       source={connectImage({ uri: uri.trim() })} | ||||
|                       style={{ | ||||
|                         width: adaptedFontsize, | ||||
|                         height: adaptedFontsize, | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import RelativeTime from '@components/RelativeTime' | ||||
| import CustomText from '@components/Text' | ||||
| import { BlurView } from '@react-native-community/blur' | ||||
| import { useAccessibility } from '@utils/accessibility/AccessibilityManager' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import { RootStackScreenProps } from '@utils/navigation/navigators' | ||||
| import { useAnnouncementMutation, useAnnouncementQuery } from '@utils/queryHooks/announcement' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| @@ -139,9 +140,9 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'> | ||||
|               > | ||||
|                 {reaction.url ? ( | ||||
|                   <FastImage | ||||
|                     source={{ | ||||
|                     source={connectImage({ | ||||
|                       uri: reduceMotionEnabled ? reaction.static_url : reaction.url | ||||
|                     }} | ||||
|                     })} | ||||
|                     style={{ | ||||
|                       width: StyleConstants.Font.LineHeight.M + 3, | ||||
|                       height: StyleConstants.Font.LineHeight.M | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import Icon from '@components/Icon' | ||||
| import { SwipeToActions } from '@components/SwipeToActions' | ||||
| import CustomText from '@components/Text' | ||||
| import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import apiInstance from '@utils/api/instance' | ||||
| import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators' | ||||
| import { getAccountStorage, setAccountStorage, useAccountStorage } from '@utils/storage/actions' | ||||
| @@ -154,9 +155,11 @@ const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<'Screen-Compose- | ||||
|                             4, | ||||
|                           marginLeft: index !== 0 ? StyleConstants.Spacing.S : 0 | ||||
|                         }} | ||||
|                         source={{ | ||||
|                           uri: attachment.local?.thumbnail || attachment.remote?.preview_url | ||||
|                         }} | ||||
|                         source={ | ||||
|                           attachment.local?.thumbnail | ||||
|                             ? { uri: attachment.local?.thumbnail } | ||||
|                             : connectImage({ uri: attachment.remote?.preview_url }) | ||||
|                         } | ||||
|                       /> | ||||
|                     ))} | ||||
|                   </View> | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { MAX_MEDIA_ATTACHMENTS } from '@components/mediaSelector' | ||||
| import CustomText from '@components/Text' | ||||
| import { useActionSheet } from '@expo/react-native-action-sheet' | ||||
| import { useNavigation } from '@react-navigation/native' | ||||
| import { connectImage } from '@utils/api/helpers/connect' | ||||
| import { featureCheck } from '@utils/helpers/featureCheck' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import layoutAnimation from '@utils/styles/layoutAnimation' | ||||
| @@ -105,7 +106,11 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => { | ||||
|       > | ||||
|         <FastImage | ||||
|           style={{ width: '100%', height: '100%' }} | ||||
|           source={{ uri: item.local?.thumbnail || item.remote?.preview_url }} | ||||
|           source={ | ||||
|             item.local?.thumbnail | ||||
|               ? { uri: item.local?.thumbnail } | ||||
|               : connectImage({ uri: item.remote?.preview_url }) | ||||
|           } | ||||
|         /> | ||||
|         {item.remote?.meta?.original?.duration ? ( | ||||
|           <CustomText | ||||
|   | ||||
| @@ -1,16 +1,17 @@ | ||||
| import haptics from '@components/haptics' | ||||
| import { MenuContainer, MenuRow } from '@components/Menu' | ||||
| import { useActionSheet } from '@expo/react-native-action-sheet' | ||||
| import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles' | ||||
| import { LOCALES } from '@i18n/locales' | ||||
| import { useNavigation } from '@react-navigation/native' | ||||
| import { connectVerify } from '@utils/api/helpers/connect' | ||||
| import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles' | ||||
| import { useGlobalStorage } from '@utils/storage/actions' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import * as Localization from 'expo-localization' | ||||
| import React from 'react' | ||||
| import React, { useEffect, useState } from 'react' | ||||
| import { useTranslation } from 'react-i18next' | ||||
| import { Linking, Platform } from 'react-native' | ||||
| import { mapFontsizeToName } from '../SettingsFontsize' | ||||
| import { LOCALES } from '@i18n/locales' | ||||
|  | ||||
| const SettingsApp: React.FC = () => { | ||||
|   const navigation = useNavigation<any>() | ||||
| @@ -24,6 +25,22 @@ const SettingsApp: React.FC = () => { | ||||
|   const [browser, setBrowser] = useGlobalStorage.string('app.browser') | ||||
|   const [autoplayGifv, setAutoplayGifv] = useGlobalStorage.boolean('app.auto_play_gifv') | ||||
|  | ||||
|   const [connect, setConnect] = useGlobalStorage.boolean('app.connect') | ||||
|   const [showConnect, setShowConnect] = useState(connect) | ||||
|   useEffect(() => { | ||||
|     connectVerify() | ||||
|       .then(() => { | ||||
|         setShowConnect(true) | ||||
|       }) | ||||
|       .catch(() => { | ||||
|         if (connect) { | ||||
|           setConnect(false) | ||||
|         } else { | ||||
|           setShowConnect(false) | ||||
|         } | ||||
|       }) | ||||
|   }, []) | ||||
|  | ||||
|   return ( | ||||
|     <MenuContainer> | ||||
|       <MenuRow | ||||
| @@ -152,6 +169,13 @@ const SettingsApp: React.FC = () => { | ||||
|         switchValue={autoplayGifv} | ||||
|         switchOnValueChange={() => setAutoplayGifv(!autoplayGifv)} | ||||
|       /> | ||||
|       {showConnect ? ( | ||||
|         <MenuRow | ||||
|           title='使用代理' | ||||
|           switchValue={connect || false} | ||||
|           switchOnValueChange={() => setConnect(!connect)} | ||||
|         /> | ||||
|       ) : null} | ||||
|     </MenuContainer> | ||||
|   ) | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| import { getGlobalStorage } from '@utils/storage/actions' | ||||
| import axios from 'axios' | ||||
| import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers' | ||||
| import { CONNECT_DOMAIN } from './helpers/connect' | ||||
|  | ||||
| export type Params = { | ||||
|   method: 'get' | 'post' | 'put' | 'delete' | ||||
| @@ -32,17 +34,20 @@ const apiGeneral = async <T = unknown>({ | ||||
|     params ? params : '' | ||||
|   ) | ||||
|  | ||||
|   const useConnect = getGlobalStorage.boolean('app.connect') | ||||
|  | ||||
|   return axios({ | ||||
|     timeout: method === 'post' ? 1000 * 60 : 1000 * 15, | ||||
|     method, | ||||
|     baseURL: `https://${domain}/`, | ||||
|     baseURL: `https://${useConnect ? CONNECT_DOMAIN() : domain}`, | ||||
|     url, | ||||
|     params, | ||||
|     headers: { | ||||
|       Accept: 'application/json', | ||||
|       ...userAgent, | ||||
|       ...headers, | ||||
|       ...(body && body instanceof FormData && { 'Content-Type': 'multipart/form-data' }) | ||||
|       ...(body && body instanceof FormData && { 'Content-Type': 'multipart/form-data' }), | ||||
|       ...(useConnect && { 'x-tooot-domain': domain }) | ||||
|     }, | ||||
|     data: body | ||||
|   }) | ||||
|   | ||||
							
								
								
									
										144
									
								
								src/utils/api/helpers/connect.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/utils/api/helpers/connect.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| import { mapEnvironment } from '@utils/helpers/checkEnvironment' | ||||
| import { getGlobalStorage, setGlobalStorage } from '@utils/storage/actions' | ||||
| import axios from 'axios' | ||||
| import parse from 'url-parse' | ||||
| import { userAgent } from '.' | ||||
|  | ||||
| const list = [ | ||||
|   'n61owz4leck', | ||||
|   'z9skyp2f0m', | ||||
|   'nc2dqtyxevj', | ||||
|   'tgl97fgudrf', | ||||
|   'eo2sj0ut2s', | ||||
|   'a75auwihvyi', | ||||
|   'vzkpud5y5b', | ||||
|   '3uivf7yyex', | ||||
|   'pxfoa1wbor', | ||||
|   '3cor5jempc', | ||||
|   '9o32znuepr', | ||||
|   '9ayt1l2dzpi', | ||||
|   '60iu4rz8js', | ||||
|   'dzoa1lbxbv', | ||||
|   '82rpiiqw21', | ||||
|   'fblij1c9gyl', | ||||
|   'wk2x048g8gl', | ||||
|   '9x91yrbtmn', | ||||
|   'dgu5p7eif6', | ||||
|   'uftwyhrkgrh', | ||||
|   'vv5hay15vjk', | ||||
|   'ooj9ihtyur', | ||||
|   'o8r7phzd58', | ||||
|   'pujwyg269s', | ||||
|   'l6yq5nr8lv', | ||||
|   'ocyrlfmdnl', | ||||
|   'rdtpeip5e2', | ||||
|   'ykzb5784js', | ||||
|   'm34z7j5us1i', | ||||
|   'tqsfr0orqa', | ||||
|   '8ncrt0mifa', | ||||
|   'ygce2fdmsm', | ||||
|   '22vk7csljz', | ||||
|   '7mmb6hrih1', | ||||
|   'grla5cpgau', | ||||
|   '0vygyvs4k7', | ||||
|   '1texbe32sf', | ||||
|   'ckwvauiiol', | ||||
|   'qkxryrbpxx', | ||||
|   'ptb19c0ks9g', | ||||
|   '3bpe76o6stg', | ||||
|   'd507ejce9g', | ||||
|   'jpul5v2mqej', | ||||
|   '6m5uxemc79', | ||||
|   'wxbtoo9t3p', | ||||
|   '8qco3d0idh', | ||||
|   'u00c2xiabvf', | ||||
|   'hutkqwrcy8', | ||||
|   't6vrkzhpzo', | ||||
|   'wy6e529mnb', | ||||
|   'kzzrlfa59pg', | ||||
|   'mmo4sv4a7s', | ||||
|   'u0dishl20k', | ||||
|   '8qyx25bq3u', | ||||
|   'd3mucdzlu1', | ||||
|   'y123m81vsjl', | ||||
|   '51opvzdo6k', | ||||
|   'r4z333th9u', | ||||
|   'q77hl0ggfr', | ||||
|   'bsk1f2wi52g', | ||||
|   'eubnxpv0pz', | ||||
|   'h11pk7qm8i', | ||||
|   'brhxw45vd5', | ||||
|   'vtnvlsrn1z', | ||||
|   '0q5w0hhzb5', | ||||
|   'vq2rz02ayf', | ||||
|   'hml3igfwkq', | ||||
|   '39qs7vhenl', | ||||
|   '5vcv775rug', | ||||
|   'kjom5gr7i3', | ||||
|   't2kmaoeb5x', | ||||
|   'ni6ow1z11b', | ||||
|   'yvgtoc3d88', | ||||
|   'iax04eatnz', | ||||
|   'esxyu9zujg', | ||||
|   '73xa28n278', | ||||
|   '5x63a8l24k', | ||||
|   'dy1trb0b3sj', | ||||
|   'd4c31j23m8', | ||||
|   'ho76046l0j', | ||||
|   'sw8lj5u2ef', | ||||
|   'z5cn21mew5', | ||||
|   'wxj73nmqwa', | ||||
|   'gdj00dlx98', | ||||
|   '0v76xag64i', | ||||
|   'j35104qduhj', | ||||
|   'l63r7h0ss6', | ||||
|   'e5xdv7t1q0h', | ||||
|   '4icoh8t4c8', | ||||
|   'nbk36jt4sq', | ||||
|   'zi0n0cv4tk', | ||||
|   'o7qkfp3rxu', | ||||
|   'xd2wefzd27', | ||||
|   'rg7e6tsacx', | ||||
|   '9lrq3s4vfm', | ||||
|   'srs9p21lxoh', | ||||
|   'n8xymau42t', | ||||
|   'q5cik283fg', | ||||
|   '68ye9feqs5', | ||||
|   'xjc5anubnv' | ||||
| ] | ||||
|  | ||||
| export const CONNECT_DOMAIN = () => | ||||
|   mapEnvironment({ | ||||
|     release: `${list[Math.floor(Math.random() * (100 - 0) + 0)]}.tooot.app`, | ||||
|     candidate: 'connect-candidate.tooot.app', | ||||
|     development: 'connect-development.tooot.app' | ||||
|   }) | ||||
|  | ||||
| export const connectImage = ({ | ||||
|   uri | ||||
| }: { | ||||
|   uri?: string | ||||
| }): { uri?: string; headers?: { 'x-tooot-domain': string } } => { | ||||
|   const connect = getGlobalStorage.boolean('app.connect') | ||||
|   if (connect) { | ||||
|     if (uri) { | ||||
|       const host = parse(uri).host | ||||
|       return { uri: uri.replace(host, CONNECT_DOMAIN()), headers: { 'x-tooot-domain': host } } | ||||
|     } else { | ||||
|       return { uri } | ||||
|     } | ||||
|   } else { | ||||
|     return { uri } | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const connectVerify = () => | ||||
|   axios({ | ||||
|     method: 'get', | ||||
|     baseURL: `https://${CONNECT_DOMAIN()}`, | ||||
|     url: 'verify', | ||||
|     headers: { ...userAgent } | ||||
|   }).catch(err => { | ||||
|     setGlobalStorage('app.connect', false) | ||||
|     return Promise.reject(err) | ||||
|   }) | ||||
| @@ -1,7 +1,8 @@ | ||||
| import { getAccountDetails } from '@utils/storage/actions' | ||||
| import { getAccountDetails, getGlobalStorage } from '@utils/storage/actions' | ||||
| import { StorageGlobal } from '@utils/storage/global' | ||||
| import axios, { AxiosRequestConfig } from 'axios' | ||||
| import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers' | ||||
| import { CONNECT_DOMAIN } from './helpers/connect' | ||||
|  | ||||
| export type Params = { | ||||
|   account?: StorageGlobal['account.active'] | ||||
| @@ -43,11 +44,15 @@ const apiInstance = async <T = unknown>({ | ||||
|     method + ctx.blue(' -> ') + `/${url}` + (params ? ctx.blue(' -> ') : ''), | ||||
|     params ? params : '' | ||||
|   ) | ||||
|   console.log('body', body) | ||||
|  | ||||
|   const useConnect = getGlobalStorage.boolean('app.connect') | ||||
|  | ||||
|   return axios({ | ||||
|     timeout: method === 'post' ? 1000 * 60 : 1000 * 15, | ||||
|     method, | ||||
|     baseURL: `https://${accountDetails['auth.domain']}/api/${version}/`, | ||||
|     baseURL: `https://${ | ||||
|       useConnect ? CONNECT_DOMAIN() : accountDetails['auth.domain'] | ||||
|     }/api/${version}`, | ||||
|     url, | ||||
|     params, | ||||
|     headers: { | ||||
| @@ -55,7 +60,8 @@ const apiInstance = async <T = unknown>({ | ||||
|       ...userAgent, | ||||
|       ...headers, | ||||
|       Authorization: `Bearer ${accountDetails['auth.token']}`, | ||||
|       ...(body && body instanceof FormData && { 'Content-Type': 'multipart/form-data' }) | ||||
|       ...(body && body instanceof FormData && { 'Content-Type': 'multipart/form-data' }), | ||||
|       ...(useConnect && { 'x-tooot-domain': accountDetails['auth.domain'] }) | ||||
|     }, | ||||
|     data: body, | ||||
|     ...extras | ||||
|   | ||||
| @@ -17,6 +17,7 @@ export type GlobalV0 = { | ||||
|   'version.account': number | ||||
|   // boolean | ||||
|   'app.auto_play_gifv'?: boolean | ||||
|   'app.connect'?: boolean | ||||
|  | ||||
|   //// account | ||||
|   // string | ||||
|   | ||||
		Reference in New Issue
	
	Block a user