1
0
mirror of https://github.com/tooot-app/app synced 2025-04-24 23:18:47 +02:00
This commit is contained in:
Zhiyuan Zheng 2021-01-17 22:37:05 +01:00
parent 813f6b57c4
commit f977fdfa8b
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
44 changed files with 252 additions and 158 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

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

View File

@ -154,7 +154,7 @@ const GracefullyImage: React.FC<Props> = ({
children={children} children={children}
style={[style, dimension && { ...dimension }]} style={[style, dimension && { ...dimension }]}
{...(onPress {...(onPress
? !imageVisible ? hidden
? { disabled: true } ? { disabled: true }
: { onPress } : { onPress }
: { disabled: true })} : { disabled: true })}

View File

@ -244,6 +244,7 @@ const ComponentInstance: React.FC<Props> = ({
{type === 'local' && appData ? ( {type === 'local' && appData ? (
<InstanceAuth <InstanceAuth
instanceDomain={instanceDomain!} instanceDomain={instanceDomain!}
instanceUri={instanceQuery.data!.uri}
appData={appData} appData={appData}
goBack={goBack} goBack={goBack}
/> />

View File

@ -8,12 +8,14 @@ import { useDispatch } from 'react-redux'
export interface Props { export interface Props {
instanceDomain: string instanceDomain: string
// Domain can be different than uri
instanceUri: Mastodon.Instance['uri']
appData: InstanceLocal['appData'] appData: InstanceLocal['appData']
goBack?: boolean goBack?: boolean
} }
const InstanceAuth = React.memo( const InstanceAuth = React.memo(
({ instanceDomain, appData, goBack }: Props) => { ({ instanceDomain, instanceUri, appData, goBack }: Props) => {
let redirectUri: string let redirectUri: string
switch (Constants.manifest.releaseChannel) { switch (Constants.manifest.releaseChannel) {
case 'production': case 'production':
@ -70,6 +72,7 @@ const InstanceAuth = React.memo(
localAddInstance({ localAddInstance({
url: instanceDomain, url: instanceDomain,
token: accessToken, token: accessToken,
uri: instanceUri,
appData appData
}) })
) )

View File

@ -1,5 +1,6 @@
import React from 'react' 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 { useTheme } from '@utils/styles/ThemeManager'
import { StyleConstants } from '@utils/styles/constants' import { StyleConstants } from '@utils/styles/constants'
@ -49,10 +50,7 @@ const ParseEmojis: React.FC<Props> = ({
<Text key={i}> <Text key={i}>
{/* When emoji starts a paragraph, lineHeight will break */} {/* When emoji starts a paragraph, lineHeight will break */}
{i === 0 ? <Text> </Text> : null} {i === 0 ? <Text> </Text> : null}
<Image <Image uri={emojis[emojiIndex].url} style={[styles.image]} />
source={{ uri: emojis[emojiIndex].url }}
style={[styles.image]}
/>
</Text> </Text>
) )
} else { } else {

View File

@ -68,7 +68,7 @@ const renderNode = ({
mention => mention.url === href mention => mention.url === href
) )
const differentAccount = routeParams?.account const differentAccount = routeParams?.account
? routeParams.account.id !== mentions[accountIndex].id ? routeParams.account.id !== mentions[accountIndex]?.id
: true : true
return ( return (
<Text <Text

View File

@ -5,22 +5,20 @@ import TimeAgo from 'react-timeago'
// @ts-ignore // @ts-ignore
import buildFormatter from 'react-timeago/lib/formatters/buildFormatter' 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 { export interface Props {
date: string date: string
} }
const RelativeTime: React.FC<Props> = ({ date }) => { const RelativeTime: React.FC<Props> = ({ date }) => {
const { i18n } = useTranslation() const { t } = useTranslation('relativeTime')
const mapLanguageToTranslation: { [key: string]: Object } = {
'zh-CN': zh,
'en-US': en
}
const formatter = buildFormatter(mapLanguageToTranslation[i18n.language])
return <TimeAgo date={date} formatter={formatter} component={Text} /> return (
<TimeAgo
date={date}
component={Text}
formatter={buildFormatter(t('strings', { returnObjects: true }))}
/>
)
} }
export default RelativeTime export default RelativeTime

View File

@ -56,6 +56,7 @@ const Timeline: React.FC<Props> = ({
refetch, refetch,
isSuccess, isSuccess,
isFetching, isFetching,
isLoading,
hasPreviousPage, hasPreviousPage,
fetchPreviousPage, fetchPreviousPage,
isFetchingPreviousPage, isFetchingPreviousPage,
@ -170,7 +171,8 @@ const Timeline: React.FC<Props> = ({
<RefreshControl <RefreshControl
{...(Platform.OS === 'android' && { enabled: true })} {...(Platform.OS === 'android' && { enabled: true })}
refreshing={ refreshing={
isFetchingPreviousPage || (isFetching && !isFetchingNextPage) isFetchingPreviousPage ||
(isFetching && !isFetchingNextPage && !isLoading)
} }
onRefresh={() => { onRefresh={() => {
if (hasPreviousPage) { 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 onScrollToIndexFailed = useCallback(error => {
const offset = error.averageItemLength * error.index const offset = error.averageItemLength * error.index
@ -209,10 +217,10 @@ const Timeline: React.FC<Props> = ({
return ( return (
<FlatList <FlatList
ref={flRef} ref={flRef}
windowSize={11} windowSize={8}
data={flattenData} data={flattenData}
initialNumToRender={5} initialNumToRender={3}
maxToRenderPerBatch={5} maxToRenderPerBatch={3}
style={styles.flatList} style={styles.flatList}
renderItem={renderItem} renderItem={renderItem}
onEndReached={onEndReached} onEndReached={onEndReached}

View File

@ -1,9 +1,9 @@
import Button from '@components/Button' import Button from '@components/Button'
import haptics from '@components/haptics' import haptics from '@components/haptics'
import Icon from '@components/Icon' import Icon from '@components/Icon'
import { ParseEmojis } from '@components/Parse'
import RelativeTime from '@components/RelativeTime' import RelativeTime from '@components/RelativeTime'
import { ParseEmojis } from '@root/components/Parse' import { toast } from '@components/toast'
import { toast } from '@root/components/toast'
import { import {
QueryKeyTimeline, QueryKeyTimeline,
useTimelineMutation useTimelineMutation
@ -32,7 +32,7 @@ const TimelinePoll: React.FC<Props> = ({
sameAccount sameAccount
}) => { }) => {
const { mode, theme } = useTheme() const { mode, theme } = useTheme()
const { t, i18n } = useTranslation('timeline') const { t } = useTranslation('timeline')
const [allOptions, setAllOptions] = useState( const [allOptions, setAllOptions] = useState(
new Array(poll.options.length).fill(false) new Array(poll.options.length).fill(false)
@ -220,7 +220,7 @@ const TimelinePoll: React.FC<Props> = ({
<Icon <Icon
style={styles.optionSelection} style={styles.optionSelection}
name={isSelected(index)} name={isSelected(index)}
size={StyleConstants.Font.Size.L} size={StyleConstants.Font.Size.M}
color={theme.primary} color={theme.primary}
/> />
<Text style={styles.optionText}> <Text style={styles.optionText}>
@ -275,6 +275,7 @@ const styles = StyleSheet.create({
flex: 1 flex: 1
}, },
optionSelection: { optionSelection: {
paddingTop: StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M,
marginRight: StyleConstants.Spacing.S marginRight: StyleConstants.Spacing.S
}, },
optionPercentage: { optionPercentage: {

View File

@ -1,3 +1,5 @@
export default { export default {
common: require('./common').default common: require('./common').default,
relativeTime: require('./components/relativeTime').default
} }

View File

@ -1,20 +1,20 @@
const strings = { export default {
prefixAgo: null, strings: {
prefixFromNow: null, prefixAgo: null,
suffixAgo: 'ago', prefixFromNow: null,
suffixFromNow: 'from now', suffixAgo: 'ago',
seconds: '%d seconds', suffixFromNow: 'from now',
minute: 'about a minute', seconds: '%d seconds',
minutes: '%d minutes', minute: 'about a minute',
hour: 'about an hour', minutes: '%d minutes',
hours: 'about %d hours', hour: 'about an hour',
day: 'a day', hours: 'about %d hours',
days: '%d days', day: 'a day',
month: 'about a month', days: '%d days',
months: '%d months', month: 'about a month',
year: 'about a year', months: '%d months',
years: '%d years', year: 'about a year',
wordSeparator: ' ' years: '%d years',
wordSeparator: ' '
}
} }
export default strings

View File

@ -1,32 +1,20 @@
import { store } from '@root/store'
import { getSettingsLanguage, supportedLngs } from '@utils/slices/settingsSlice'
import i18next from 'i18next' import i18next from 'i18next'
import { initReactI18next } from 'react-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 en from '@root/i18n/en/_all'
import { import zh_Hans from '@root/i18n/zh-Hans/_all'
changeLanguage,
getSettingsLanguage
} from '@utils/slices/settingsSlice'
import { store } from '@root/store'
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({ i18next.use(initReactI18next).init({
lng: 'zh-CN', lng: getSettingsLanguage(store.getState()),
fallbackLng: 'en-US', fallbackLng: 'en',
supportedLngs: ['zh-CN', 'en-US'], supportedLngs: supportedLngs,
ns: ['common'], ns: ['common'],
defaultNS: 'common', defaultNS: 'common',
resources: { 'zh-CN': zh, 'en-US': en }, resources: { 'zh-Hans': zh_Hans, en },
saveMissing: true, saveMissing: true,
missingKeyHandler: (lng, ns, key, fallbackValue) => { missingKeyHandler: (lng, ns, key, fallbackValue) => {

View File

@ -21,5 +21,6 @@ export default {
sharedAnnouncements: require('./screens/sharedAnnouncements').default, sharedAnnouncements: require('./screens/sharedAnnouncements').default,
relationship: require('./components/relationship').default, relationship: require('./components/relationship').default,
relativeTime: require('./components/relativeTime').default,
timeline: require('./components/timeline').default timeline: require('./components/timeline').default
} }

View 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: ''
}
}

View File

@ -4,8 +4,8 @@ export default {
language: { language: {
heading: '切换语言', heading: '切换语言',
options: { options: {
zh: '简体中文', 'en': 'English',
en: 'English', 'zh-Hans': '简体中文',
cancel: '$t(common:buttons.cancel)' cancel: '$t(common:buttons.cancel)'
} }
}, },

View File

@ -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

View File

@ -98,33 +98,28 @@ const ScreenMeSettings: React.FC = () => {
title={t('content.language.heading')} title={t('content.language.heading')}
content={t(`content.language.options.${settingsLanguage}`)} content={t(`content.language.options.${settingsLanguage}`)}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={() => onPress={() => {
const availableLanguages = Object.keys(
i18n.services.resourceStore.data
)
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('content.language.heading'), title: t('content.language.heading'),
options: [ options: [
t('content.language.options.zh'), ...availableLanguages.map(language =>
t('content.language.options.en'), t(`content.language.options.${language}`)
),
t('content.language.options.cancel') t('content.language.options.cancel')
], ],
cancelButtonIndex: 2 cancelButtonIndex: i18n.languages.length
}, },
buttonIndex => { buttonIndex => {
switch (buttonIndex) { haptics('Success')
case 0: dispatch(changeLanguage(availableLanguages[buttonIndex]))
haptics('Success') i18n.changeLanguage(availableLanguages[buttonIndex])
dispatch(changeLanguage('zh-CN'))
i18n.changeLanguage('zh-CN')
break
case 1:
haptics('Success')
dispatch(changeLanguage('en-US'))
i18n.changeLanguage('en-US')
break
}
} }
) )
} }}
/> />
<MenuRow <MenuRow
title={t('content.theme.heading')} title={t('content.theme.heading')}
@ -229,7 +224,7 @@ const ScreenMeSettings: React.FC = () => {
iconBack='ChevronRight' iconBack='ChevronRight'
/> />
<Text style={[styles.version, { color: theme.secondary }]}> <Text style={[styles.version, { color: theme.secondary }]}>
{t('content.version', { version: '1.0.0' })} {t('content.version', { version: Constants.manifest.version })}
</Text> </Text>
</MenuContainer> </MenuContainer>

View File

@ -15,6 +15,7 @@ export interface Props {
const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>( const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>(
({ account }, ref) => { ({ account }, ref) => {
const { i18n } = useTranslation()
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('sharedAccount') const { t } = useTranslation('sharedAccount')
const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient) const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient)
@ -26,7 +27,11 @@ const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>(
width={StyleConstants.Font.Size.S * 8} width={StyleConstants.Font.Size.S * 8}
height={StyleConstants.Font.LineHeight.S} height={StyleConstants.Font.LineHeight.S}
style={{ marginBottom: StyleConstants.Spacing.M }} style={{ marginBottom: StyleConstants.Spacing.M }}
shimmerColors={[theme.shimmerDefault, theme.shimmerHighlight, theme.shimmerDefault]} shimmerColors={[
theme.shimmerDefault,
theme.shimmerHighlight,
theme.shimmerDefault
]}
> >
<View style={styles.created}> <View style={styles.created}>
<Icon <Icon
@ -42,11 +47,14 @@ const AccountInformationCreated = forwardRef<ShimmerPlaceholder, Props>(
}} }}
> >
{t('content.created_at', { {t('content.created_at', {
date: new Date(account?.created_at!).toLocaleDateString('zh-CN', { date: new Date(account?.created_at!).toLocaleDateString(
year: 'numeric', i18n.language,
month: 'long', {
day: 'numeric' year: 'numeric',
}) month: 'long',
day: 'numeric'
}
)
})} })}
</Text> </Text>
</View> </View>

View File

@ -28,7 +28,7 @@ const AccountInformationFields = React.memo(
size={'M'} size={'M'}
emojis={account.emojis} emojis={account.emojis}
showFullLink showFullLink
numberOfLines={3} numberOfLines={5}
/> />
{field.verified_at ? ( {field.verified_at ? (
<Icon <Icon
@ -45,7 +45,7 @@ const AccountInformationFields = React.memo(
size={'M'} size={'M'}
emojis={account.emojis} emojis={account.emojis}
showFullLink showFullLink
numberOfLines={3} numberOfLines={5}
/> />
</View> </View>
</View> </View>

View File

@ -123,19 +123,28 @@ const Compose: React.FC<SharedComposeProp> = ({
<HeaderLeft <HeaderLeft
type='text' type='text'
content='退出编辑' content='退出编辑'
onPress={() => onPress={() => {
Alert.alert('确认取消编辑?', '', [ if (
{ totalTextCount === 0 &&
text: '退出编辑', composeState.attachments.uploads.length === 0 &&
style: 'destructive', composeState.poll.active === false
onPress: () => navigation.goBack() ) {
}, navigation.goBack()
{ text: '继续编辑', style: 'cancel' } return
]) } else {
} Alert.alert('确认取消编辑?', '', [
{
text: '退出编辑',
style: 'destructive',
onPress: () => navigation.goBack()
},
{ text: '继续编辑', style: 'cancel' }
])
}
}}
/> />
), ),
[] [totalTextCount]
) )
const headerCenter = useCallback( const headerCenter = useCallback(
() => ( () => (

View File

@ -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 React, { useContext } from 'react'
import ComposeSpoilerInput from '@screens/Shared/Compose/SpoilerInput' import { StyleSheet, Text, View } from 'react-native'
import ComposeTextInput from '@screens/Shared/Compose/TextInput' import { Chase } from 'react-native-animated-spinkit'
import ComposeContext from '@screens/Shared/Compose//utils/createContext' 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 ComposeRootHeader: React.FC = () => {
const { composeState } = useContext(ComposeContext) const { composeState } = useContext(ComposeContext)
const localActiveIndex = useSelector(getLocalActiveIndex)
const localInstances = useSelector(getLocalInstances)
return ( 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} {composeState.spoiler.active ? <ComposeSpoilerInput /> : null}
<ComposeTextInput /> <ComposeTextInput />
</> </>
) )
} }
const styles = StyleSheet.create({
postingAs: {
marginHorizontal: StyleConstants.Spacing.Global.PagePadding,
marginTop: StyleConstants.Spacing.S
},
postingAsText: {
...StyleConstants.FontStyle.S
}
})
export default ComposeRootHeader export default ComposeRootHeader

View File

@ -6,6 +6,7 @@ import {
Image, Image,
Platform, Platform,
Share, Share,
StatusBar,
StyleSheet, StyleSheet,
Text Text
} from 'react-native' } from 'react-native'
@ -57,20 +58,23 @@ const ScreenSharedImagesViewer: React.FC<SharedImagesViewerProp> = ({
const component = useCallback( const component = useCallback(
() => ( () => (
<ImageViewer <>
index={initialIndex} <StatusBar barStyle='light-content' />
imageUrls={imageUrls} <ImageViewer
pageAnimateTime={250} index={initialIndex}
enableSwipeDown={true} imageUrls={imageUrls}
useNativeDriver={true} pageAnimateTime={250}
swipeDownThreshold={100} enableSwipeDown={true}
renderIndicator={() => <></>} useNativeDriver={true}
saveToLocalByLongPress={false} swipeDownThreshold={100}
onSwipeDown={() => navigation.goBack()} renderIndicator={() => <></>}
style={{ flex: 1, marginBottom: 44 + safeAreaInsets.bottom }} saveToLocalByLongPress={false}
onChange={index => index !== undefined && setCurrentIndex(index)} onSwipeDown={() => navigation.goBack()}
renderImage={props => <TheImage {...props} imageUrls={imageUrls} />} 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]) }, [currentIndex])
return ( return (
<Stack.Navigator screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}> <Stack.Navigator
screenOptions={{ headerHideShadow: true, headerTopInsetEnabled: false }}
>
<Stack.Screen <Stack.Screen
name='Screen-Shared-ImagesViewer-Root' name='Screen-Shared-ImagesViewer-Root'
component={component} component={component}

View File

@ -150,7 +150,7 @@ const ScreenSharedSearch: React.FC<Props> = ({ searchTerm }) => {
<ComponentAccount <ComponentAccount
account={item} account={item}
onPress={() => { onPress={() => {
navigation.push('Screen-Shared-Account', { item }) navigation.push('Screen-Shared-Account', { account: item })
}} }}
/> />
) )

View File

@ -201,16 +201,27 @@ const sharedScreens = (
// https://github.com/react-navigation/react-navigation/issues/6746#issuecomment-583897436 // https://github.com/react-navigation/react-navigation/issues/6746#issuecomment-583897436
headerCenter: () => ( headerCenter: () => (
<View style={styles.searchBar}> <View style={styles.searchBar}>
<Text <TextInput
style={{ ...StyleConstants.FontStyle.M, color: theme.primary }} editable={false}
> children={
<Text
</Text> style={[
styles.textInput,
{
color: theme.primary
}
]}
children='搜索'
/>
}
/>
<TextInput <TextInput
style={[ style={[
styles.textInput, styles.textInput,
{ {
color: theme.primary flex: 1,
color: theme.primary,
paddingLeft: StyleConstants.Spacing.XS
} }
]} ]}
autoFocus autoFocus
@ -251,10 +262,7 @@ const styles = StyleSheet.create({
alignItems: 'center' alignItems: 'center'
}, },
textInput: { textInput: {
...StyleConstants.FontStyle.M, fontSize: StyleConstants.Font.Size.M
paddingLeft: StyleConstants.Spacing.XS,
marginBottom:
(StyleConstants.Font.LineHeight.M - StyleConstants.Font.Size.M) / 2
} }
}) })

View File

@ -3,6 +3,7 @@ import analytics from '@components/analytics'
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@root/store' import { RootState } from '@root/store'
import * as AuthSession from 'expo-auth-session' import * as AuthSession from 'expo-auth-session'
import * as Localization from 'expo-localization'
export type InstanceLocal = { export type InstanceLocal = {
appData: { appData: {
@ -11,6 +12,7 @@ export type InstanceLocal = {
} }
url: string url: string
token: string token: string
uri: Mastodon.Instance['uri']
account: { account: {
id: Mastodon.Account['id'] id: Mastodon.Account['id']
preferences: Mastodon.Preferences preferences: Mastodon.Preferences
@ -50,10 +52,12 @@ export const localAddInstance = createAsyncThunk(
async ({ async ({
url, url,
token, token,
uri,
appData appData
}: { }: {
url: InstanceLocal['url'] url: InstanceLocal['url']
token: InstanceLocal['token'] token: InstanceLocal['token']
uri: Mastodon.Instance['uri']
appData: InstanceLocal['appData'] appData: InstanceLocal['appData']
}): Promise<{ type: 'add' | 'overwrite'; data: InstanceLocal }> => { }): Promise<{ type: 'add' | 'overwrite'; data: InstanceLocal }> => {
const { store } = require('@root/store') const { store } = require('@root/store')
@ -101,6 +105,7 @@ export const localAddInstance = createAsyncThunk(
appData, appData,
url, url,
token, token,
uri,
account: { account: {
id, id,
preferences preferences
@ -159,7 +164,7 @@ export const instancesInitialState: InstancesState = {
instances: [] instances: []
}, },
remote: { remote: {
url: 'm.cmx.im' url: Localization.locale.includes('zh') ? 'm.cmx.im' : 'mastodon.social'
} }
} }

View File

@ -1,16 +1,19 @@
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit' import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@root/store' import { RootState } from '@root/store'
import * as Analytics from 'expo-firebase-analytics' import * as Analytics from 'expo-firebase-analytics'
import * as Localization from 'expo-localization'
export const supportedLngs = ['zh-Hans', 'en']
export type SettingsState = { export type SettingsState = {
language: 'zh-CN' | 'en-US' | undefined language: 'zh-Hans' | 'en'
theme: 'light' | 'dark' | 'auto' theme: 'light' | 'dark' | 'auto'
browser: 'internal' | 'external' browser: 'internal' | 'external'
analytics: boolean analytics: boolean
} }
export const settingsInitialState = { export const settingsInitialState = {
language: undefined, language: Localization.locale,
theme: 'auto', theme: 'auto',
browser: 'internal', browser: 'internal',
analytics: true analytics: true