mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Updates
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 1.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icon.png
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icon.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 33 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 69 KiB | 
| @@ -154,7 +154,7 @@ const GracefullyImage: React.FC<Props> = ({ | ||||
|       children={children} | ||||
|       style={[style, dimension && { ...dimension }]} | ||||
|       {...(onPress | ||||
|         ? !imageVisible | ||||
|         ? hidden | ||||
|           ? { disabled: true } | ||||
|           : { onPress } | ||||
|         : { disabled: true })} | ||||
|   | ||||
| @@ -244,6 +244,7 @@ const ComponentInstance: React.FC<Props> = ({ | ||||
|       {type === 'local' && appData ? ( | ||||
|         <InstanceAuth | ||||
|           instanceDomain={instanceDomain!} | ||||
|           instanceUri={instanceQuery.data!.uri} | ||||
|           appData={appData} | ||||
|           goBack={goBack} | ||||
|         /> | ||||
|   | ||||
| @@ -8,12 +8,14 @@ import { useDispatch } from 'react-redux' | ||||
|  | ||||
| export interface Props { | ||||
|   instanceDomain: string | ||||
|   // Domain can be different than uri | ||||
|   instanceUri: Mastodon.Instance['uri'] | ||||
|   appData: InstanceLocal['appData'] | ||||
|   goBack?: boolean | ||||
| } | ||||
|  | ||||
| const InstanceAuth = React.memo( | ||||
|   ({ instanceDomain, appData, goBack }: Props) => { | ||||
|   ({ instanceDomain, instanceUri, appData, goBack }: Props) => { | ||||
|     let redirectUri: string | ||||
|     switch (Constants.manifest.releaseChannel) { | ||||
|       case 'production': | ||||
| @@ -70,6 +72,7 @@ const InstanceAuth = React.memo( | ||||
|             localAddInstance({ | ||||
|               url: instanceDomain, | ||||
|               token: accessToken, | ||||
|               uri: instanceUri, | ||||
|               appData | ||||
|             }) | ||||
|           ) | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import React from 'react' | ||||
| import { Image, StyleSheet, Text } from 'react-native' | ||||
| import { StyleSheet, Text } from 'react-native' | ||||
| import { Image } from 'react-native-expo-image-cache' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
|  | ||||
| @@ -49,10 +50,7 @@ const ParseEmojis: React.FC<Props> = ({ | ||||
|                 <Text key={i}> | ||||
|                   {/* When emoji starts a paragraph, lineHeight will break */} | ||||
|                   {i === 0 ? <Text> </Text> : null} | ||||
|                   <Image | ||||
|                     source={{ uri: emojis[emojiIndex].url }} | ||||
|                     style={[styles.image]} | ||||
|                   /> | ||||
|                   <Image uri={emojis[emojiIndex].url} style={[styles.image]} /> | ||||
|                 </Text> | ||||
|               ) | ||||
|             } else { | ||||
|   | ||||
| @@ -68,7 +68,7 @@ const renderNode = ({ | ||||
|             mention => mention.url === href | ||||
|           ) | ||||
|           const differentAccount = routeParams?.account | ||||
|             ? routeParams.account.id !== mentions[accountIndex].id | ||||
|             ? routeParams.account.id !== mentions[accountIndex]?.id | ||||
|             : true | ||||
|           return ( | ||||
|             <Text | ||||
|   | ||||
| @@ -5,22 +5,20 @@ import TimeAgo from 'react-timeago' | ||||
| // @ts-ignore | ||||
| import buildFormatter from 'react-timeago/lib/formatters/buildFormatter' | ||||
|  | ||||
| import zh from '@root/i18n/zh/components/relativeTime' | ||||
| import en from '@root/i18n/en/components/relativeTime' | ||||
|  | ||||
| export interface Props { | ||||
|   date: string | ||||
| } | ||||
|  | ||||
| const RelativeTime: React.FC<Props> = ({ date }) => { | ||||
|   const { i18n } = useTranslation() | ||||
|   const mapLanguageToTranslation: { [key: string]: Object } = { | ||||
|     'zh-CN': zh, | ||||
|     'en-US': en | ||||
|   } | ||||
|   const formatter = buildFormatter(mapLanguageToTranslation[i18n.language]) | ||||
|   const { t } = useTranslation('relativeTime') | ||||
|  | ||||
|   return <TimeAgo date={date} formatter={formatter} component={Text} /> | ||||
|   return ( | ||||
|     <TimeAgo | ||||
|       date={date} | ||||
|       component={Text} | ||||
|       formatter={buildFormatter(t('strings', { returnObjects: true }))} | ||||
|     /> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| export default RelativeTime | ||||
|   | ||||
| @@ -56,6 +56,7 @@ const Timeline: React.FC<Props> = ({ | ||||
|     refetch, | ||||
|     isSuccess, | ||||
|     isFetching, | ||||
|     isLoading, | ||||
|     hasPreviousPage, | ||||
|     fetchPreviousPage, | ||||
|     isFetchingPreviousPage, | ||||
| @@ -170,7 +171,8 @@ const Timeline: React.FC<Props> = ({ | ||||
|       <RefreshControl | ||||
|         {...(Platform.OS === 'android' && { enabled: true })} | ||||
|         refreshing={ | ||||
|           isFetchingPreviousPage || (isFetching && !isFetchingNextPage) | ||||
|           isFetchingPreviousPage || | ||||
|           (isFetching && !isFetchingNextPage && !isLoading) | ||||
|         } | ||||
|         onRefresh={() => { | ||||
|           if (hasPreviousPage) { | ||||
| @@ -192,7 +194,13 @@ const Timeline: React.FC<Props> = ({ | ||||
|         }} | ||||
|       /> | ||||
|     ), | ||||
|     [hasPreviousPage, isFetchingPreviousPage, isFetching, isFetchingNextPage] | ||||
|     [ | ||||
|       hasPreviousPage, | ||||
|       isFetchingPreviousPage, | ||||
|       isFetching, | ||||
|       isFetchingNextPage, | ||||
|       isLoading | ||||
|     ] | ||||
|   ) | ||||
|   const onScrollToIndexFailed = useCallback(error => { | ||||
|     const offset = error.averageItemLength * error.index | ||||
| @@ -209,10 +217,10 @@ const Timeline: React.FC<Props> = ({ | ||||
|   return ( | ||||
|     <FlatList | ||||
|       ref={flRef} | ||||
|       windowSize={11} | ||||
|       windowSize={8} | ||||
|       data={flattenData} | ||||
|       initialNumToRender={5} | ||||
|       maxToRenderPerBatch={5} | ||||
|       initialNumToRender={3} | ||||
|       maxToRenderPerBatch={3} | ||||
|       style={styles.flatList} | ||||
|       renderItem={renderItem} | ||||
|       onEndReached={onEndReached} | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| import Button from '@components/Button' | ||||
| import haptics from '@components/haptics' | ||||
| import Icon from '@components/Icon' | ||||
| import { ParseEmojis } from '@components/Parse' | ||||
| import RelativeTime from '@components/RelativeTime' | ||||
| import { ParseEmojis } from '@root/components/Parse' | ||||
| import { toast } from '@root/components/toast' | ||||
| import { toast } from '@components/toast' | ||||
| import { | ||||
|   QueryKeyTimeline, | ||||
|   useTimelineMutation | ||||
| @@ -32,7 +32,7 @@ const TimelinePoll: React.FC<Props> = ({ | ||||
|   sameAccount | ||||
| }) => { | ||||
|   const { mode, theme } = useTheme() | ||||
|   const { t, i18n } = useTranslation('timeline') | ||||
|   const { t } = useTranslation('timeline') | ||||
|  | ||||
|   const [allOptions, setAllOptions] = useState( | ||||
|     new Array(poll.options.length).fill(false) | ||||
| @@ -220,7 +220,7 @@ const TimelinePoll: React.FC<Props> = ({ | ||||
|           <Icon | ||||
|             style={styles.optionSelection} | ||||
|             name={isSelected(index)} | ||||
|             size={StyleConstants.Font.Size.L} | ||||
|             size={StyleConstants.Font.Size.M} | ||||
|             color={theme.primary} | ||||
|           /> | ||||
|           <Text style={styles.optionText}> | ||||
| @@ -275,6 +275,7 @@ const styles = StyleSheet.create({ | ||||
|     flex: 1 | ||||
|   }, | ||||
|   optionSelection: { | ||||
|     paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M, | ||||
|     marginRight: StyleConstants.Spacing.S | ||||
|   }, | ||||
|   optionPercentage: { | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| export default { | ||||
|   common: require('./common').default | ||||
|   common: require('./common').default, | ||||
|  | ||||
|   relativeTime: require('./components/relativeTime').default | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| const strings = { | ||||
|   prefixAgo: null, | ||||
|   prefixFromNow: null, | ||||
|   suffixAgo: 'ago', | ||||
|   suffixFromNow: 'from now', | ||||
|   seconds: '%d seconds', | ||||
|   minute: 'about a minute', | ||||
|   minutes: '%d minutes', | ||||
|   hour: 'about an hour', | ||||
|   hours: 'about %d hours', | ||||
|   day: 'a day', | ||||
|   days: '%d days', | ||||
|   month: 'about a month', | ||||
|   months: '%d months', | ||||
|   year: 'about a year', | ||||
|   years: '%d years', | ||||
|   wordSeparator: ' ' | ||||
| export default { | ||||
|   strings: { | ||||
|     prefixAgo: null, | ||||
|     prefixFromNow: null, | ||||
|     suffixAgo: 'ago', | ||||
|     suffixFromNow: 'from now', | ||||
|     seconds: '%d seconds', | ||||
|     minute: 'about a minute', | ||||
|     minutes: '%d minutes', | ||||
|     hour: 'about an hour', | ||||
|     hours: 'about %d hours', | ||||
|     day: 'a day', | ||||
|     days: '%d days', | ||||
|     month: 'about a month', | ||||
|     months: '%d months', | ||||
|     year: 'about a year', | ||||
|     years: '%d years', | ||||
|     wordSeparator: ' ' | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default strings | ||||
|   | ||||
| @@ -1,32 +1,20 @@ | ||||
| import { store } from '@root/store' | ||||
| import { getSettingsLanguage, supportedLngs } from '@utils/slices/settingsSlice' | ||||
| import i18next from 'i18next' | ||||
| import { initReactI18next } from 'react-i18next' | ||||
| import * as Localization from 'expo-localization' | ||||
|  | ||||
| import zh from '@root/i18n/zh/_all' | ||||
| import en from '@root/i18n/en/_all' | ||||
| import { | ||||
|   changeLanguage, | ||||
|   getSettingsLanguage | ||||
| } from '@utils/slices/settingsSlice' | ||||
| import { store } from '@root/store' | ||||
| import zh_Hans from '@root/i18n/zh-Hans/_all' | ||||
|  | ||||
| if (!getSettingsLanguage(store.getState())) { | ||||
|   const deviceLocal = Localization.locale | ||||
|   if (deviceLocal.startsWith('zh')) { | ||||
|     store.dispatch(changeLanguage('zh-CN')) | ||||
|   } else { | ||||
|     store.dispatch(changeLanguage('en-US')) | ||||
|   } | ||||
| } | ||||
| i18next.use(initReactI18next).init({ | ||||
|   lng: 'zh-CN', | ||||
|   fallbackLng: 'en-US', | ||||
|   supportedLngs: ['zh-CN', 'en-US'], | ||||
|   lng: getSettingsLanguage(store.getState()), | ||||
|   fallbackLng: 'en', | ||||
|   supportedLngs: supportedLngs, | ||||
|  | ||||
|   ns: ['common'], | ||||
|   defaultNS: 'common', | ||||
|  | ||||
|   resources: { 'zh-CN': zh, 'en-US': en }, | ||||
|   resources: { 'zh-Hans': zh_Hans, en }, | ||||
|  | ||||
|   saveMissing: true, | ||||
|   missingKeyHandler: (lng, ns, key, fallbackValue) => { | ||||
|   | ||||
| @@ -21,5 +21,6 @@ export default { | ||||
|   sharedAnnouncements: require('./screens/sharedAnnouncements').default, | ||||
| 
 | ||||
|   relationship: require('./components/relationship').default, | ||||
|   relativeTime: require('./components/relativeTime').default, | ||||
|   timeline: require('./components/timeline').default | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/i18n/zh-Hans/components/relativeTime.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/i18n/zh-Hans/components/relativeTime.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| export default { | ||||
|   strings: { | ||||
|     prefixAgo: null, | ||||
|     prefixFromNow: null, | ||||
|     suffixAgo: '之前', | ||||
|     suffixFromNow: '之后', | ||||
|     seconds: '%d秒', | ||||
|     minute: '1分钟', | ||||
|     minutes: '%d分钟', | ||||
|     hour: '1小时', | ||||
|     hours: '%d小时', | ||||
|     day: '1天', | ||||
|     days: '%d天', | ||||
|     month: '1个月', | ||||
|     months: '%d月', | ||||
|     year: '大约1年', | ||||
|     years: '%d年', | ||||
|  | ||||
|     wordSeparator: '' | ||||
|   } | ||||
| } | ||||
| @@ -4,8 +4,8 @@ export default { | ||||
|     language: { | ||||
|       heading: '切换语言', | ||||
|       options: { | ||||
|         zh: '简体中文', | ||||
|         en: 'English', | ||||
|         'en': 'English', | ||||
|         'zh-Hans': '简体中文', | ||||
|         cancel: '$t(common:buttons.cancel)' | ||||
|       } | ||||
|     }, | ||||
| @@ -1,21 +0,0 @@ | ||||
| const strings = { | ||||
|   prefixAgo: null, | ||||
|   prefixFromNow: null, | ||||
|   suffixAgo: '之前', | ||||
|   suffixFromNow: '之后', | ||||
|   seconds: '%d秒', | ||||
|   minute: '1分钟', | ||||
|   minutes: '%d分钟', | ||||
|   hour: '1小时', | ||||
|   hours: '%d小时', | ||||
|   day: '1天', | ||||
|   days: '%d天', | ||||
|   month: '1个月', | ||||
|   months: '%d月', | ||||
|   year: '大约1年', | ||||
|   years: '%d年', | ||||
|  | ||||
|   wordSeparator: '' | ||||
| } | ||||
|  | ||||
| export default strings | ||||
| @@ -98,33 +98,28 @@ const ScreenMeSettings: React.FC = () => { | ||||
|           title={t('content.language.heading')} | ||||
|           content={t(`content.language.options.${settingsLanguage}`)} | ||||
|           iconBack='ChevronRight' | ||||
|           onPress={() => | ||||
|           onPress={() => { | ||||
|             const availableLanguages = Object.keys( | ||||
|               i18n.services.resourceStore.data | ||||
|             ) | ||||
|             showActionSheetWithOptions( | ||||
|               { | ||||
|                 title: t('content.language.heading'), | ||||
|                 options: [ | ||||
|                   t('content.language.options.zh'), | ||||
|                   t('content.language.options.en'), | ||||
|                   ...availableLanguages.map(language => | ||||
|                     t(`content.language.options.${language}`) | ||||
|                   ), | ||||
|                   t('content.language.options.cancel') | ||||
|                 ], | ||||
|                 cancelButtonIndex: 2 | ||||
|                 cancelButtonIndex: i18n.languages.length | ||||
|               }, | ||||
|               buttonIndex => { | ||||
|                 switch (buttonIndex) { | ||||
|                   case 0: | ||||
|                     haptics('Success') | ||||
|                     dispatch(changeLanguage('zh-CN')) | ||||
|                     i18n.changeLanguage('zh-CN') | ||||
|                     break | ||||
|                   case 1: | ||||
|                     haptics('Success') | ||||
|                     dispatch(changeLanguage('en-US')) | ||||
|                     i18n.changeLanguage('en-US') | ||||
|                     break | ||||
|                 } | ||||
|                 haptics('Success') | ||||
|                 dispatch(changeLanguage(availableLanguages[buttonIndex])) | ||||
|                 i18n.changeLanguage(availableLanguages[buttonIndex]) | ||||
|               } | ||||
|             ) | ||||
|           } | ||||
|           }} | ||||
|         /> | ||||
|         <MenuRow | ||||
|           title={t('content.theme.heading')} | ||||
| @@ -229,7 +224,7 @@ const ScreenMeSettings: React.FC = () => { | ||||
|           iconBack='ChevronRight' | ||||
|         /> | ||||
|         <Text style={[styles.version, { color: theme.secondary }]}> | ||||
|           {t('content.version', { version: '1.0.0' })} | ||||
|           {t('content.version', { version: Constants.manifest.version })} | ||||
|         </Text> | ||||
|       </MenuContainer> | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,7 @@ export interface Props { | ||||
|  | ||||
| const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>( | ||||
|   ({ account }, ref) => { | ||||
|     const { i18n } = useTranslation() | ||||
|     const { theme } = useTheme() | ||||
|     const { t } = useTranslation('sharedAccount') | ||||
|     const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient) | ||||
| @@ -26,7 +27,11 @@ const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>( | ||||
|         width={StyleConstants.Font.Size.S * 8} | ||||
|         height={StyleConstants.Font.LineHeight.S} | ||||
|         style={{ marginBottom: StyleConstants.Spacing.M }} | ||||
|         shimmerColors={[theme.shimmerDefault, theme.shimmerHighlight, theme.shimmerDefault]} | ||||
|         shimmerColors={[ | ||||
|           theme.shimmerDefault, | ||||
|           theme.shimmerHighlight, | ||||
|           theme.shimmerDefault | ||||
|         ]} | ||||
|       > | ||||
|         <View style={styles.created}> | ||||
|           <Icon | ||||
| @@ -42,11 +47,14 @@ const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>( | ||||
|             }} | ||||
|           > | ||||
|             {t('content.created_at', { | ||||
|               date: new Date(account?.created_at!).toLocaleDateString('zh-CN', { | ||||
|                 year: 'numeric', | ||||
|                 month: 'long', | ||||
|                 day: 'numeric' | ||||
|               }) | ||||
|               date: new Date(account?.created_at!).toLocaleDateString( | ||||
|                 i18n.language, | ||||
|                 { | ||||
|                   year: 'numeric', | ||||
|                   month: 'long', | ||||
|                   day: 'numeric' | ||||
|                 } | ||||
|               ) | ||||
|             })} | ||||
|           </Text> | ||||
|         </View> | ||||
|   | ||||
| @@ -28,7 +28,7 @@ const AccountInformationFields = React.memo( | ||||
|                 size={'M'} | ||||
|                 emojis={account.emojis} | ||||
|                 showFullLink | ||||
|                 numberOfLines={3} | ||||
|                 numberOfLines={5} | ||||
|               /> | ||||
|               {field.verified_at ? ( | ||||
|                 <Icon | ||||
| @@ -45,7 +45,7 @@ const AccountInformationFields = React.memo( | ||||
|                 size={'M'} | ||||
|                 emojis={account.emojis} | ||||
|                 showFullLink | ||||
|                 numberOfLines={3} | ||||
|                 numberOfLines={5} | ||||
|               /> | ||||
|             </View> | ||||
|           </View> | ||||
|   | ||||
| @@ -123,19 +123,28 @@ const Compose: React.FC<SharedComposeProp> = ({ | ||||
|       <HeaderLeft | ||||
|         type='text' | ||||
|         content='退出编辑' | ||||
|         onPress={() => | ||||
|           Alert.alert('确认取消编辑?', '', [ | ||||
|             { | ||||
|               text: '退出编辑', | ||||
|               style: 'destructive', | ||||
|               onPress: () => navigation.goBack() | ||||
|             }, | ||||
|             { text: '继续编辑', style: 'cancel' } | ||||
|           ]) | ||||
|         } | ||||
|         onPress={() => { | ||||
|           if ( | ||||
|             totalTextCount === 0 && | ||||
|             composeState.attachments.uploads.length === 0 && | ||||
|             composeState.poll.active === false | ||||
|           ) { | ||||
|             navigation.goBack() | ||||
|             return | ||||
|           } else { | ||||
|             Alert.alert('确认取消编辑?', '', [ | ||||
|               { | ||||
|                 text: '退出编辑', | ||||
|                 style: 'destructive', | ||||
|                 onPress: () => navigation.goBack() | ||||
|               }, | ||||
|               { text: '继续编辑', style: 'cancel' } | ||||
|             ]) | ||||
|           } | ||||
|         }} | ||||
|       /> | ||||
|     ), | ||||
|     [] | ||||
|     [totalTextCount] | ||||
|   ) | ||||
|   const headerCenter = useCallback( | ||||
|     () => ( | ||||
|   | ||||
| @@ -1,17 +1,77 @@ | ||||
| import { useAccountQuery } from '@utils/queryHooks/account' | ||||
| import { | ||||
|   getLocalActiveIndex, | ||||
|   getLocalInstances, | ||||
|   InstanceLocal | ||||
| } from '@utils/slices/instancesSlice' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import React, { useContext } from 'react' | ||||
| import ComposeSpoilerInput from '@screens/Shared/Compose/SpoilerInput' | ||||
| import ComposeTextInput from '@screens/Shared/Compose/TextInput' | ||||
| import ComposeContext from '@screens/Shared/Compose//utils/createContext' | ||||
| import { StyleSheet, Text, View } from 'react-native' | ||||
| import { Chase } from 'react-native-animated-spinkit' | ||||
| import { useSelector } from 'react-redux' | ||||
| import ComposeSpoilerInput from '../SpoilerInput' | ||||
| import ComposeTextInput from '../TextInput' | ||||
| import ComposeContext from '../utils/createContext' | ||||
|  | ||||
| const PostingAs: React.FC<{ | ||||
|   id: Mastodon.Account['id'] | ||||
|   domain: InstanceLocal['url'] | ||||
| }> = ({ id, domain }) => { | ||||
|   const { theme } = useTheme() | ||||
|  | ||||
|   const { data, status } = useAccountQuery({ id }) | ||||
|  | ||||
|   switch (status) { | ||||
|     case 'loading': | ||||
|       return ( | ||||
|         <Chase | ||||
|           size={StyleConstants.Font.LineHeight.M - 2} | ||||
|           color={theme.secondary} | ||||
|         /> | ||||
|       ) | ||||
|     case 'success': | ||||
|       return ( | ||||
|         <Text style={[styles.postingAsText, { color: theme.secondary }]}> | ||||
|           用 @{data?.acct}@{domain} 发布 | ||||
|         </Text> | ||||
|       ) | ||||
|     default: | ||||
|       return null | ||||
|   } | ||||
| } | ||||
|  | ||||
| const ComposeRootHeader: React.FC = () => { | ||||
|   const { composeState } = useContext(ComposeContext) | ||||
|   const localActiveIndex = useSelector(getLocalActiveIndex) | ||||
|   const localInstances = useSelector(getLocalInstances) | ||||
|  | ||||
|   return ( | ||||
|     <> | ||||
|       {localActiveIndex !== null && | ||||
|         localInstances.length && | ||||
|         localInstances.length > 1 && ( | ||||
|           <View style={styles.postingAs}> | ||||
|             <PostingAs | ||||
|               id={localInstances[localActiveIndex].account.id} | ||||
|               domain={localInstances[localActiveIndex].uri} | ||||
|             /> | ||||
|           </View> | ||||
|         )} | ||||
|       {composeState.spoiler.active ? <ComposeSpoilerInput /> : null} | ||||
|       <ComposeTextInput /> | ||||
|     </> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| const styles = StyleSheet.create({ | ||||
|   postingAs: { | ||||
|     marginHorizontal: StyleConstants.Spacing.Global.PagePadding, | ||||
|     marginTop: StyleConstants.Spacing.S | ||||
|   }, | ||||
|   postingAsText: { | ||||
|     ...StyleConstants.FontStyle.S | ||||
|   } | ||||
| }) | ||||
|  | ||||
| export default ComposeRootHeader | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { | ||||
|   Image, | ||||
|   Platform, | ||||
|   Share, | ||||
|   StatusBar, | ||||
|   StyleSheet, | ||||
|   Text | ||||
| } from 'react-native' | ||||
| @@ -57,20 +58,23 @@ const ScreenSharedImagesViewer: React.FC<SharedImagesViewerProp> = ({ | ||||
|  | ||||
|   const component = useCallback( | ||||
|     () => ( | ||||
|       <ImageViewer | ||||
|         index={initialIndex} | ||||
|         imageUrls={imageUrls} | ||||
|         pageAnimateTime={250} | ||||
|         enableSwipeDown={true} | ||||
|         useNativeDriver={true} | ||||
|         swipeDownThreshold={100} | ||||
|         renderIndicator={() => <></>} | ||||
|         saveToLocalByLongPress={false} | ||||
|         onSwipeDown={() => navigation.goBack()} | ||||
|         style={{ flex: 1, marginBottom: 44 + safeAreaInsets.bottom }} | ||||
|         onChange={index => index !== undefined && setCurrentIndex(index)} | ||||
|         renderImage={props => <TheImage {...props} imageUrls={imageUrls} />} | ||||
|       /> | ||||
|       <> | ||||
|         <StatusBar barStyle='light-content' /> | ||||
|         <ImageViewer | ||||
|           index={initialIndex} | ||||
|           imageUrls={imageUrls} | ||||
|           pageAnimateTime={250} | ||||
|           enableSwipeDown={true} | ||||
|           useNativeDriver={true} | ||||
|           swipeDownThreshold={100} | ||||
|           renderIndicator={() => <></>} | ||||
|           saveToLocalByLongPress={false} | ||||
|           onSwipeDown={() => navigation.goBack()} | ||||
|           style={{ flex: 1, marginBottom: 44 + safeAreaInsets.bottom }} | ||||
|           onChange={index => index !== undefined && setCurrentIndex(index)} | ||||
|           renderImage={props => <TheImage {...props} imageUrls={imageUrls} />} | ||||
|         /> | ||||
|       </> | ||||
|     ), | ||||
|     [] | ||||
|   ) | ||||
| @@ -85,7 +89,9 @@ const ScreenSharedImagesViewer: React.FC<SharedImagesViewerProp> = ({ | ||||
|   }, [currentIndex]) | ||||
|  | ||||
|   return ( | ||||
|     <Stack.Navigator screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}> | ||||
|     <Stack.Navigator | ||||
|       screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }} | ||||
|     > | ||||
|       <Stack.Screen | ||||
|         name='Screen-Shared-ImagesViewer-Root' | ||||
|         component={component} | ||||
|   | ||||
| @@ -150,7 +150,7 @@ const ScreenSharedSearch: React.FC<Props> = ({ searchTerm }) => { | ||||
|           <ComponentAccount | ||||
|             account={item} | ||||
|             onPress={() => { | ||||
|               navigation.push('Screen-Shared-Account', { item }) | ||||
|               navigation.push('Screen-Shared-Account', { account: item }) | ||||
|             }} | ||||
|           /> | ||||
|         ) | ||||
|   | ||||
| @@ -201,16 +201,27 @@ const sharedScreens = ( | ||||
|         // https://github.com/react-navigation/react-navigation/issues/6746#issuecomment-583897436 | ||||
|         headerCenter: () => ( | ||||
|           <View style={styles.searchBar}> | ||||
|             <Text | ||||
|               style={{ ...StyleConstants.FontStyle.M, color: theme.primary }} | ||||
|             > | ||||
|               搜索 | ||||
|             </Text> | ||||
|             <TextInput | ||||
|               editable={false} | ||||
|               children={ | ||||
|                 <Text | ||||
|                   style={[ | ||||
|                     styles.textInput, | ||||
|                     { | ||||
|                       color: theme.primary | ||||
|                     } | ||||
|                   ]} | ||||
|                   children='搜索' | ||||
|                 /> | ||||
|               } | ||||
|             /> | ||||
|             <TextInput | ||||
|               style={[ | ||||
|                 styles.textInput, | ||||
|                 { | ||||
|                   color: theme.primary | ||||
|                   flex: 1, | ||||
|                   color: theme.primary, | ||||
|                   paddingLeft: StyleConstants.Spacing.XS | ||||
|                 } | ||||
|               ]} | ||||
|               autoFocus | ||||
| @@ -251,10 +262,7 @@ const styles = StyleSheet.create({ | ||||
|     alignItems: 'center' | ||||
|   }, | ||||
|   textInput: { | ||||
|     ...StyleConstants.FontStyle.M, | ||||
|     paddingLeft: StyleConstants.Spacing.XS, | ||||
|     marginBottom: | ||||
|       (StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M) / 2 | ||||
|     fontSize: StyleConstants.Font.Size.M | ||||
|   } | ||||
| }) | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import analytics from '@components/analytics' | ||||
| import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' | ||||
| import { RootState } from '@root/store' | ||||
| import * as AuthSession from 'expo-auth-session' | ||||
| import * as Localization from 'expo-localization' | ||||
|  | ||||
| export type InstanceLocal = { | ||||
|   appData: { | ||||
| @@ -11,6 +12,7 @@ export type InstanceLocal = { | ||||
|   } | ||||
|   url: string | ||||
|   token: string | ||||
|   uri: Mastodon.Instance['uri'] | ||||
|   account: { | ||||
|     id: Mastodon.Account['id'] | ||||
|     preferences: Mastodon.Preferences | ||||
| @@ -50,10 +52,12 @@ export const localAddInstance = createAsyncThunk( | ||||
|   async ({ | ||||
|     url, | ||||
|     token, | ||||
|     uri, | ||||
|     appData | ||||
|   }: { | ||||
|     url: InstanceLocal['url'] | ||||
|     token: InstanceLocal['token'] | ||||
|     uri: Mastodon.Instance['uri'] | ||||
|     appData: InstanceLocal['appData'] | ||||
|   }): Promise<{ type: 'add' | 'overwrite'; data: InstanceLocal }> => { | ||||
|     const { store } = require('@root/store') | ||||
| @@ -101,6 +105,7 @@ export const localAddInstance = createAsyncThunk( | ||||
|         appData, | ||||
|         url, | ||||
|         token, | ||||
|         uri, | ||||
|         account: { | ||||
|           id, | ||||
|           preferences | ||||
| @@ -159,7 +164,7 @@ export const instancesInitialState: InstancesState = { | ||||
|     instances: [] | ||||
|   }, | ||||
|   remote: { | ||||
|     url: 'm.cmx.im' | ||||
|     url: Localization.locale.includes('zh') ? 'm.cmx.im' : 'mastodon.social' | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,16 +1,19 @@ | ||||
| import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' | ||||
| import { RootState } from '@root/store' | ||||
| import * as Analytics from 'expo-firebase-analytics' | ||||
| import * as Localization from 'expo-localization' | ||||
|  | ||||
| export const supportedLngs = ['zh-Hans', 'en'] | ||||
|  | ||||
| export type SettingsState = { | ||||
|   language: 'zh-CN' | 'en-US' | undefined | ||||
|   language: 'zh-Hans' | 'en' | ||||
|   theme: 'light' | 'dark' | 'auto' | ||||
|   browser: 'internal' | 'external' | ||||
|   analytics: boolean | ||||
| } | ||||
|  | ||||
| export const settingsInitialState = { | ||||
|   language: undefined, | ||||
|   language: Localization.locale, | ||||
|   theme: 'auto', | ||||
|   browser: 'internal', | ||||
|   analytics: true | ||||
|   | ||||
		Reference in New Issue
	
	Block a user