From 6ee48ffb9d628a04c487b73b222be76241ff3ec4 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Mon, 29 Dec 2025 10:23:36 +0200
Subject: feat(mobile): make the settings menu look more native (#2307)

* feat(mobile): make the settings menu look more native

* more fixes

* review comments
---
 apps/mobile/app/dashboard/(tabs)/settings.tsx | 180 +++++++++++++-------------
 1 file changed, 93 insertions(+), 87 deletions(-)

(limited to 'apps/mobile/app/dashboard/(tabs)/settings.tsx')

diff --git a/apps/mobile/app/dashboard/(tabs)/settings.tsx b/apps/mobile/app/dashboard/(tabs)/settings.tsx
index db19b6fe..106baec5 100644
--- a/apps/mobile/app/dashboard/(tabs)/settings.tsx
+++ b/apps/mobile/app/dashboard/(tabs)/settings.tsx
@@ -4,11 +4,11 @@ import { Slider } from "react-native-awesome-slider";
 import { useSharedValue } from "react-native-reanimated";
 import Constants from "expo-constants";
 import { Link } from "expo-router";
+import { UserProfileHeader } from "@/components/settings/UserProfileHeader";
 import { Button } from "@/components/ui/Button";
 import ChevronRight from "@/components/ui/ChevronRight";
 import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
 import { Divider } from "@/components/ui/Divider";
-import PageTitle from "@/components/ui/PageTitle";
 import { Text } from "@/components/ui/Text";
 import { useServerVersion } from "@/lib/hooks";
 import { useSession } from "@/lib/session";
@@ -31,7 +31,7 @@ export default function Dashboard() {
     imageQuality.value = settings.imageQuality * 100;
   }, [settings]);
 
-  const { data, error, isLoading } = api.users.whoami.useQuery();
+  const { data, error } = api.users.whoami.useQuery();
   const {
     data: serverVersion,
     isLoading: isServerVersionLoading,
@@ -44,103 +44,106 @@ export default function Dashboard() {
 
   return (
     <CustomSafeAreaView>
-      <PageTitle title="Settings" />
+      <UserProfileHeader
+        image={data?.image}
+        name={data?.name}
+        email={data?.email}
+      />
       <View className="flex h-full w-full items-center gap-3 px-4 py-2">
-        <View className="flex w-full gap-3 rounded-lg bg-card px-4 py-2">
-          <Text>{isSettingsLoading ? "Loading ..." : settings.address}</Text>
-          <Divider orientation="horizontal" />
-          <Text>{isLoading ? "Loading ..." : data?.email}</Text>
-        </View>
-        <Text className="w-full p-1 text-2xl font-bold text-foreground">
-          App Settings
-        </Text>
-        <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2">
-          <Link asChild href="/dashboard/settings/theme" className="flex-1">
-            <Pressable className="flex flex-row justify-between">
-              <Text>Theme</Text>
-              <View className="flex flex-row items-center gap-2">
-                <Text className="text-muted-foreground">
-                  {
-                    { light: "Light", dark: "Dark", system: "System" }[
-                      settings.theme
-                    ]
-                  }
-                </Text>
-                <ChevronRight />
-              </View>
-            </Pressable>
-          </Link>
-        </View>
-        <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2">
-          <Link
-            asChild
-            href="/dashboard/settings/bookmark-default-view"
-            className="flex-1"
-          >
-            <Pressable className="flex flex-row justify-between">
-              <Text>Default Bookmark View</Text>
-              <View className="flex flex-row items-center gap-2">
-                {isSettingsLoading ? (
-                  <ActivityIndicator size="small" />
-                ) : (
+        <View className="w-full rounded-xl bg-card py-2">
+          <View className="flex flex-row items-center justify-between gap-8 px-4 py-1">
+            <Link asChild href="/dashboard/settings/theme" className="flex-1">
+              <Pressable className="flex flex-row justify-between">
+                <Text>Theme</Text>
+                <View className="flex flex-row items-center gap-2">
                   <Text className="text-muted-foreground">
-                    {settings.defaultBookmarkView === "reader"
-                      ? "Reader"
-                      : "Browser"}
+                    {
+                      { light: "Light", dark: "Dark", system: "System" }[
+                        settings.theme
+                      ]
+                    }
                   </Text>
-                )}
+                  <ChevronRight />
+                </View>
+              </Pressable>
+            </Link>
+          </View>
+          <Divider orientation="horizontal" className="mx-6 my-1" />
+          <View className="flex flex-row items-center justify-between gap-8 px-4 py-1">
+            <Link
+              asChild
+              href="/dashboard/settings/bookmark-default-view"
+              className="flex-1"
+            >
+              <Pressable className="flex flex-row justify-between">
+                <Text>Default Bookmark View</Text>
+                <View className="flex flex-row items-center gap-2">
+                  {isSettingsLoading ? (
+                    <ActivityIndicator size="small" />
+                  ) : (
+                    <Text className="text-muted-foreground">
+                      {settings.defaultBookmarkView === "reader"
+                        ? "Reader"
+                        : "Browser"}
+                    </Text>
+                  )}
+                  <ChevronRight />
+                </View>
+              </Pressable>
+            </Link>
+          </View>
+          <Divider orientation="horizontal" className="mx-6 my-1" />
+          <View className="flex flex-row items-center justify-between gap-8 px-4 py-1">
+            <Link
+              asChild
+              href="/dashboard/settings/reader-settings"
+              className="flex-1"
+            >
+              <Pressable className="flex flex-row justify-between">
+                <Text>Reader Text Settings</Text>
                 <ChevronRight />
-              </View>
-            </Pressable>
-          </Link>
-        </View>
-        <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2">
-          <Link
-            asChild
-            href="/dashboard/settings/reader-settings"
-            className="flex-1"
-          >
-            <Pressable className="flex flex-row justify-between">
-              <Text>Reader Text Settings</Text>
-              <ChevronRight />
-            </Pressable>
-          </Link>
-        </View>
-        <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2">
-          <Text>Show note preview in bookmark</Text>
-          <Switch
-            value={settings.showNotes}
-            onValueChange={(value) =>
-              setSettings({
-                ...settings,
-                showNotes: value,
-              })
-            }
-          />
-        </View>
-        <Text className="w-full p-1 text-2xl font-bold text-foreground">
-          Upload Settings
-        </Text>
-        <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2">
-          <Text>Image Quality</Text>
-          <View className="flex flex-1 flex-row items-center justify-center gap-2">
-            <Text className="text-foreground">
-              {Math.round(settings.imageQuality * 100)}%
+              </Pressable>
+            </Link>
+          </View>
+          <Divider orientation="horizontal" className="mx-6 my-1" />
+          <View className="flex flex-row items-center justify-between gap-8 px-4 py-1">
+            <Text className="flex-1" numberOfLines={1}>
+              Show notes in bookmark card
             </Text>
-            <Slider
-              onSlidingComplete={(value) =>
+            <Switch
+              className="shrink-0"
+              value={settings.showNotes}
+              onValueChange={(value) =>
                 setSettings({
                   ...settings,
-                  imageQuality: Math.round(value) / 100,
+                  showNotes: value,
                 })
               }
-              progress={imageQuality}
-              minimumValue={imageQualityMin}
-              maximumValue={imageQualityMax}
             />
           </View>
         </View>
-        <Divider orientation="horizontal" />
+
+        <View className="w-full rounded-xl bg-card py-2">
+          <View className="flex w-full flex-row items-center justify-between gap-8 px-4 py-1">
+            <Text>Upload Image Quality</Text>
+            <View className="flex flex-1 flex-row items-center justify-center gap-2">
+              <Text className="text-foreground">
+                {Math.round(settings.imageQuality * 100)}%
+              </Text>
+              <Slider
+                onSlidingComplete={(value) =>
+                  setSettings({
+                    ...settings,
+                    imageQuality: Math.round(value) / 100,
+                  })
+                }
+                progress={imageQuality}
+                minimumValue={imageQualityMin}
+                maximumValue={imageQualityMax}
+              />
+            </View>
+          </View>
+        </View>
         <Button
           androidRootClassName="w-full"
           onPress={logout}
@@ -149,6 +152,9 @@ export default function Dashboard() {
           <Text>Log Out</Text>
         </Button>
         <View className="mt-4 w-full gap-1">
+          <Text className="text-center text-sm text-muted-foreground">
+            {isSettingsLoading ? "Loading..." : settings.address}
+          </Text>
           <Text className="text-center text-sm text-muted-foreground">
             App Version: {Constants.expoConfig?.version ?? "unknown"}
           </Text>
-- 
cgit v1.2.3-70-g09d2

