update theme dark, light mode

This commit is contained in:
2025-11-17 17:01:42 +07:00
parent e725819c01
commit 862c4e42a4
25 changed files with 1274 additions and 442 deletions

View File

@@ -16,6 +16,7 @@ import {
} from "@/constants";
import { useColorScheme } from "@/hooks/use-color-scheme.web";
import { usePlatform } from "@/hooks/use-platform";
import { useThemeContext } from "@/hooks/use-theme-context";
import {
getAlarmEventBus,
getBanzonesEventBus,
@@ -53,7 +54,7 @@ export default function HomeScreen() {
PolygonWithLabelProps[]
>([]);
const platform = usePlatform();
const theme = useColorScheme();
const theme = useThemeContext().colorScheme;
const scale = useRef(new Animated.Value(0)).current;
const opacity = useRef(new Animated.Value(1)).current;

View File

@@ -1,15 +1,18 @@
import { useRouter } from "expo-router";
import { useEffect, useState } from "react";
import { StyleSheet, View } from "react-native";
import { StyleSheet, View, ScrollView } from "react-native";
import EnIcon from "@/assets/icons/en_icon.png";
import VnIcon from "@/assets/icons/vi_icon.png";
import RotateSwitch from "@/components/rotate-switch";
import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";
import { ThemeToggle } from "@/components/theme-toggle";
import { DOMAIN, TOKEN } from "@/constants";
import { useI18n } from "@/hooks/use-i18n";
import { useThemeContext } from "@/hooks/use-theme-context";
import { removeStorageItem } from "@/utils/storage";
import { SafeAreaView } from "react-native-safe-area-context";
type Todo = {
userId: number;
id: number;
@@ -21,7 +24,9 @@ export default function SettingScreen() {
const router = useRouter();
const [data, setData] = useState<Todo | null>(null);
const { t, locale, setLocale } = useI18n();
const { colors } = useThemeContext();
const [isEnabled, setIsEnabled] = useState(locale === "vi");
// Sync isEnabled state khi locale thay đổi
useEffect(() => {
setIsEnabled(locale === "vi");
@@ -33,72 +38,116 @@ export default function SettingScreen() {
};
return (
<ThemedView style={styles.container}>
<ThemedText type="title">{t("navigation.setting")}</ThemedText>
<SafeAreaView style={styles.safeArea} edges={["top", "left", "right"]}>
<ThemedView style={styles.container}>
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
>
<ThemedText type="title" style={styles.title}>
{t("navigation.setting")}
</ThemedText>
<View style={styles.settingItem}>
<ThemedText type="default">{t("common.language")}</ThemedText>
{/* <Switch
trackColor={{ false: "#767577", true: "#81b0ff" }}
thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
ios_backgroundColor="#3e3e3e"
onValueChange={toggleSwitch}
value={isEnabled}
/> */}
<RotateSwitch
initialValue={isEnabled}
onChange={toggleSwitch}
size="sm"
offImage={EnIcon}
onImage={VnIcon}
/>
</View>
{/* Theme Toggle Section */}
<ThemeToggle style={styles.themeSection} />
<ThemedView
style={styles.button}
onTouchEnd={async () => {
await removeStorageItem(TOKEN);
await removeStorageItem(DOMAIN);
router.navigate("/auth/login");
}}
>
<ThemedText type="defaultSemiBold">{t("auth.logout")}</ThemedText>
{/* Language Section */}
<View
style={[
styles.settingItem,
{
backgroundColor: colors.surface,
borderColor: colors.border,
},
]}
>
<ThemedText type="default">{t("common.language")}</ThemedText>
<RotateSwitch
initialValue={isEnabled}
onChange={toggleSwitch}
size="sm"
offImage={EnIcon}
onImage={VnIcon}
/>
</View>
{/* Logout Button */}
<ThemedView
style={[styles.button, { backgroundColor: colors.primary }]}
onTouchEnd={async () => {
await removeStorageItem(TOKEN);
await removeStorageItem(DOMAIN);
router.navigate("/auth/login");
}}
>
<ThemedText type="defaultSemiBold" style={styles.buttonText}>
{t("auth.logout")}
</ThemedText>
</ThemedView>
{data && (
<ThemedView
style={[styles.debugSection, { backgroundColor: colors.surface }]}
>
<ThemedText type="default">{data.title}</ThemedText>
<ThemedText type="default">{data.completed}</ThemedText>
<ThemedText type="default">{data.id}</ThemedText>
</ThemedView>
)}
</ScrollView>
</ThemedView>
{data && (
<ThemedView style={{ marginTop: 20 }}>
<ThemedText type="default">{data.title}</ThemedText>
<ThemedText type="default">{data.completed}</ThemedText>
<ThemedText type="default">{data.id}</ThemedText>
</ThemedView>
)}
</ThemedView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
paddingBottom: 5,
},
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
scrollView: {
flex: 1,
},
scrollContent: {
padding: 20,
gap: 16,
},
title: {
textAlign: "center",
marginBottom: 20,
},
themeSection: {
marginBottom: 8,
},
settingItem: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
width: "100%",
paddingHorizontal: 16,
paddingVertical: 12,
borderRadius: 8,
backgroundColor: "rgba(0, 122, 255, 0.1)",
paddingVertical: 16,
borderRadius: 12,
borderWidth: 1,
},
button: {
marginTop: 20,
paddingVertical: 12,
paddingVertical: 14,
paddingHorizontal: 20,
backgroundColor: "#007AFF",
borderRadius: 8,
borderRadius: 12,
alignItems: "center",
justifyContent: "center",
},
buttonText: {
color: "#fff",
fontSize: 16,
},
debugSection: {
marginTop: 20,
padding: 16,
borderRadius: 12,
gap: 8,
},
});

View File

@@ -5,19 +5,18 @@ import CrewListTable from "@/components/tripInfo/CrewListTable";
import FishingToolsTable from "@/components/tripInfo/FishingToolsList";
import NetListTable from "@/components/tripInfo/NetListTable";
import TripCostTable from "@/components/tripInfo/TripCostTable";
import { useThemeContext } from "@/hooks/use-theme-context";
import { Platform, ScrollView, StyleSheet, Text, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
export default function TripInfoScreen() {
// const { trip, getTrip } = useTrip();
// useEffect(() => {
// getTrip();
// }, []);
const { colors } = useThemeContext();
return (
<SafeAreaView style={styles.safeArea} edges={["top", "left", "right"]}>
<View style={styles.header}>
<Text style={styles.titleText}>Thông Tin Chuyến Đi</Text>
<Text style={[styles.titleText, { color: colors.text }]}>
Thông Tin Chuyến Đi
</Text>
<View style={styles.buttonWrapper}>
<ButtonCreateNewHaulOrTrip />
</View>

View File

@@ -1,7 +1,7 @@
import {
DarkTheme,
DefaultTheme,
ThemeProvider,
ThemeProvider as NavigationThemeProvider,
} from "@react-navigation/native";
import { Stack, useRouter } from "expo-router";
import { StatusBar } from "expo-status-bar";
@@ -13,52 +13,61 @@ import { GluestackUIProvider } from "@/components/ui/gluestack-ui-provider/glues
import { toastConfig } from "@/config";
import { setRouterInstance } from "@/config/auth";
import "@/global.css";
import { useColorScheme } from "@/hooks/use-color-scheme";
import { ThemeProvider, useThemeContext } from "@/hooks/use-theme-context";
import { I18nProvider } from "@/hooks/use-i18n";
import Toast from "react-native-toast-message";
import "../global.css";
export default function RootLayout() {
const colorScheme = useColorScheme();
function AppContent() {
const { colorScheme } = useThemeContext();
const router = useRouter();
useEffect(() => {
setRouterInstance(router);
}, [router]);
return (
<GluestackUIProvider mode={colorScheme}>
<NavigationThemeProvider
value={colorScheme === "dark" ? DarkTheme : DefaultTheme}
>
<Stack
screenOptions={{ headerShown: false }}
initialRouteName="auth/login"
>
<Stack.Screen
name="auth/login"
options={{
title: "Login",
headerShown: false,
}}
/>
<Stack.Screen
name="(tabs)"
options={{
title: "Home",
headerShown: false,
}}
/>
<Stack.Screen
name="modal"
options={{ presentation: "formSheet", title: "Modal" }}
/>
</Stack>
<StatusBar style="auto" />
<Toast config={toastConfig} visibilityTime={2000} topOffset={60} />
</NavigationThemeProvider>
</GluestackUIProvider>
);
}
export default function RootLayout() {
return (
<I18nProvider>
<GluestackUIProvider>
<ThemeProvider
value={colorScheme === "dark" ? DarkTheme : DefaultTheme}
>
<Stack
screenOptions={{ headerShown: false }}
initialRouteName="auth/login"
>
<Stack.Screen
name="auth/login"
options={{
title: "Login",
headerShown: false,
}}
/>
<Stack.Screen
name="(tabs)"
options={{
title: "Home",
headerShown: false,
}}
/>
<Stack.Screen
name="modal"
options={{ presentation: "formSheet", title: "Modal" }}
/>
</Stack>
<StatusBar style="auto" />
<Toast config={toastConfig} visibilityTime={2000} topOffset={60} />
</ThemeProvider>
</GluestackUIProvider>
<ThemeProvider>
<AppContent />
</ThemeProvider>
</I18nProvider>
);
}