mirror of https://github.com/tooot-app/app
Theme done
This commit is contained in:
parent
24d0681c9e
commit
1493e20962
35
App.tsx
35
App.tsx
|
@ -28,22 +28,25 @@ setConsole({
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<AppearanceProvider>
|
<AppearanceProvider>
|
||||||
<ThemeManager>
|
<ReactQueryCacheProvider queryCache={queryCache}>
|
||||||
<ReactQueryCacheProvider queryCache={queryCache}>
|
<Provider store={store}>
|
||||||
<Provider store={store}>
|
<PersistGate persistor={persistor}>
|
||||||
<PersistGate persistor={persistor}>
|
{bootstrapped => {
|
||||||
{bootstrapped => {
|
if (bootstrapped) {
|
||||||
if (bootstrapped) {
|
console.log('Bootstrapped!')
|
||||||
require('src/i18n/i18n')
|
require('src/i18n/i18n')
|
||||||
return <Index />
|
return (
|
||||||
} else {
|
<ThemeManager>
|
||||||
return <></>
|
<Index />
|
||||||
}
|
</ThemeManager>
|
||||||
}}
|
)
|
||||||
</PersistGate>
|
} else {
|
||||||
</Provider>
|
return <></>
|
||||||
</ReactQueryCacheProvider>
|
}
|
||||||
</ThemeManager>
|
}}
|
||||||
|
</PersistGate>
|
||||||
|
</Provider>
|
||||||
|
</ReactQueryCacheProvider>
|
||||||
</AppearanceProvider>
|
</AppearanceProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
116
src/Index.tsx
116
src/Index.tsx
|
@ -4,6 +4,7 @@ import { NavigationContainer } from '@react-navigation/native'
|
||||||
import { enableScreens } from 'react-native-screens'
|
import { enableScreens } from 'react-native-screens'
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { StatusBar } from 'react-native'
|
||||||
import Toast from 'react-native-toast-message'
|
import Toast from 'react-native-toast-message'
|
||||||
import { Feather } from '@expo/vector-icons'
|
import { Feather } from '@expo/vector-icons'
|
||||||
|
|
||||||
|
@ -30,65 +31,72 @@ export type RootStackParamList = {
|
||||||
|
|
||||||
export const Index: React.FC = () => {
|
export const Index: React.FC = () => {
|
||||||
const { mode, theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
|
enum barStyle {
|
||||||
|
light = 'dark-content',
|
||||||
|
dark = 'light-content'
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainer theme={themes[mode]}>
|
<>
|
||||||
<Tab.Navigator
|
<StatusBar barStyle={barStyle[mode]} />
|
||||||
screenOptions={({ route }) => ({
|
<NavigationContainer theme={themes[mode]}>
|
||||||
tabBarIcon: ({ focused, color, size }) => {
|
<Tab.Navigator
|
||||||
let name: string
|
screenOptions={({ route }) => ({
|
||||||
switch (route.name) {
|
tabBarIcon: ({ focused, color, size }) => {
|
||||||
case 'Screen-Local':
|
let name: string
|
||||||
name = 'home'
|
switch (route.name) {
|
||||||
break
|
case 'Screen-Local':
|
||||||
case 'Screen-Public':
|
name = 'home'
|
||||||
name = 'globe'
|
break
|
||||||
break
|
case 'Screen-Public':
|
||||||
case 'Screen-Post':
|
name = 'globe'
|
||||||
name = 'plus'
|
break
|
||||||
break
|
case 'Screen-Post':
|
||||||
case 'Screen-Notifications':
|
name = 'plus'
|
||||||
name = 'bell'
|
break
|
||||||
break
|
case 'Screen-Notifications':
|
||||||
case 'Screen-Me':
|
name = 'bell'
|
||||||
name = focused ? 'smile' : 'meh'
|
break
|
||||||
break
|
case 'Screen-Me':
|
||||||
default:
|
name = focused ? 'smile' : 'meh'
|
||||||
name = 'alert-octagon'
|
break
|
||||||
break
|
default:
|
||||||
}
|
name = 'alert-octagon'
|
||||||
return <Feather name={name} size={size} color={color} />
|
break
|
||||||
}
|
}
|
||||||
})}
|
return <Feather name={name} size={size} color={color} />
|
||||||
tabBarOptions={{
|
|
||||||
activeTintColor: theme.primary,
|
|
||||||
inactiveTintColor: theme.secondary,
|
|
||||||
showLabel: false
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Tab.Screen name='Screen-Local' component={ScreenLocal} />
|
|
||||||
<Tab.Screen name='Screen-Public' component={ScreenPublic} />
|
|
||||||
<Tab.Screen
|
|
||||||
name='Screen-Post'
|
|
||||||
listeners={({ navigation, route }) => ({
|
|
||||||
tabPress: e => {
|
|
||||||
e.preventDefault()
|
|
||||||
navigation.navigate(getCurrentTab(navigation), {
|
|
||||||
screen: 'Screen-Shared-Compose'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
tabBarOptions={{
|
||||||
|
activeTintColor: theme.primary,
|
||||||
|
inactiveTintColor: theme.secondary,
|
||||||
|
showLabel: false
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{() => <></>}
|
<Tab.Screen name='Screen-Local' component={ScreenLocal} />
|
||||||
</Tab.Screen>
|
<Tab.Screen name='Screen-Public' component={ScreenPublic} />
|
||||||
<Tab.Screen
|
<Tab.Screen
|
||||||
name='Screen-Notifications'
|
name='Screen-Post'
|
||||||
component={ScreenNotifications}
|
listeners={({ navigation, route }) => ({
|
||||||
/>
|
tabPress: e => {
|
||||||
<Tab.Screen name='Screen-Me' component={ScreenMe} />
|
e.preventDefault()
|
||||||
</Tab.Navigator>
|
navigation.navigate(getCurrentTab(navigation), {
|
||||||
|
screen: 'Screen-Shared-Compose'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{() => <></>}
|
||||||
|
</Tab.Screen>
|
||||||
|
<Tab.Screen
|
||||||
|
name='Screen-Notifications'
|
||||||
|
component={ScreenNotifications}
|
||||||
|
/>
|
||||||
|
<Tab.Screen name='Screen-Me' component={ScreenMe} />
|
||||||
|
</Tab.Navigator>
|
||||||
|
|
||||||
<Toast ref={(ref: any) => Toast.setRef(ref)} config={toastConfig} />
|
<Toast ref={(ref: any) => Toast.setRef(ref)} config={toastConfig} />
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ export interface Props {
|
||||||
|
|
||||||
const Timelines: React.FC<Props> = ({ name, content }) => {
|
const Timelines: React.FC<Props> = ({ name, content }) => {
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
const { theme } = useTheme()
|
const { mode, theme } = useTheme()
|
||||||
const localRegistered = useSelector(getLocalUrl)
|
const localRegistered = useSelector(getLocalUrl)
|
||||||
const publicDomain = useSelector(getRemoteUrl)
|
const publicDomain = useSelector(getRemoteUrl)
|
||||||
const [segment, setSegment] = useState(0)
|
const [segment, setSegment] = useState(0)
|
||||||
|
@ -107,6 +107,7 @@ const Timelines: React.FC<Props> = ({ name, content }) => {
|
||||||
headerCenter: () => (
|
headerCenter: () => (
|
||||||
<View style={styles.segmentsContainer}>
|
<View style={styles.segmentsContainer}>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
|
appearance={mode}
|
||||||
values={[content[0].title, content[1].title]}
|
values={[content[0].title, content[1].title]}
|
||||||
selectedIndex={segment}
|
selectedIndex={segment}
|
||||||
onChange={onChangeSegment}
|
onChange={onChangeSegment}
|
||||||
|
|
|
@ -88,6 +88,7 @@ const TimelineDefault: React.FC<Props> = ({ item, queryKey }) => {
|
||||||
emojis={actualStatus.account.emojis}
|
emojis={actualStatus.account.emojis}
|
||||||
account={actualStatus.account.acct}
|
account={actualStatus.account.acct}
|
||||||
created_at={item.created_at}
|
created_at={item.created_at}
|
||||||
|
visibility={item.visibility}
|
||||||
application={item.application}
|
application={item.application}
|
||||||
/>
|
/>
|
||||||
{/* Can pass toot info to next page to speed up performance */}
|
{/* Can pass toot info to next page to speed up performance */}
|
||||||
|
|
|
@ -98,6 +98,7 @@ export interface Props {
|
||||||
emojis?: Mastodon.Emoji[]
|
emojis?: Mastodon.Emoji[]
|
||||||
account: string
|
account: string
|
||||||
created_at: string
|
created_at: string
|
||||||
|
visibility: Mastodon.Status['visibility']
|
||||||
application?: Mastodon.Application
|
application?: Mastodon.Application
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +110,7 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
emojis,
|
emojis,
|
||||||
account,
|
account,
|
||||||
created_at,
|
created_at,
|
||||||
|
visibility,
|
||||||
application
|
application
|
||||||
}) => {
|
}) => {
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
@ -197,6 +199,14 @@ const HeaderDefault: React.FC<Props> = ({
|
||||||
{since}
|
{since}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
{visibility === 'private' && (
|
||||||
|
<Feather
|
||||||
|
name='lock'
|
||||||
|
size={constants.FONT_SIZE_S}
|
||||||
|
color={theme.secondary}
|
||||||
|
style={styles.visibility}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{application && application.name !== 'Web' && (
|
{application && application.name !== 'Web' && (
|
||||||
<View>
|
<View>
|
||||||
<Text
|
<Text
|
||||||
|
@ -292,12 +302,16 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
meta: {
|
meta: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
marginTop: constants.SPACING_XS,
|
marginTop: constants.SPACING_XS,
|
||||||
marginBottom: constants.SPACING_S
|
marginBottom: constants.SPACING_S
|
||||||
},
|
},
|
||||||
created_at: {
|
created_at: {
|
||||||
fontSize: constants.FONT_SIZE_S
|
fontSize: constants.FONT_SIZE_S
|
||||||
},
|
},
|
||||||
|
visibility: {
|
||||||
|
marginLeft: constants.SPACING_S
|
||||||
|
},
|
||||||
application: {
|
application: {
|
||||||
fontSize: constants.FONT_SIZE_S,
|
fontSize: constants.FONT_SIZE_S,
|
||||||
marginLeft: constants.SPACING_S
|
marginLeft: constants.SPACING_S
|
||||||
|
|
|
@ -9,9 +9,8 @@ import {
|
||||||
getSettingsLanguage
|
getSettingsLanguage
|
||||||
} from 'src/utils/slices/settingsSlice'
|
} from 'src/utils/slices/settingsSlice'
|
||||||
import { store } from 'src/store'
|
import { store } from 'src/store'
|
||||||
console.log(store.getState())
|
|
||||||
if (!getSettingsLanguage(store.getState())) {
|
if (!getSettingsLanguage(store.getState())) {
|
||||||
console.log('No default locale of app')
|
|
||||||
const deviceLocal = Localization.locale
|
const deviceLocal = Localization.locale
|
||||||
if (deviceLocal.startsWith('zh')) {
|
if (deviceLocal.startsWith('zh')) {
|
||||||
store.dispatch(changeLanguage('zh'))
|
store.dispatch(changeLanguage('zh'))
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
export default {
|
export default {
|
||||||
common: require('./common').default,
|
common: require('./common').default,
|
||||||
settings: require('./settings').default
|
|
||||||
|
meRoot: require('./screens/meRoot').default,
|
||||||
|
meConversations: require('./screens/meConversations').default,
|
||||||
|
meBookmarks: require('./screens/meBookmarks').default,
|
||||||
|
meFavourites: require('./screens/meFavourites').default,
|
||||||
|
meLists: require('./screens/meLists').default,
|
||||||
|
meListsList: require('./screens/meListsList').default,
|
||||||
|
meSettings: require('./screens/meSettings').default
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
export default {
|
export default {
|
||||||
|
buttons: {
|
||||||
|
cancel: '取消'
|
||||||
|
},
|
||||||
headers: {
|
headers: {
|
||||||
local: {
|
local: {
|
||||||
segments: {
|
segments: {
|
||||||
|
@ -12,20 +15,6 @@ export default {
|
||||||
right: '外站嘟嘟'
|
right: '外站嘟嘟'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
notifications: '我的通知',
|
notifications: '我的通知'
|
||||||
me: {
|
|
||||||
root: '我的长毛象',
|
|
||||||
conversations: '私信',
|
|
||||||
bookmarks: '书签',
|
|
||||||
favourites: '喜欢',
|
|
||||||
lists: {
|
|
||||||
root: '列表',
|
|
||||||
list: '列表 {{list}}'
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
root: '设置',
|
|
||||||
language: '语言'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
heading: '书签',
|
||||||
|
content: {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
heading: '私信',
|
||||||
|
content: {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
heading: '收藏',
|
||||||
|
content: {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
heading: '列表',
|
||||||
|
content: {}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
heading: '列表 {{list}}',
|
||||||
|
content: {}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
export default {
|
||||||
|
heading: '我的长毛象',
|
||||||
|
content: {
|
||||||
|
login: {},
|
||||||
|
collections: {
|
||||||
|
conversations: '$t(meConversations:heading)',
|
||||||
|
bookmarks: '$t(meBookmarks:heading)',
|
||||||
|
favourites: '$t(meFavourites:heading)',
|
||||||
|
lists: '$t(meLists:heading)'
|
||||||
|
},
|
||||||
|
settings: '$t(meSettings:heading)',
|
||||||
|
logout: {
|
||||||
|
button: '退出当前账号',
|
||||||
|
alert: {
|
||||||
|
title: '确认退出登录?',
|
||||||
|
message: '退出登录后,需要重新认证账号',
|
||||||
|
buttons: {
|
||||||
|
logout: '退出登录',
|
||||||
|
cancel: '$t(common:buttons.cancel)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
export default {
|
||||||
|
heading: '设置',
|
||||||
|
content: {
|
||||||
|
language: {
|
||||||
|
heading: '切换语言',
|
||||||
|
options: {
|
||||||
|
zh: '简体中文',
|
||||||
|
en: 'English',
|
||||||
|
cancel: '$t(common:buttons.cancel)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
heading: '颜色模式',
|
||||||
|
options: {
|
||||||
|
auto: '跟随系统',
|
||||||
|
light: '浅色模式',
|
||||||
|
dark: '深色模式',
|
||||||
|
cancel: '$t(common:buttons.cancel)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
export default {
|
|
||||||
content: {
|
|
||||||
language: {
|
|
||||||
title: '切换语言',
|
|
||||||
options: {
|
|
||||||
zh: '简体中文',
|
|
||||||
en: 'English'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -41,42 +41,42 @@ const ScreenMe: React.FC = () => {
|
||||||
name='Screen-Me-Conversations'
|
name='Screen-Me-Conversations'
|
||||||
component={ScreenMeConversations}
|
component={ScreenMeConversations}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('headers.me.conversations')
|
headerTitle: t('meConversations:heading')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Bookmarks'
|
name='Screen-Me-Bookmarks'
|
||||||
component={ScreenMeBookmarks}
|
component={ScreenMeBookmarks}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('headers.me.bookmarks')
|
headerTitle: t('meBookmarks:heading')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Favourites'
|
name='Screen-Me-Favourites'
|
||||||
component={ScreenMeFavourites}
|
component={ScreenMeFavourites}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('headers.me.favourites')
|
headerTitle: t('meFavourites:heading')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Lists'
|
name='Screen-Me-Lists'
|
||||||
component={ScreenMeLists}
|
component={ScreenMeLists}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('headers.me.lists.root')
|
headerTitle: t('meLists:heading')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Lists-List'
|
name='Screen-Me-Lists-List'
|
||||||
component={ScreenMeListsList}
|
component={ScreenMeListsList}
|
||||||
options={({ route }: any) => ({
|
options={({ route }: any) => ({
|
||||||
headerTitle: t('headers.me.lists.list', { list: route.params.title })
|
headerTitle: t('meListsList:heading', { list: route.params.title })
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name='Screen-Me-Settings'
|
name='Screen-Me-Settings'
|
||||||
component={ScreenMeSettings}
|
component={ScreenMeSettings}
|
||||||
options={{
|
options={{
|
||||||
headerTitle: t('headers.me.settings.root')
|
headerTitle: t('meSettings:heading')
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { getLocalUrl } from 'src/utils/slices/instancesSlice'
|
||||||
|
|
||||||
import Login from './Root/Login'
|
import Login from './Root/Login'
|
||||||
import MyInfo from './Root/MyInfo'
|
import MyInfo from './Root/MyInfo'
|
||||||
import MyCollections from './Root/MyCollections'
|
import Collections from './Root/Collections'
|
||||||
import Settings from './Root/Settings'
|
import Settings from './Root/Settings'
|
||||||
import Logout from './Root/Logout'
|
import Logout from './Root/Logout'
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ const ScreenMeRoot: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
{localRegistered ? <MyInfo /> : <Login />}
|
{localRegistered ? <MyInfo /> : <Login />}
|
||||||
{localRegistered && <MyCollections />}
|
{localRegistered && <Collections />}
|
||||||
<Settings />
|
<Settings />
|
||||||
{localRegistered && <Logout />}
|
{localRegistered && <Logout />}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
@ -4,34 +4,34 @@ import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
||||||
|
|
||||||
const MyInfo: React.FC = () => {
|
const Collections: React.FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation('meRoot')
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
iconFront='mail'
|
iconFront='mail'
|
||||||
title={t('headers.me.conversations')}
|
title={t('content.collections.conversations')}
|
||||||
onPress={() => navigation.navigate('Screen-Me-Conversations')}
|
onPress={() => navigation.navigate('Screen-Me-Conversations')}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
iconFront='bookmark'
|
iconFront='bookmark'
|
||||||
title={t('headers.me.bookmarks')}
|
title={t('content.collections.bookmarks')}
|
||||||
onPress={() => navigation.navigate('Screen-Me-Bookmarks')}
|
onPress={() => navigation.navigate('Screen-Me-Bookmarks')}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
iconFront='star'
|
iconFront='star'
|
||||||
title={t('headers.me.favourites')}
|
title={t('content.collections.favourites')}
|
||||||
onPress={() => navigation.navigate('Screen-Me-Favourites')}
|
onPress={() => navigation.navigate('Screen-Me-Favourites')}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
iconFront='list'
|
iconFront='list'
|
||||||
title={t('headers.me.lists.root')}
|
title={t('content.collections.lists')}
|
||||||
onPress={() => navigation.navigate('Screen-Me-Lists')}
|
onPress={() => navigation.navigate('Screen-Me-Lists')}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MyInfo
|
export default Collections
|
|
@ -5,17 +5,19 @@ import { updateLocal } from 'src/utils/slices/instancesSlice'
|
||||||
import MenuButton from 'src/components/Menu/Button'
|
import MenuButton from 'src/components/Menu/Button'
|
||||||
import { MenuContainer } from 'src/components/Menu'
|
import { MenuContainer } from 'src/components/Menu'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
const Logout: React.FC = () => {
|
const Logout: React.FC = () => {
|
||||||
|
const { t } = useTranslation('meRoot')
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
const alertOption = {
|
const alertOption = {
|
||||||
title: '确认退出登录?',
|
title: t('content.logout.alert.title'),
|
||||||
message: '退出登录后,需要重新认证账号',
|
message: t('content.logout.alert.message'),
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: '退出登录',
|
text: t('content.logout.alert.buttons.logout'),
|
||||||
style: 'destructive' as const,
|
style: 'destructive' as const,
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
dispatch(updateLocal({}))
|
dispatch(updateLocal({}))
|
||||||
|
@ -26,7 +28,7 @@ const Logout: React.FC = () => {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '取消',
|
text: t('content.logout.alert.buttons.cancel'),
|
||||||
style: 'cancel' as const
|
style: 'cancel' as const
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -35,7 +37,7 @@ const Logout: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
text='退出当前账号'
|
text={t('content.logout.button')}
|
||||||
destructive={true}
|
destructive={true}
|
||||||
alertOption={alertOption}
|
alertOption={alertOption}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -5,14 +5,14 @@ import { useTranslation } from 'react-i18next'
|
||||||
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
const Settings: React.FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation('meRoot')
|
||||||
const navigation = useNavigation()
|
const navigation = useNavigation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer>
|
<MenuContainer>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
iconFront='settings'
|
iconFront='settings'
|
||||||
title={t('headers.me.settings.root')}
|
title={t('content.settings')}
|
||||||
onPress={() => navigation.navigate('Screen-Me-Settings')}
|
onPress={() => navigation.navigate('Screen-Me-Settings')}
|
||||||
/>
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
|
|
|
@ -6,28 +6,32 @@ import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
import { MenuContainer, MenuItem } from 'src/components/Menu'
|
||||||
import {
|
import {
|
||||||
changeLanguage,
|
changeLanguage,
|
||||||
getSettingsLanguage
|
changeTheme,
|
||||||
|
getSettingsLanguage,
|
||||||
|
getSettingsTheme
|
||||||
} from 'src/utils/slices/settingsSlice'
|
} from 'src/utils/slices/settingsSlice'
|
||||||
|
import { useTheme } from 'src/utils/styles/ThemeManager'
|
||||||
|
|
||||||
const ScreenMeSettings: React.FC = () => {
|
const ScreenMeSettings: React.FC = () => {
|
||||||
const { t, i18n } = useTranslation('settings')
|
const { t, i18n } = useTranslation('meSettings')
|
||||||
const language = useSelector(getSettingsLanguage)
|
const { setTheme } = useTheme()
|
||||||
|
const settingsLanguage = useSelector(getSettingsLanguage)
|
||||||
|
const settingsTheme = useSelector(getSettingsTheme)
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
console.log(i18n.language)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContainer marginTop={true}>
|
<MenuContainer marginTop={true}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
title={t('content.language.title')}
|
title={t('content.language.heading')}
|
||||||
content={t(`settings:content.language.options.${language}`)}
|
content={t(`content.language.options.${settingsLanguage}`)}
|
||||||
iconBack='chevron-right'
|
iconBack='chevron-right'
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
ActionSheetIOS.showActionSheetWithOptions(
|
ActionSheetIOS.showActionSheetWithOptions(
|
||||||
{
|
{
|
||||||
options: [
|
options: [
|
||||||
t('settings:content.language.options.zh'),
|
t('content.language.options.zh'),
|
||||||
t('settings:content.language.options.en'),
|
t('content.language.options.en'),
|
||||||
'取消'
|
t('content.language.options.cancel')
|
||||||
],
|
],
|
||||||
cancelButtonIndex: 2
|
cancelButtonIndex: 2
|
||||||
},
|
},
|
||||||
|
@ -46,6 +50,39 @@ const ScreenMeSettings: React.FC = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<MenuItem
|
||||||
|
title={t('content.theme.heading')}
|
||||||
|
content={t(`content.theme.options.${settingsTheme}`)}
|
||||||
|
iconBack='chevron-right'
|
||||||
|
onPress={() =>
|
||||||
|
ActionSheetIOS.showActionSheetWithOptions(
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
dispatch(changeTheme('auto'))
|
||||||
|
break
|
||||||
|
case 1:
|
||||||
|
dispatch(changeTheme('light'))
|
||||||
|
setTheme('light')
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
dispatch(changeTheme('dark'))
|
||||||
|
setTheme('dark')
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
</MenuContainer>
|
</MenuContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,12 @@ import { RootState } from 'src/store'
|
||||||
|
|
||||||
export type SettingsState = {
|
export type SettingsState = {
|
||||||
language: 'zh' | 'en' | undefined
|
language: 'zh' | 'en' | undefined
|
||||||
|
theme: 'light' | 'dark' | 'auto'
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
language: undefined
|
language: undefined,
|
||||||
|
theme: 'auto'
|
||||||
}
|
}
|
||||||
|
|
||||||
// export const updateLocal = createAsyncThunk(
|
// export const updateLocal = createAsyncThunk(
|
||||||
|
@ -62,6 +64,12 @@ const settingsSlice = createSlice({
|
||||||
action: PayloadAction<NonNullable<SettingsState['language']>>
|
action: PayloadAction<NonNullable<SettingsState['language']>>
|
||||||
) => {
|
) => {
|
||||||
state.language = action.payload
|
state.language = action.payload
|
||||||
|
},
|
||||||
|
changeTheme: (
|
||||||
|
state,
|
||||||
|
action: PayloadAction<NonNullable<SettingsState['theme']>>
|
||||||
|
) => {
|
||||||
|
state.theme = action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// extraReducers: builder => {
|
// extraReducers: builder => {
|
||||||
|
@ -72,6 +80,7 @@ const settingsSlice = createSlice({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getSettingsLanguage = (state: RootState) => state.settings.language
|
export const getSettingsLanguage = (state: RootState) => state.settings.language
|
||||||
|
export const getSettingsTheme = (state: RootState) => state.settings.theme
|
||||||
|
|
||||||
export const { changeLanguage } = settingsSlice.actions
|
export const { changeLanguage, changeTheme } = settingsSlice.actions
|
||||||
export default settingsSlice.reducer
|
export default settingsSlice.reducer
|
||||||
|
|
|
@ -1,39 +1,44 @@
|
||||||
import React, { createContext, useContext, useEffect, useState } from 'react'
|
import React, { createContext, useContext, useEffect, useState } from 'react'
|
||||||
import { Appearance, useColorScheme } from 'react-native-appearance'
|
import { Appearance } from 'react-native-appearance'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
import { ColorDefinitions, getTheme } from 'src/utils/styles/themes'
|
import { ColorDefinitions, getTheme } from 'src/utils/styles/themes'
|
||||||
|
import { getSettingsTheme } from '../slices/settingsSlice'
|
||||||
|
|
||||||
const osTheme = Appearance.getColorScheme() as 'light' | 'dark'
|
type ContextType = {
|
||||||
|
|
||||||
export const ManageThemeContext: React.Context<{
|
|
||||||
mode: 'light' | 'dark'
|
mode: 'light' | 'dark'
|
||||||
theme: { [key in ColorDefinitions]: string }
|
theme: { [key in ColorDefinitions]: string }
|
||||||
toggle: () => void
|
setTheme: (theme: 'light' | 'dark') => void
|
||||||
}> = createContext({
|
}
|
||||||
mode: osTheme,
|
|
||||||
theme: getTheme(osTheme),
|
export const ManageThemeContext = createContext<ContextType>({
|
||||||
toggle: () => {}
|
mode: 'light',
|
||||||
|
theme: getTheme('light'),
|
||||||
|
setTheme: () => {}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const useTheme = () => useContext(ManageThemeContext)
|
export const useTheme = () => useContext(ManageThemeContext)
|
||||||
|
|
||||||
const ThemeManager: React.FC = ({ children }) => {
|
const ThemeManager: React.FC = ({ children }) => {
|
||||||
const [mode, setMode] = useState(osTheme)
|
const userTheme = useSelector(getSettingsTheme)
|
||||||
const systemTheme = useColorScheme()
|
const currentMode =
|
||||||
|
userTheme === 'auto'
|
||||||
|
? (Appearance.getColorScheme() as 'light' | 'dark')
|
||||||
|
: userTheme
|
||||||
|
|
||||||
const toggleTheme = () => {
|
const [mode, setMode] = useState(currentMode)
|
||||||
mode === 'light' ? setMode('dark') : setMode('light')
|
|
||||||
}
|
const setTheme = (theme: 'light' | 'dark') => setMode(theme)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMode(systemTheme === 'no-preference' ? 'light' : systemTheme)
|
setMode(currentMode)
|
||||||
}, [systemTheme])
|
}, [currentMode])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ManageThemeContext.Provider
|
<ManageThemeContext.Provider
|
||||||
value={{
|
value={{
|
||||||
mode: mode,
|
mode: mode,
|
||||||
theme: getTheme(mode),
|
theme: getTheme(mode),
|
||||||
toggle: toggleTheme
|
setTheme: setTheme
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
Loading…
Reference in New Issue