109 lines
3.3 KiB
TypeScript
109 lines
3.3 KiB
TypeScript
import { FC, useCallback } from "react"
|
|
import { TextStyle, View, ViewStyle } from "react-native"
|
|
import { useMMKVString } from "react-native-mmkv"
|
|
|
|
import { Icon } from "@/components/Icon"
|
|
import { ListItem } from "@/components/ListItem"
|
|
import { Screen } from "@/components/Screen"
|
|
import { Text } from "@/components/Text"
|
|
import { translate } from "@/i18n/translate"
|
|
import { AppStackScreenProps } from "@/navigators/navigationTypes"
|
|
import { useAppTheme } from "@/theme/context"
|
|
import { $styles } from "@/theme/styles"
|
|
import type { ImmutableThemeContextModeT } from "@/theme/types"
|
|
import type { ThemedStyle } from "@/theme/types"
|
|
import { s } from "@/utils/responsive"
|
|
import { storage } from "@/utils/storage"
|
|
import { useHeader } from "@/utils/useHeader"
|
|
|
|
type ThemeOption = {
|
|
value: ImmutableThemeContextModeT | "system"
|
|
labelKey: string
|
|
}
|
|
|
|
const THEME_OPTIONS: ThemeOption[] = [
|
|
{ value: "system", labelKey: "themeScreen:system" },
|
|
{ value: "light", labelKey: "themeScreen:light" },
|
|
{ value: "dark", labelKey: "themeScreen:dark" },
|
|
]
|
|
|
|
export const ThemeScreen: FC<AppStackScreenProps<"Theme">> = function ThemeScreen({ navigation }) {
|
|
const { themed, theme, setThemeContextOverride } = useAppTheme()
|
|
// Read the stored theme preference directly from MMKV
|
|
// undefined = system, "light" = light, "dark" = dark
|
|
const [themeScheme] = useMMKVString("ignite.themeScheme", storage)
|
|
|
|
// Determine current selection: if no stored value, it's "system"
|
|
const currentTheme = themeScheme === "light" || themeScheme === "dark" ? themeScheme : "system"
|
|
|
|
const handleSelectTheme = useCallback(
|
|
(value: ImmutableThemeContextModeT | "system") => {
|
|
if (value === "system") {
|
|
setThemeContextOverride(undefined)
|
|
} else {
|
|
setThemeContextOverride(value)
|
|
}
|
|
navigation.goBack()
|
|
},
|
|
[setThemeContextOverride, navigation],
|
|
)
|
|
|
|
useHeader(
|
|
{
|
|
title: translate("themeScreen:title"),
|
|
leftIcon: "back",
|
|
onLeftPress: () => navigation.goBack(),
|
|
},
|
|
[],
|
|
)
|
|
|
|
return (
|
|
<Screen
|
|
preset="scroll"
|
|
safeAreaEdges={["bottom"]}
|
|
contentContainerStyle={[$styles.container, themed($container)]}
|
|
>
|
|
<Text size="xs" style={themed($hint)}>
|
|
{translate("themeScreen:selectHint")}
|
|
</Text>
|
|
|
|
<View style={themed($listContainer)}>
|
|
{THEME_OPTIONS.map((option) => {
|
|
const isSelected = currentTheme === option.value
|
|
return (
|
|
<ListItem
|
|
key={option.value}
|
|
text={translate(option.labelKey as any)}
|
|
textStyle={isSelected ? themed($selectedText) : undefined}
|
|
RightComponent={
|
|
isSelected ? <Icon icon="check" size={20} color={theme.colors.tint} /> : undefined
|
|
}
|
|
onPress={() => handleSelectTheme(option.value)}
|
|
/>
|
|
)
|
|
})}
|
|
</View>
|
|
</Screen>
|
|
)
|
|
}
|
|
|
|
const $container: ThemedStyle<ViewStyle> = ({ spacing }) => ({
|
|
paddingTop: spacing.md,
|
|
})
|
|
|
|
const $hint: ThemedStyle<TextStyle> = ({ colors, spacing }) => ({
|
|
color: colors.textDim,
|
|
marginBottom: spacing.md,
|
|
})
|
|
|
|
const $listContainer: ThemedStyle<ViewStyle> = ({ colors }) => ({
|
|
backgroundColor: colors.palette.neutral200,
|
|
borderRadius: s(8),
|
|
overflow: "hidden",
|
|
})
|
|
|
|
const $selectedText: ThemedStyle<TextStyle> = ({ colors }) => ({
|
|
color: colors.tint,
|
|
fontWeight: "600",
|
|
})
|