mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Updates
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { InstanceLocal, localAddInstance } from '@utils/slices/instancesSlice'
|
||||
import * as AuthSession from 'expo-auth-session'
|
||||
import Constants from 'expo-constants'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useQueryClient } from 'react-query'
|
||||
import { useDispatch } from 'react-redux'
|
||||
@ -16,17 +15,9 @@ export interface Props {
|
||||
|
||||
const InstanceAuth = React.memo(
|
||||
({ instanceDomain, instanceUri, appData, goBack }: Props) => {
|
||||
let redirectUri: string
|
||||
switch (Constants.manifest.releaseChannel) {
|
||||
case 'production':
|
||||
case 'staging':
|
||||
case 'testing':
|
||||
redirectUri = 'tooot://expo-auth-session'
|
||||
break
|
||||
default:
|
||||
redirectUri = 'exp://127.0.0.1:19000'
|
||||
break
|
||||
}
|
||||
|
||||
const redirectUri = AuthSession.makeRedirectUri({ useProxy: false })
|
||||
|
||||
const navigation = useNavigation()
|
||||
const queryClient = useQueryClient()
|
||||
const dispatch = useDispatch()
|
||||
|
@ -23,11 +23,11 @@ const Names: React.FC<{ accounts: Mastodon.Account[] }> = ({ accounts }) => {
|
||||
return (
|
||||
<Text numberOfLines={1}>
|
||||
<Text style={[styles.namesLeading, { color: theme.secondary }]}>
|
||||
{t('shared.header.conversation.withAccounts')}{' '}
|
||||
{t('shared.header.conversation.withAccounts')}
|
||||
</Text>
|
||||
{accounts.map((account, index) => (
|
||||
<Text key={account.id} numberOfLines={1}>
|
||||
{index !== 0 ? ', ' : undefined}
|
||||
{index !== 0 ? t('common:separator') : undefined}
|
||||
<ParseEmojis
|
||||
content={account.display_name || account.username}
|
||||
emojis={account.emojis}
|
||||
|
@ -15,5 +15,6 @@ export default {
|
||||
error: {
|
||||
message: '{{function}} failed, please retry'
|
||||
}
|
||||
}
|
||||
},
|
||||
separator: ', '
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
import { store } from '@root/store'
|
||||
import { getSettingsLanguage, supportedLngs } from '@utils/slices/settingsSlice'
|
||||
import i18next from 'i18next'
|
||||
import i18n from 'i18next'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
|
||||
import en from '@root/i18n/en/_all'
|
||||
import zh_Hans from '@root/i18n/zh-Hans/_all'
|
||||
|
||||
i18next.use(initReactI18next).init({
|
||||
lng: getSettingsLanguage(store.getState()),
|
||||
i18n.use(initReactI18next).init({
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
supportedLngs: supportedLngs,
|
||||
|
||||
ns: ['common'],
|
||||
defaultNS: 'common',
|
||||
@ -23,7 +20,11 @@ i18next.use(initReactI18next).init({
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false
|
||||
}
|
||||
},
|
||||
react: {
|
||||
useSuspense: false
|
||||
},
|
||||
debug: true
|
||||
})
|
||||
|
||||
export default i18next
|
||||
export default i18n
|
||||
|
@ -15,5 +15,6 @@ export default {
|
||||
error: {
|
||||
message: '{{function}}失败,请重试'
|
||||
}
|
||||
}
|
||||
},
|
||||
separator: ','
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ const ScreenLocal = React.memo(
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Stack.Navigator
|
||||
<Stack.Navigator
|
||||
screenOptions={{
|
||||
headerLeft: () => null,
|
||||
headerRight: () => (
|
||||
|
@ -1,310 +1,23 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Button from '@components/Button'
|
||||
import haptics from '@components/haptics'
|
||||
import Icon from '@components/Icon'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { persistor } from '@root/store'
|
||||
import {
|
||||
getLocalActiveIndex,
|
||||
getLocalInstances
|
||||
} from '@utils/slices/instancesSlice'
|
||||
import {
|
||||
changeAnalytics,
|
||||
changeBrowser,
|
||||
changeLanguage,
|
||||
changeTheme,
|
||||
getSettingsAnalytics,
|
||||
getSettingsBrowser,
|
||||
getSettingsLanguage,
|
||||
getSettingsTheme
|
||||
} from '@utils/slices/settingsSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import Constants from 'expo-constants'
|
||||
import * as Linking from 'expo-linking'
|
||||
import * as StoreReview from 'expo-store-review'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import { CacheManager } from 'react-native-expo-image-cache'
|
||||
import React from 'react'
|
||||
import { ScrollView } from 'react-native-gesture-handler'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const DevDebug: React.FC = () => {
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||
const localInstances = useSelector(getLocalInstances)
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={'Local active index'}
|
||||
content={typeof localActiveIndex + ' - ' + localActiveIndex}
|
||||
onPress={() => {}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={'Saved local instances'}
|
||||
content={localInstances.length.toString()}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
options: localInstances
|
||||
.map(instance => {
|
||||
return instance.url + ': ' + instance.account.id
|
||||
})
|
||||
.concat(['Cancel']),
|
||||
cancelButtonIndex: localInstances.length
|
||||
},
|
||||
buttonIndex => {}
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={'Purge secure storage'}
|
||||
style={{
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2,
|
||||
marginBottom: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}}
|
||||
destructive
|
||||
onPress={() => persistor.purge()}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={'Crash test'}
|
||||
style={{
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2,
|
||||
marginBottom: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}}
|
||||
destructive
|
||||
onPress={() => {
|
||||
throw new Error('Testing crash')
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
import SettingsAnalytics from './Settings/Analytics'
|
||||
import SettingsApp from './Settings/App'
|
||||
import SettingsDev from './Settings/Dev'
|
||||
import SettingsTooot from './Settings/Tooot'
|
||||
|
||||
const ScreenMeSettings: React.FC = () => {
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const { t, i18n } = useTranslation('meSettings')
|
||||
const { setTheme, theme } = useTheme()
|
||||
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||
const settingsTheme = useSelector(getSettingsTheme)
|
||||
const settingsBrowser = useSelector(getSettingsBrowser)
|
||||
const settingsAnalytics = useSelector(getSettingsAnalytics)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const [cacheSize, setCacheSize] = useState<number>()
|
||||
useEffect(() => {
|
||||
CacheManager.getCacheSize().then(size => setCacheSize(size))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.language.heading')}
|
||||
content={t(`content.language.options.${settingsLanguage}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
const availableLanguages = Object.keys(
|
||||
i18n.services.resourceStore.data
|
||||
)
|
||||
const options = availableLanguages
|
||||
.map(language => t(`content.language.options.${language}`))
|
||||
.concat(t('content.language.options.cancel'))
|
||||
<SettingsApp />
|
||||
<SettingsTooot />
|
||||
<SettingsAnalytics />
|
||||
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.language.heading'),
|
||||
options,
|
||||
cancelButtonIndex: options.length - 1
|
||||
},
|
||||
buttonIndex => {
|
||||
if (buttonIndex < options.length) {
|
||||
analytics('settings_language_press', {
|
||||
current: i18n.language,
|
||||
new: availableLanguages[buttonIndex]
|
||||
})
|
||||
haptics('Success')
|
||||
// @ts-ignore
|
||||
dispatch(changeLanguage(availableLanguages[buttonIndex]))
|
||||
i18n.changeLanguage(availableLanguages[buttonIndex])
|
||||
}
|
||||
}
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.theme.heading')}
|
||||
content={t(`content.theme.options.${settingsTheme}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.theme.heading'),
|
||||
options: [
|
||||
t('content.theme.options.auto'),
|
||||
t('content.theme.options.light'),
|
||||
t('content.theme.options.dark'),
|
||||
t('content.theme.options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 3
|
||||
},
|
||||
buttonIndex => {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'auto'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('auto'))
|
||||
break
|
||||
case 1:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'light'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('light'))
|
||||
setTheme('light')
|
||||
break
|
||||
case 2:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'dark'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('dark'))
|
||||
setTheme('dark')
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.browser.heading')}
|
||||
content={t(`content.browser.options.${settingsBrowser}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.browser.heading'),
|
||||
options: [
|
||||
t('content.browser.options.internal'),
|
||||
t('content.browser.options.external'),
|
||||
t('content.browser.options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
buttonIndex => {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
analytics('settings_browser_press', {
|
||||
current: settingsBrowser,
|
||||
new: 'internal'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeBrowser('internal'))
|
||||
break
|
||||
case 1:
|
||||
analytics('settings_browser_press', {
|
||||
current: settingsBrowser,
|
||||
new: 'external'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeBrowser('external'))
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
</MenuContainer>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.cache.heading')}
|
||||
content={
|
||||
cacheSize ? prettyBytes(cacheSize) : t('content.cache.empty')
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={async () => {
|
||||
analytics('settings_cache_press', {
|
||||
size: cacheSize ? prettyBytes(cacheSize) : 'empty'
|
||||
})
|
||||
await CacheManager.clearCache()
|
||||
haptics('Success')
|
||||
setCacheSize(0)
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.support.heading')}
|
||||
content={
|
||||
<Icon
|
||||
name='Heart'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={theme.red}
|
||||
/>
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_support_press')
|
||||
Linking.openURL('https://www.patreon.com/xmflsct')
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.review.heading')}
|
||||
content={
|
||||
<Icon
|
||||
name='Star'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color='#FF9500'
|
||||
/>
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_review_press')
|
||||
StoreReview.isAvailableAsync().then(() =>
|
||||
StoreReview.requestReview()
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.analytics.heading')}
|
||||
description={t('content.analytics.description')}
|
||||
switchValue={settingsAnalytics}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(changeAnalytics(!settingsAnalytics))
|
||||
}
|
||||
/>
|
||||
<Text style={[styles.version, { color: theme.secondary }]}>
|
||||
{t('content.version', { version: Constants.manifest.version })}
|
||||
</Text>
|
||||
</MenuContainer>
|
||||
|
||||
{__DEV__ || Constants.manifest.releaseChannel === 'testing' ? (
|
||||
<DevDebug />
|
||||
{__DEV__ || Constants.manifest.releaseChannel?.includes('testing') ? (
|
||||
<SettingsDev />
|
||||
) : null}
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
version: {
|
||||
textAlign: 'center',
|
||||
...StyleConstants.FontStyle.S,
|
||||
marginTop: StyleConstants.Spacing.M
|
||||
}
|
||||
})
|
||||
|
||||
export default ScreenMeSettings
|
||||
|
46
src/screens/Me/Settings/Analytics.tsx
Normal file
46
src/screens/Me/Settings/Analytics.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import {
|
||||
changeAnalytics,
|
||||
getSettingsAnalytics
|
||||
} from '@utils/slices/settingsSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import Constants from 'expo-constants'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const SettingsAnalytics: React.FC = () => {
|
||||
const dispatch = useDispatch()
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation('meSettings')
|
||||
|
||||
const settingsAnalytics = useSelector(getSettingsAnalytics)
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.analytics.heading')}
|
||||
description={t('content.analytics.description')}
|
||||
switchValue={settingsAnalytics}
|
||||
switchOnValueChange={() =>
|
||||
dispatch(changeAnalytics(!settingsAnalytics))
|
||||
}
|
||||
/>
|
||||
<Text style={[styles.version, { color: theme.secondary }]}>
|
||||
{t('content.version', { version: Constants.manifest.version })}
|
||||
</Text>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
version: {
|
||||
textAlign: 'center',
|
||||
...StyleConstants.FontStyle.S,
|
||||
marginTop: StyleConstants.Spacing.M
|
||||
}
|
||||
})
|
||||
|
||||
export default SettingsAnalytics
|
175
src/screens/Me/Settings/App.tsx
Normal file
175
src/screens/Me/Settings/App.tsx
Normal file
@ -0,0 +1,175 @@
|
||||
import analytics from '@components/analytics'
|
||||
import haptics from '@components/haptics'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import i18n from '@root/i18n/i18n'
|
||||
import {
|
||||
changeBrowser,
|
||||
changeLanguage,
|
||||
changeTheme,
|
||||
getSettingsLanguage,
|
||||
getSettingsTheme,
|
||||
getSettingsBrowser
|
||||
} from '@utils/slices/settingsSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { CacheManager } from 'react-native-expo-image-cache'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const SettingsApp: React.FC = () => {
|
||||
const dispatch = useDispatch()
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const { setTheme } = useTheme()
|
||||
const { t } = useTranslation('meSettings')
|
||||
|
||||
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||
const settingsTheme = useSelector(getSettingsTheme)
|
||||
const settingsBrowser = useSelector(getSettingsBrowser)
|
||||
|
||||
const [cacheSize, setCacheSize] = useState<number>()
|
||||
useEffect(() => {
|
||||
CacheManager.getCacheSize().then(size => setCacheSize(size))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.language.heading')}
|
||||
content={t(`content.language.options.${settingsLanguage}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
const availableLanguages = Object.keys(
|
||||
i18n.services.resourceStore.data
|
||||
)
|
||||
const options = availableLanguages
|
||||
.map(language => t(`content.language.options.${language}`))
|
||||
.concat(t('content.language.options.cancel'))
|
||||
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.language.heading'),
|
||||
options,
|
||||
cancelButtonIndex: options.length - 1
|
||||
},
|
||||
buttonIndex => {
|
||||
if (buttonIndex < options.length) {
|
||||
analytics('settings_language_press', {
|
||||
current: i18n.language,
|
||||
new: availableLanguages[buttonIndex]
|
||||
})
|
||||
haptics('Success')
|
||||
// @ts-ignore
|
||||
dispatch(changeLanguage(availableLanguages[buttonIndex]))
|
||||
i18n.changeLanguage(availableLanguages[buttonIndex])
|
||||
}
|
||||
}
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.theme.heading')}
|
||||
content={t(`content.theme.options.${settingsTheme}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.theme.heading'),
|
||||
options: [
|
||||
t('content.theme.options.auto'),
|
||||
t('content.theme.options.light'),
|
||||
t('content.theme.options.dark'),
|
||||
t('content.theme.options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 3
|
||||
},
|
||||
buttonIndex => {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'auto'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('auto'))
|
||||
break
|
||||
case 1:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'light'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('light'))
|
||||
setTheme('light')
|
||||
break
|
||||
case 2:
|
||||
analytics('settings_appearance_press', {
|
||||
current: settingsTheme,
|
||||
new: 'dark'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeTheme('dark'))
|
||||
setTheme('dark')
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.browser.heading')}
|
||||
content={t(`content.browser.options.${settingsBrowser}`)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('content.browser.heading'),
|
||||
options: [
|
||||
t('content.browser.options.internal'),
|
||||
t('content.browser.options.external'),
|
||||
t('content.browser.options.cancel')
|
||||
],
|
||||
cancelButtonIndex: 2
|
||||
},
|
||||
buttonIndex => {
|
||||
switch (buttonIndex) {
|
||||
case 0:
|
||||
analytics('settings_browser_press', {
|
||||
current: settingsBrowser,
|
||||
new: 'internal'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeBrowser('internal'))
|
||||
break
|
||||
case 1:
|
||||
analytics('settings_browser_press', {
|
||||
current: settingsBrowser,
|
||||
new: 'external'
|
||||
})
|
||||
haptics('Success')
|
||||
dispatch(changeBrowser('external'))
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.cache.heading')}
|
||||
content={cacheSize ? prettyBytes(cacheSize) : t('content.cache.empty')}
|
||||
iconBack='ChevronRight'
|
||||
onPress={async () => {
|
||||
analytics('settings_cache_press', {
|
||||
size: cacheSize ? prettyBytes(cacheSize) : 'empty'
|
||||
})
|
||||
await CacheManager.clearCache()
|
||||
haptics('Success')
|
||||
setCacheSize(0)
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default SettingsApp
|
69
src/screens/Me/Settings/Dev.tsx
Normal file
69
src/screens/Me/Settings/Dev.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import Button from '@components/Button'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { persistor } from '@root/store'
|
||||
import {
|
||||
getLocalActiveIndex,
|
||||
getLocalInstances
|
||||
} from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import React from 'react'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
const SettingsDev: React.FC = () => {
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||
const localInstances = useSelector(getLocalInstances)
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={'Local active index'}
|
||||
content={typeof localActiveIndex + ' - ' + localActiveIndex}
|
||||
onPress={() => {}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={'Saved local instances'}
|
||||
content={localInstances.length.toString()}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() =>
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
options: localInstances
|
||||
.map(instance => {
|
||||
return instance.url + ': ' + instance.account.id
|
||||
})
|
||||
.concat(['Cancel']),
|
||||
cancelButtonIndex: localInstances.length
|
||||
},
|
||||
buttonIndex => {}
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={'Purge secure storage'}
|
||||
style={{
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2,
|
||||
marginBottom: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}}
|
||||
destructive
|
||||
onPress={() => persistor.purge()}
|
||||
/>
|
||||
<Button
|
||||
type='text'
|
||||
content={'Crash test'}
|
||||
style={{
|
||||
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2,
|
||||
marginBottom: StyleConstants.Spacing.Global.PagePadding * 2
|
||||
}}
|
||||
destructive
|
||||
onPress={() => {
|
||||
throw new Error('Testing crash')
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default SettingsDev
|
84
src/screens/Me/Settings/Tooot.tsx
Normal file
84
src/screens/Me/Settings/Tooot.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
import analytics from '@components/analytics'
|
||||
import Icon from '@components/Icon'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { useSearchQuery } from '@utils/queryHooks/search'
|
||||
import { getLocalActiveIndex } from '@utils/slices/instancesSlice'
|
||||
import { StyleConstants } from '@utils/styles/constants'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Linking from 'expo-linking'
|
||||
import * as StoreReview from 'expo-store-review'
|
||||
import * as WebBrowser from 'expo-web-browser'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
const SettingsTooot: React.FC = () => {
|
||||
const localActiveIndex = useSelector(getLocalActiveIndex)
|
||||
const navigation = useNavigation()
|
||||
const { theme } = useTheme()
|
||||
const { t } = useTranslation('meSettings')
|
||||
|
||||
const { isLoading, data } = useSearchQuery({
|
||||
term: '@tooot@xmflsct.com',
|
||||
options: { enabled: localActiveIndex !== null }
|
||||
})
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<MenuRow
|
||||
title={t('content.support.heading')}
|
||||
content={
|
||||
<Icon
|
||||
name='Heart'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={theme.red}
|
||||
/>
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_support_press')
|
||||
Linking.openURL('https://www.patreon.com/xmflsct')
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('content.review.heading')}
|
||||
content={
|
||||
<Icon name='Star' size={StyleConstants.Font.Size.M} color='#FF9500' />
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
analytics('settings_review_press')
|
||||
StoreReview.isAvailableAsync().then(() => StoreReview.requestReview())
|
||||
}}
|
||||
/>
|
||||
<MenuRow
|
||||
title={'联系 tooot'}
|
||||
loading={isLoading}
|
||||
content={
|
||||
<Icon
|
||||
name='Mail'
|
||||
size={StyleConstants.Font.Size.M}
|
||||
color={theme.secondary}
|
||||
/>
|
||||
}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
const foundAccounts = data?.accounts.filter(
|
||||
account => account.acct === 'tooot@xmflsct.com'
|
||||
)
|
||||
if (foundAccounts?.length === 1) {
|
||||
navigation.navigate('Screen-Shared-Compose', {
|
||||
type: 'conversation',
|
||||
accts: [foundAccounts[0].acct]
|
||||
})
|
||||
} else {
|
||||
WebBrowser.openBrowserAsync('https://social.xmflsct.com/@tooot')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default SettingsTooot
|
@ -128,7 +128,7 @@ const AccountAttachments = React.memo(
|
||||
<Animated.View style={[styles.base, styleContainer]}>
|
||||
<FlatList
|
||||
horizontal
|
||||
data={flattenData.splice(0, 4)}
|
||||
data={flattenData.filter(status => !status.sensitive).splice(0, 4)}
|
||||
renderItem={renderItem}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
/>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import ComponentAccount from '@components/Account'
|
||||
import analytics from '@components/analytics'
|
||||
import ComponentHashtag from '@components/Hashtag'
|
||||
import ComponentSeparator from '@components/Separator'
|
||||
import TimelineDefault from '@components/Timelines/Timeline/Default'
|
||||
|
@ -12,7 +12,7 @@ import { persistReducer, persistStore } from 'redux-persist'
|
||||
|
||||
const secureStorage = createSecureStore()
|
||||
|
||||
const prefix = 'mastodon_app'
|
||||
const prefix = 'ajieorjaiojwoirjwe'
|
||||
|
||||
const contextsPersistConfig = {
|
||||
key: 'contexts',
|
||||
|
@ -1,22 +1,12 @@
|
||||
import client from '@api/client'
|
||||
import { AxiosError } from 'axios'
|
||||
import Constants from 'expo-constants'
|
||||
import * as AuthSession from 'expo-auth-session'
|
||||
import { useQuery, UseQueryOptions } from 'react-query'
|
||||
|
||||
export type QueryKey = ['Apps', { instanceDomain?: string }]
|
||||
|
||||
const queryFunction = ({ queryKey }: { queryKey: QueryKey }) => {
|
||||
let redirectUri: string
|
||||
switch (Constants.manifest.releaseChannel) {
|
||||
case 'production':
|
||||
case 'staging':
|
||||
case 'testing':
|
||||
redirectUri = 'tooot://expo-auth-session'
|
||||
break
|
||||
default:
|
||||
redirectUri = 'exp://127.0.0.1:19000'
|
||||
break
|
||||
}
|
||||
const redirectUri = AuthSession.makeRedirectUri({ useProxy: false })
|
||||
|
||||
const { instanceDomain } = queryKey[1]
|
||||
|
||||
|
@ -38,7 +38,7 @@ const contextsSlice = createSlice({
|
||||
initialState: contextsInitialState as ContextsState,
|
||||
reducers: {
|
||||
updateStoreReview: (state, action: PayloadAction<1>) => {
|
||||
if (Constants.manifest.releaseChannel === 'production') {
|
||||
if (Constants.manifest.releaseChannel?.includes('production')) {
|
||||
state.storeReview.current = state.storeReview.current + action.payload
|
||||
if (state.storeReview.current === state.storeReview.context) {
|
||||
StoreReview.isAvailableAsync().then(() => StoreReview.requestReview())
|
||||
|
@ -3,8 +3,6 @@ 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-Hans' | 'en'
|
||||
theme: 'light' | 'dark' | 'auto'
|
||||
|
Reference in New Issue
Block a user