feat(mobile): discoverLanguage ui setting

This commit is contained in:
DIYgod 2025-05-19 11:14:36 +08:00
parent ebfdda7c2e
commit 7702d8a459
No known key found for this signature in database
5 changed files with 149 additions and 125 deletions

View File

@ -1,9 +1,14 @@
import { defaultUISettings } from "@follow/shared/src/settings/defaults"
import type { UISettings } from "@follow/shared/src/settings/interface"
import { getDeviceLanguage } from "@/src/lib/i18n"
import { createSettingAtom } from "./internal/helper"
export const createDefaultSettings = (): UISettings => defaultUISettings
export const createDefaultSettings = (): UISettings => ({
...defaultUISettings,
discoverLanguage: getDeviceLanguage().startsWith("zh") ? "all" : "eng",
})
export const {
useSettingKey: useUISettingKey,

View File

@ -0,0 +1,77 @@
import type { RSSHubCategory } from "@follow/constants"
import { CategoryMap, RSSHubCategories } from "@follow/constants"
import { LinearGradient } from "expo-linear-gradient"
import { memo } from "react"
import { useTranslation } from "react-i18next"
import { Pressable, StyleSheet, Text, View } from "react-native"
import { Grid } from "@/src/components/ui/grid"
import { ItemPressable } from "@/src/components/ui/pressable/ItemPressable"
import { FilterCuteReIcon } from "@/src/icons/filter_cute_re"
import { Grid2CuteReIcon } from "@/src/icons/grid_2_cute_re"
import { useNavigation } from "@/src/lib/navigation/hooks"
import { Recommendations } from "@/src/modules/discover/Recommendations"
import { RecommendationCategoryScreen } from "@/src/screens/(stack)/recommendation/RecommendationCategoryScreen"
export const Category = () => {
return (
<>
<View className="mt-4 flex-row items-center justify-between pb-1 pl-6 pr-5 pt-4">
<View className="flex-row items-center gap-2">
<Grid2CuteReIcon width={24} height={24} />
<Text className="text-label text-2xl font-bold leading-[1.1]">Categories</Text>
</View>
<ItemPressable className="rounded-lg p-1">
<FilterCuteReIcon width={20} height={20} />
</ItemPressable>
</View>
<Grid columns={2} gap={12} className="p-4">
{RSSHubCategories.map((category) => (
<CategoryItem key={category} category={category} />
))}
</Grid>
</>
)
}
const CategoryItem = memo(({ category }: { category: RSSHubCategory }) => {
const { t } = useTranslation("common")
const name = t(`discover.category.${category}`)
const navigation = useNavigation()
return (
<Pressable
className="overflow-hidden rounded-2xl"
key={category}
onPress={() => {
if (category === "all") {
navigation.pushControllerView(Recommendations)
} else {
navigation.pushControllerView(RecommendationCategoryScreen, {
category,
})
}
}}
>
<LinearGradient
colors={[`${CategoryMap[category].color}80`, CategoryMap[category].color]}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
className="rounded-2xl p-4"
style={styles.cardItem}
>
<View className="flex-1">
<Text className="absolute right-2 top-2 text-4xl">{CategoryMap[category].emoji}</Text>
<Text className="absolute bottom-0 left-2 text-xl font-bold text-white">{name}</Text>
</View>
</LinearGradient>
</Pressable>
)
})
const styles = StyleSheet.create({
cardItem: {
aspectRatio: 16 / 9,
},
})

View File

@ -1,97 +1,13 @@
import type { RSSHubCategory } from "@follow/constants"
import { CategoryMap, RSSHubCategories } from "@follow/constants"
import { LinearGradient } from "expo-linear-gradient"
import { memo } from "react"
import { useTranslation } from "react-i18next"
import { Pressable, StyleSheet, Text, View } from "react-native"
import { View } from "react-native"
import { Grid } from "@/src/components/ui/grid"
// import { ItemPressable } from "@/src/components/ui/pressable/ItemPressable"
// import { FilterCuteReIcon } from "@/src/icons/filter_cute_re"
import { Grid2CuteReIcon } from "@/src/icons/grid_2_cute_re"
import { TrendingUpCuteReIcon } from "@/src/icons/trending_up_cute_re"
import { useNavigation } from "@/src/lib/navigation/hooks"
import { Recommendations } from "@/src/modules/discover/Recommendations"
import { Category } from "@/src/modules/discover/Category"
import { Trending } from "@/src/modules/discover/Trending"
import { RecommendationCategoryScreen } from "@/src/screens/(stack)/recommendation/RecommendationCategoryScreen"
export function DiscoverContent() {
return (
<View>
<View className="flex-row items-center justify-between pb-1 pl-6 pr-5 pt-4">
<View className="flex-row items-center gap-2">
<TrendingUpCuteReIcon width={24} height={24} />
<Text className="text-label text-2xl font-bold leading-[1.1]">Trending</Text>
</View>
{/* <ItemPressable className="rounded-lg p-1">
<FilterCuteReIcon width={20} height={20} />
</ItemPressable> */}
</View>
<Trending className="mt-4" itemClassName="px-6" />
<View className="mt-4 flex-row items-center justify-between pb-1 pl-6 pr-5 pt-4">
<View className="flex-row items-center gap-2">
<Grid2CuteReIcon width={24} height={24} />
<Text className="text-label text-2xl font-bold leading-[1.1]">Categories</Text>
</View>
{/* <ItemPressable className="rounded-lg p-1">
<FilterCuteReIcon width={20} height={20} />
</ItemPressable> */}
</View>
<DiscoverGrid />
<Trending itemClassName="px-6" />
<Category />
</View>
)
}
const DiscoverGrid = () => {
return (
<Grid columns={2} gap={12} className="p-4">
{RSSHubCategories.map((category) => (
<CategoryItem key={category} category={category} />
))}
</Grid>
)
}
const CategoryItem = memo(({ category }: { category: RSSHubCategory }) => {
const { t } = useTranslation("common")
const name = t(`discover.category.${category}`)
const navigation = useNavigation()
return (
<Pressable
className="overflow-hidden rounded-2xl"
key={category}
onPress={() => {
if (category === "all") {
navigation.pushControllerView(Recommendations)
} else {
navigation.pushControllerView(RecommendationCategoryScreen, {
category,
})
}
}}
>
<LinearGradient
colors={[`${CategoryMap[category].color}80`, CategoryMap[category].color]}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
className="rounded-2xl p-4"
style={styles.cardItem}
>
<View className="flex-1">
<Text className="absolute right-2 top-2 text-4xl">{CategoryMap[category].emoji}</Text>
<Text className="absolute bottom-0 left-2 text-xl font-bold text-white">{name}</Text>
</View>
</LinearGradient>
</Pressable>
)
})
const styles = StyleSheet.create({
cardItem: {
aspectRatio: 16 / 9,
},
})

View File

@ -22,6 +22,7 @@ import type { SharedValue } from "react-native-reanimated"
import { useSharedValue } from "react-native-reanimated"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import { useUISettingKey } from "@/src/atoms/settings/ui"
import { AnimatedScrollView } from "@/src/components/common/AnimatedComponents"
import { BlurEffect } from "@/src/components/common/BlurEffect"
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
@ -117,6 +118,12 @@ export const Recommendations = () => {
)
}
const LanguageMap = {
all: "all",
eng: "en",
cmn: "zh-CN",
} as const
export const RecommendationTab: TabComponent<{
contentContainerStyle?: ContentStyle
insets?: { top?: number; bottom?: number }
@ -129,9 +136,12 @@ export const RecommendationTab: TabComponent<{
insets: customInsets,
...rest
}) => {
const discoverLanguage = useUISettingKey("discoverLanguage")
const { data, isLoading } = useQuery({
queryKey: ["rsshub-popular", "cache", tab.value],
queryFn: () => fetchRsshubPopular(tab.value, "all").then((res) => res.data),
queryFn: () =>
fetchRsshubPopular(tab.value, LanguageMap[discoverLanguage]).then((res) => res.data),
})
const keys = useMemo(() => {
if (!data) {

View File

@ -1,9 +1,13 @@
import { cn } from "@follow/utils"
import { useQuery } from "@tanstack/react-query"
import { useTranslation } from "react-i18next"
import { Text, View } from "react-native"
import { useUISettingKey } from "@/src/atoms/settings/ui"
import { PlatformActivityIndicator } from "@/src/components/ui/loading/PlatformActivityIndicator"
import { ItemPressableStyle } from "@/src/components/ui/pressable/enum"
import { ItemPressable } from "@/src/components/ui/pressable/ItemPressable"
import { FilterCuteReIcon } from "@/src/icons/filter_cute_re"
import { TrendingUpCuteReIcon } from "@/src/icons/trending_up_cute_re"
import { fetchFeedTrending } from "./api"
import { FeedSummary } from "./FeedSummary"
@ -15,51 +19,63 @@ export const Trending = ({
className?: string
itemClassName?: string
}) => {
const { i18n } = useTranslation()
const discoverLanguage = useUISettingKey("discoverLanguage")
const { data, isLoading } = useQuery({
queryKey: ["trending", "feeds"],
queryFn: () =>
fetchFeedTrending({
lang: i18n.language.startsWith("zh") ? undefined : "eng",
lang: discoverLanguage === "all" ? undefined : discoverLanguage,
limit: 20,
}).then((res) => res.data),
})
return (
<View className={className}>
{isLoading ? (
<View className="mt-5 flex h-12 items-center justify-center">
<PlatformActivityIndicator />
<View className={cn("flex-row items-center justify-between pb-1 pt-4", itemClassName)}>
<View className="flex-row items-center gap-2">
<TrendingUpCuteReIcon width={24} height={24} />
<Text className="text-label text-2xl font-bold leading-[1.1]">Trending</Text>
</View>
) : (
data?.map((item, index) => (
<FeedSummary
key={item.feed?.id}
item={item}
className={cn("flex flex-1 flex-row items-center bg-none py-3", itemClassName)}
simple
preChildren={
<View
className={cn(
"mr-4 flex size-6 items-center justify-center rounded-full",
index < 3
? cn(
"bg-accent text-white",
index === 0 && "bg-accent",
index === 1 && "bg-accent/90",
index === 2 && "bg-accent/80",
)
: "bg-gray-5/60",
)}
>
<Text className={cn("text-xs font-medium", index < 3 && "text-white")}>
{index + 1}
</Text>
</View>
}
/>
))
)}
<ItemPressable className="rounded-lg p-1" itemStyle={ItemPressableStyle.UnStyled}>
<FilterCuteReIcon width={20} height={20} />
</ItemPressable>
</View>
<View className="mt-4">
{isLoading ? (
<View className="mt-5 flex h-12 items-center justify-center">
<PlatformActivityIndicator />
</View>
) : (
data?.map((item, index) => (
<FeedSummary
key={item.feed?.id}
item={item}
className={cn("flex flex-1 flex-row items-center bg-none py-3", itemClassName)}
simple
preChildren={
<View
className={cn(
"mr-4 flex size-6 items-center justify-center rounded-full",
index < 3
? cn(
"bg-accent text-white",
index === 0 && "bg-accent",
index === 1 && "bg-accent/90",
index === 2 && "bg-accent/80",
)
: "bg-gray-5/60",
)}
>
<Text className={cn("text-xs font-medium", index < 3 && "text-white")}>
{index + 1}
</Text>
</View>
}
/>
))
)}
</View>
</View>
)
}