feat(settings): add profile hero and settings search

This commit is contained in:
Gauvain
2026-06-03 23:48:22 +02:00
parent e476e0b4d9
commit 6a38c393e6
6 changed files with 258 additions and 32 deletions

View File

@@ -1,16 +1,19 @@
import { useNavigation } from "expo-router";
import { t } from "i18next";
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import { Platform, ScrollView, TouchableOpacity, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Text } from "@/components/common/Text";
import { AppLanguageSelector } from "@/components/settings/AppLanguageSelector";
import { SettingsHero } from "@/components/settings/index/SettingsHero";
import { SettingsRow } from "@/components/settings/index/SettingsRow";
import { SettingsSearchBar } from "@/components/settings/index/SettingsSearchBar";
import { SettingsSection } from "@/components/settings/index/SettingsSection";
import {
SETTINGS_CATALOG,
type SettingsEntry,
type SettingsTarget,
} from "@/components/settings/index/settingsCatalog";
import { useSettingsSearch } from "@/components/settings/index/useSettingsSearch";
import {
QuickConnectSheet,
type QuickConnectSheetRef,
@@ -19,7 +22,6 @@ import { StorageSettings } from "@/components/settings/StorageSettings";
import useRouter from "@/hooks/useAppRouter";
import { useJellyfin } from "@/providers/JellyfinProvider";
// TV-specific settings component
const SettingsTV = Platform.isTV ? require("./settings.tv").default : null;
function SettingsMobile() {
@@ -28,7 +30,10 @@ function SettingsMobile() {
const { logout } = useJellyfin();
const navigation = useNavigation();
const quickConnectRef = useRef<QuickConnectSheetRef>(null);
const [query, setQuery] = useState("");
const os: "ios" | "android" = Platform.OS === "ios" ? "ios" : "android";
const results = useSettingsSearch(query);
const searching = query.trim().length > 0;
useEffect(() => {
navigation.setOptions({
@@ -42,19 +47,20 @@ function SettingsMobile() {
});
}, []);
const handleEntry = (entry: SettingsEntry) => {
if (entry.target.type === "action") {
if (entry.target.action === "quickConnect") {
const handleTarget = (target: SettingsTarget) => {
if (target.type === "action") {
if (target.action === "quickConnect") {
quickConnectRef.current?.present();
}
return;
}
router.push(entry.target.route as any);
router.push(target.route as any);
};
return (
<ScrollView
contentInsetAdjustmentBehavior='automatic'
keyboardShouldPersistTaps='handled'
contentContainerStyle={{
paddingLeft: insets.left,
paddingRight: insets.right,
@@ -62,35 +68,65 @@ function SettingsMobile() {
paddingBottom: 32,
}}
>
<View className='mx-3 mb-5'>
<AppLanguageSelector />
</View>
{!searching && (
<SettingsHero
onPress={() => router.push("/settings/account/page" as any)}
/>
)}
<SettingsSearchBar value={query} onChange={setQuery} />
{SETTINGS_CATALOG.map((section) => {
const entries = section.entries.filter(
(e) => !e.platforms || e.platforms.includes(os),
);
if (entries.length === 0) return null;
return (
<SettingsSection key={section.id} title={t(section.titleKey)}>
{entries.map((e, i) => (
{searching ? (
<SettingsSection title={t("home.settings.search_results")}>
{results.length === 0 ? (
<View className='px-4 py-3'>
<Text className='text-[#9899A1]'>
{t("home.settings.search_no_results")}
</Text>
</View>
) : (
results.map((r, i) => (
<SettingsRow
key={e.id}
title={t(e.titleKey)}
icon={e.icon}
onPress={() => handleEntry(e)}
isLast={i === entries.length - 1}
key={r.id}
title={r.title}
icon={r.icon}
value={r.subtitle}
onPress={() => handleTarget(r.target)}
isLast={i === results.length - 1}
/>
))}
))
)}
</SettingsSection>
) : (
<>
<View className='mx-3 mb-5'>
<AppLanguageSelector />
</View>
{SETTINGS_CATALOG.map((section) => {
const entries = section.entries.filter(
(e) => !e.platforms || e.platforms.includes(os),
);
if (entries.length === 0) return null;
return (
<SettingsSection key={section.id} title={t(section.titleKey)}>
{entries.map((e, i) => (
<SettingsRow
key={e.id}
title={t(e.titleKey)}
icon={e.icon}
onPress={() => handleTarget(e.target)}
isLast={i === entries.length - 1}
/>
))}
</SettingsSection>
);
})}
<SettingsSection>
<View className='p-3'>
<StorageSettings />
</View>
</SettingsSection>
);
})}
<SettingsSection>
<View className='p-3'>
<StorageSettings />
</View>
</SettingsSection>
</>
)}
<QuickConnectSheet ref={quickConnectRef} />
</ScrollView>