template_0205
This commit is contained in:
170
RN_TEMPLATE/app/screens/SettingsScreen.tsx
Normal file
170
RN_TEMPLATE/app/screens/SettingsScreen.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
import { FC, useCallback, useState } from "react"
|
||||
import { TextStyle, View, ViewStyle } from "react-native"
|
||||
import i18n from "i18next"
|
||||
import { useMMKVString } from "react-native-mmkv"
|
||||
|
||||
import { Button } from "@/components/Button"
|
||||
import { Dialog } from "@/components/Dialog"
|
||||
import { Icon } from "@/components/Icon"
|
||||
import { ListItem } from "@/components/ListItem"
|
||||
import { Screen } from "@/components/Screen"
|
||||
import { Text } from "@/components/Text"
|
||||
import { useAuth } from "@/context/AuthContext"
|
||||
import { translate } from "@/i18n/translate"
|
||||
import { AppStackScreenProps } from "@/navigators/navigationTypes"
|
||||
import { useAppTheme } from "@/theme/context"
|
||||
import { $styles } from "@/theme/styles"
|
||||
import type { ThemedStyle } from "@/theme/types"
|
||||
import { s } from "@/utils/responsive"
|
||||
import { storage } from "@/utils/storage"
|
||||
import { useHeader } from "@/utils/useHeader"
|
||||
|
||||
// Language display names
|
||||
const LANGUAGE_NAMES: Record<string, string> = {
|
||||
en: "English",
|
||||
zh: "中文",
|
||||
ja: "日本語",
|
||||
ko: "한국어",
|
||||
es: "Español",
|
||||
fr: "Français",
|
||||
ar: "العربية",
|
||||
hi: "हिन्दी",
|
||||
}
|
||||
|
||||
// Theme display names
|
||||
const THEME_NAMES: Record<string, string> = {
|
||||
system: "System",
|
||||
light: "Light",
|
||||
dark: "Dark",
|
||||
}
|
||||
|
||||
export const SettingsScreen: FC<AppStackScreenProps<"Settings">> = function SettingsScreen({
|
||||
navigation,
|
||||
}) {
|
||||
const { themed, theme } = useAppTheme()
|
||||
const { logout } = useAuth()
|
||||
const [showLogoutDialog, setShowLogoutDialog] = useState(false)
|
||||
|
||||
// Read the stored theme preference directly from MMKV
|
||||
const [themeScheme] = useMMKVString("ignite.themeScheme", storage)
|
||||
|
||||
// Get current theme name for display: if no stored value, it's "system"
|
||||
const currentThemeName =
|
||||
themeScheme === "light" || themeScheme === "dark"
|
||||
? THEME_NAMES[themeScheme]
|
||||
: THEME_NAMES.system
|
||||
|
||||
const handleLogoutPress = useCallback(() => {
|
||||
setShowLogoutDialog(true)
|
||||
}, [])
|
||||
|
||||
const handleLogoutConfirm = useCallback(() => {
|
||||
setShowLogoutDialog(false)
|
||||
logout()
|
||||
}, [logout])
|
||||
|
||||
useHeader(
|
||||
{
|
||||
title: translate("settingsScreen:title"),
|
||||
leftIcon: "back",
|
||||
onLeftPress: () => navigation.goBack(),
|
||||
},
|
||||
[],
|
||||
)
|
||||
|
||||
return (
|
||||
<Screen preset="fixed" safeAreaEdges={["bottom"]} contentContainerStyle={$styles.flex1}>
|
||||
{/* Content */}
|
||||
<View style={[$styles.container, themed($container), $styles.flex1]}>
|
||||
{/* Appearance Section */}
|
||||
<Text preset="subheading" tx="settingsScreen:appearance" style={themed($sectionTitle)} />
|
||||
|
||||
<ListItem
|
||||
tx="settingsScreen:theme"
|
||||
leftIcon="moon"
|
||||
leftIconColor={theme.colors.tint}
|
||||
RightComponent={
|
||||
<View style={$rightContainer}>
|
||||
<Text size="xs" style={themed($themeText)}>
|
||||
{currentThemeName}
|
||||
</Text>
|
||||
<Icon icon="caretRight" size={s(24)} color={theme.colors.textDim} />
|
||||
</View>
|
||||
}
|
||||
onPress={() => navigation.navigate("Theme")}
|
||||
/>
|
||||
|
||||
{/* Language Section */}
|
||||
<Text
|
||||
preset="subheading"
|
||||
tx="settingsScreen:language"
|
||||
style={themed($sectionTitleWithMargin)}
|
||||
/>
|
||||
|
||||
<ListItem
|
||||
tx="settingsScreen:currentLanguage"
|
||||
leftIcon="globe"
|
||||
leftIconColor={theme.colors.tint}
|
||||
RightComponent={
|
||||
<View style={$rightContainer}>
|
||||
<Text size="xs" style={themed($languageText)}>
|
||||
{LANGUAGE_NAMES[i18n.language?.split("-")[0] || "en"] || "English"}
|
||||
</Text>
|
||||
<Icon icon="caretRight" size={s(24)} color={theme.colors.textDim} />
|
||||
</View>
|
||||
}
|
||||
onPress={() => navigation.navigate("Language")}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Logout Button - Fixed at bottom */}
|
||||
<View style={themed($bottomContainer)}>
|
||||
<Button tx="common:logOut" preset="reversed" onPress={handleLogoutPress} />
|
||||
</View>
|
||||
|
||||
{/* Logout Confirmation Dialog */}
|
||||
<Dialog
|
||||
visible={showLogoutDialog}
|
||||
onClose={() => setShowLogoutDialog(false)}
|
||||
preset="destructive"
|
||||
titleTx="securityScreen:confirmLogout"
|
||||
messageTx="securityScreen:confirmLogoutMessage"
|
||||
confirmTx="common:logOut"
|
||||
onConfirm={handleLogoutConfirm}
|
||||
onCancel={() => setShowLogoutDialog(false)}
|
||||
/>
|
||||
</Screen>
|
||||
)
|
||||
}
|
||||
|
||||
const $container: ThemedStyle<ViewStyle> = ({ spacing }) => ({
|
||||
paddingTop: spacing.lg,
|
||||
})
|
||||
|
||||
const $sectionTitle: ThemedStyle<TextStyle> = () => ({
|
||||
// First section doesn't need top margin
|
||||
})
|
||||
|
||||
const $sectionTitleWithMargin: ThemedStyle<TextStyle> = ({ spacing }) => ({
|
||||
marginTop: spacing.xxl,
|
||||
})
|
||||
|
||||
const $rightContainer: ViewStyle = {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}
|
||||
|
||||
const $themeText: ThemedStyle<TextStyle> = ({ colors, spacing }) => ({
|
||||
color: colors.textDim,
|
||||
marginRight: spacing.xs,
|
||||
})
|
||||
|
||||
const $languageText: ThemedStyle<TextStyle> = ({ colors, spacing }) => ({
|
||||
color: colors.textDim,
|
||||
marginRight: spacing.xs,
|
||||
})
|
||||
|
||||
const $bottomContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingBottom: spacing.md,
|
||||
})
|
||||
Reference in New Issue
Block a user