From fe69ca8ce88b51b0117aebfbb512fef16b4ebb35 Mon Sep 17 00:00:00 2001 From: xuatz Date: Thu, 17 Jul 2025 17:24:33 +0900 Subject: feat(mobile): Add user setting for default bookmark view mode (#1723) * feat(mobile): add user setting for default bookmark view mode * regen db migration script * clean up implementation * Update docs/docs/07-Development/01-setup.md * Update GEMINI.md * use local setting instead of storing value in db * improve start-dev.sh to also handle for db migration * rename mobileBookmarkClickDefaultViewMode to defaultBookmarkView for consistency --- apps/mobile/app/dashboard/(tabs)/settings.tsx | 27 ++++++++- apps/mobile/app/dashboard/_layout.tsx | 8 +++ .../app/dashboard/bookmarks/[slug]/index.tsx | 9 ++- .../dashboard/settings/bookmark-default-view.tsx | 68 ++++++++++++++++++++++ apps/mobile/lib/settings.ts | 11 +++- 5 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 apps/mobile/app/dashboard/settings/bookmark-default-view.tsx (limited to 'apps/mobile') diff --git a/apps/mobile/app/dashboard/(tabs)/settings.tsx b/apps/mobile/app/dashboard/(tabs)/settings.tsx index db118df8..b0ba94df 100644 --- a/apps/mobile/app/dashboard/(tabs)/settings.tsx +++ b/apps/mobile/app/dashboard/(tabs)/settings.tsx @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { Pressable, Text, View } from "react-native"; +import { ActivityIndicator, Pressable, Text, View } from "react-native"; import { Slider } from "react-native-awesome-slider"; import { useSharedValue } from "react-native-reanimated"; import { Link } from "expo-router"; @@ -67,6 +67,31 @@ export default function Dashboard() { + + + + + Default Bookmark View + + + {isSettingsLoading ? ( + + ) : ( + + {settings.defaultBookmarkView === "reader" + ? "Reader" + : "Browser"} + + )} + + + + + Upload Settings diff --git a/apps/mobile/app/dashboard/_layout.tsx b/apps/mobile/app/dashboard/_layout.tsx index 223101bd..eb1cbe4b 100644 --- a/apps/mobile/app/dashboard/_layout.tsx +++ b/apps/mobile/app/dashboard/_layout.tsx @@ -136,6 +136,14 @@ export default function Dashboard() { headerBackTitle: "Back", }} /> + ); } diff --git a/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx b/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx index 00954dd8..eafcfc19 100644 --- a/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx +++ b/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import { useState } from "react"; import { Alert, Keyboard, @@ -27,6 +27,7 @@ import FullPageSpinner from "@/components/ui/FullPageSpinner"; import { Input } from "@/components/ui/Input"; import { useToast } from "@/components/ui/Toast"; import { useAssetUrl } from "@/lib/hooks"; +import useAppSettings from "@/lib/settings"; import { api } from "@/lib/trpc"; import { MenuView } from "@react-native-menu/menu"; import { @@ -378,9 +379,11 @@ export default function ListView() { const { slug } = useLocalSearchParams(); const { colorScheme } = useColorScheme(); const isDark = colorScheme === "dark"; + const { settings } = useAppSettings(); - const [bookmarkLinkType, setBookmarkLinkType] = - useState("browser"); + const [bookmarkLinkType, setBookmarkLinkType] = useState( + settings.defaultBookmarkView, + ); if (typeof slug !== "string") { throw new Error("Unexpected param type"); diff --git a/apps/mobile/app/dashboard/settings/bookmark-default-view.tsx b/apps/mobile/app/dashboard/settings/bookmark-default-view.tsx new file mode 100644 index 00000000..c8c522cf --- /dev/null +++ b/apps/mobile/app/dashboard/settings/bookmark-default-view.tsx @@ -0,0 +1,68 @@ +import { Pressable, Text, View } from "react-native"; +import { useRouter } from "expo-router"; +import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView"; +import { Divider } from "@/components/ui/Divider"; +import { useToast } from "@/components/ui/Toast"; +import useAppSettings from "@/lib/settings"; +import { Check } from "lucide-react-native"; + +export default function BookmarkDefaultViewSettings() { + const router = useRouter(); + const { toast } = useToast(); + const { settings, setSettings } = useAppSettings(); + + const handleUpdate = async (mode: "reader" | "browser") => { + try { + await setSettings({ + ...settings, + defaultBookmarkView: mode, + }); + toast({ + message: "Default Bookmark View updated!", + showProgress: false, + }); + router.back(); + } catch { + toast({ + message: "Something went wrong", + variant: "destructive", + showProgress: false, + }); + } + }; + + const options = (["reader", "browser"] as const) + .map((mode) => { + const currentMode = settings.defaultBookmarkView; + const isChecked = currentMode === mode; + return [ + handleUpdate(mode)} + className="flex flex-row justify-between" + key={mode} + > + + {{ browser: "Browser", reader: "Reader" }[mode]} + + {isChecked && } + , + , + ]; + }) + .flat(); + options.pop(); + + return ( + + + + {options} + + + + ); +} diff --git a/apps/mobile/lib/settings.ts b/apps/mobile/lib/settings.ts index 58b0817f..51fa661f 100644 --- a/apps/mobile/lib/settings.ts +++ b/apps/mobile/lib/settings.ts @@ -10,6 +10,10 @@ const zSettingsSchema = z.object({ address: z.string(), imageQuality: z.number().optional().default(0.2), theme: z.enum(["light", "dark", "system"]).optional().default("system"), + defaultBookmarkView: z + .enum(["reader", "browser"]) + .optional() + .default("reader"), }); export type Settings = z.infer; @@ -23,7 +27,12 @@ interface AppSettingsState { const useSettings = create((set, get) => ({ settings: { isLoading: true, - settings: { address: "", imageQuality: 0.2, theme: "system" }, + settings: { + address: "", + imageQuality: 0.2, + theme: "system", + defaultBookmarkView: "reader", + }, }, setSettings: async (settings) => { await SecureStore.setItemAsync(SETTING_NAME, JSON.stringify(settings)); -- cgit v1.2.3-70-g09d2