This commit is contained in:
yuchenglong
2026-01-20 14:23:31 +08:00
13 changed files with 1490 additions and 271 deletions

View File

@@ -17,7 +17,7 @@ import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { useAppState } from "@/context/AppStateContext";
import { useTheme } from "@/context/ThemeContext";
import { changeLanguage } from "@/i18n";
import { changeLanguage, SUPPORTED_LANGUAGES } from "@/i18n";
import { appleSignIn, fetchUserProfile, logout } from "@/lib/api";
import { storage } from "@/lib/storage";
import type { UserProfile } from "@/types/api";
@@ -50,6 +50,7 @@ export default function ProfileScreen() {
const [user, setUser] = React.useState<UserProfile | null>(null);
const [loginModalVisible, setLoginModalVisible] = React.useState(false);
const [oddsModalVisible, setOddsModalVisible] = React.useState(false);
const [languageModalVisible, setLanguageModalVisible] = React.useState(false);
const currentLanguage = i18n.language;
@@ -87,9 +88,16 @@ export default function ProfileScreen() {
selectedBookmakers: next,
});
};
const toggleLanguage = () => {
const nextLang = currentLanguage.startsWith("en") ? "zh" : "en";
changeLanguage(nextLang);
const selectLanguage = (langCode: string) => {
changeLanguage(langCode);
setLanguageModalVisible(false);
};
const getCurrentLanguageName = () => {
const lang = SUPPORTED_LANGUAGES.find((l) =>
currentLanguage.startsWith(l.code)
);
return lang?.name || "English";
};
const handleAppleSignIn = async () => {
@@ -120,13 +128,13 @@ export default function ProfileScreen() {
},
user:
credential.fullName &&
(credential.fullName.givenName || credential.fullName.familyName)
(credential.fullName.givenName || credential.fullName.familyName)
? {
name: {
firstName: credential.fullName.givenName || undefined,
lastName: credential.fullName.familyName || undefined,
},
}
name: {
firstName: credential.fullName.givenName || undefined,
lastName: credential.fullName.familyName || undefined,
},
}
: undefined,
};
@@ -204,6 +212,7 @@ export default function ProfileScreen() {
options={{
title: t("profile.title"),
headerShown: true,
headerBackTitle: t("settings.back"),
// Ensure header matches theme to avoid white flash
headerStyle: {
backgroundColor: isDark ? "#000" : "#f2f2f7",
@@ -243,9 +252,9 @@ export default function ProfileScreen() {
<ThemedText type="title">
{user?.nickname || t("profile.name")}
</ThemedText>
<ThemedText style={{ color: subTextColor }}>
{/* <ThemedText style={{ color: subTextColor }}>
{user?.appleId || ""}
</ThemedText>
</ThemedText> */}
</View>
</View>
<TouchableOpacity
@@ -320,24 +329,30 @@ export default function ProfileScreen() {
},
]}
>
<View style={styles.settingLabel}>
<IconSymbol
name="globe"
size={20}
color={iconColor}
style={{ marginRight: 10 }}
/>
<ThemedText>{t("settings.language")}</ThemedText>
</View>
<View style={styles.settingControl}>
<TouchableOpacity onPress={toggleLanguage} style={styles.button}>
<ThemedText>
{currentLanguage.startsWith("zh")
? t("settings.chinese")
: t("settings.english")}
<TouchableOpacity
style={styles.settingItemContent}
onPress={() => setLanguageModalVisible(true)}
>
<View style={styles.settingLabel}>
<IconSymbol
name="globe"
size={20}
color={iconColor}
style={{ marginRight: 10 }}
/>
<ThemedText>{t("settings.language")}</ThemedText>
</View>
<View style={{ flexDirection: "row", alignItems: "center" }}>
<ThemedText style={{ color: subTextColor, marginRight: 4 }}>
{getCurrentLanguageName()}
</ThemedText>
</TouchableOpacity>
</View>
<IconSymbol
name="chevron-forward"
size={16}
color={subTextColor}
/>
</View>
</TouchableOpacity>
</View>
<View
@@ -587,7 +602,7 @@ export default function ProfileScreen() {
onPress={handleAppleSignIn}
/>
)}
<TouchableOpacity style={styles.googleButton} onPress={() => {}}>
<TouchableOpacity style={styles.googleButton} onPress={() => { }}>
<ThemedText>{t("settings.google_login")}</ThemedText>
</TouchableOpacity>
<TouchableOpacity
@@ -662,6 +677,68 @@ export default function ProfileScreen() {
</View>
</TouchableOpacity>
</Modal>
<Modal
visible={languageModalVisible}
transparent
animationType="slide"
onRequestClose={() => setLanguageModalVisible(false)}
>
<TouchableOpacity
style={styles.modalMask}
activeOpacity={1}
onPress={() => setLanguageModalVisible(false)}
>
<View
style={[
styles.modalCard,
{
backgroundColor: isDark ? "#1c1c1e" : "#fff",
maxHeight: "70%",
},
]}
>
<ThemedText style={styles.modalTitle}>
{t("settings.language")}
</ThemedText>
<ScrollView style={{ marginVertical: 10 }}>
{SUPPORTED_LANGUAGES.map((lang) => {
const isSelected = currentLanguage.startsWith(lang.code);
return (
<TouchableOpacity
key={lang.code}
style={[
styles.bookmakerItem,
{ borderColor: isDark ? "#38383a" : "#eee" },
]}
onPress={() => selectLanguage(lang.code)}
>
<ThemedText
style={{
color: isSelected ? "#FF9500" : textColor,
fontWeight: isSelected ? "bold" : "normal",
}}
>
{lang.name}
</ThemedText>
{isSelected && (
<IconSymbol name="checkmark" size={18} color="#FF9500" />
)}
</TouchableOpacity>
);
})}
</ScrollView>
<TouchableOpacity
style={styles.modalCancel}
onPress={() => setLanguageModalVisible(false)}
>
<ThemedText type="defaultSemiBold">
{t("settings.cancel")}
</ThemedText>
</TouchableOpacity>
</View>
</TouchableOpacity>
</Modal>
</>
);
}