From 06ee048afc2bc68f56ba0a08021970ed88f17594 Mon Sep 17 00:00:00 2001 From: Yuzu Date: Tue, 30 Jun 2026 21:29:57 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20demo=20mode=20anonymi?= =?UTF-8?q?zation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/config/appConfig.ts | 2 + .../src/features/auth/AccountSwitcher.tsx | 63 ++++++++------ .../src/features/friends/FriendsSidebar.tsx | 29 ++++--- .../src/features/profile/ProfileView.tsx | 86 ++++++++++--------- .../src/features/settings/SettingsView.tsx | 16 +++- src/renderer/src/lib/debugSettings.ts | 14 +++ src/renderer/src/lib/demoMode.ts | 64 ++++++++++++++ .../src/lib/i18n/locales/en/settings.json | 4 +- .../src/lib/i18n/locales/ja/settings.json | 4 +- .../src/lib/i18n/locales/th/settings.json | 4 +- src/shared/types/appConfig.ts | 1 + 11 files changed, 205 insertions(+), 82 deletions(-) create mode 100644 src/renderer/src/lib/demoMode.ts diff --git a/src/main/config/appConfig.ts b/src/main/config/appConfig.ts index fec1f2b..15b825d 100644 --- a/src/main/config/appConfig.ts +++ b/src/main/config/appConfig.ts @@ -14,6 +14,7 @@ const DEFAULT_PREFERENCES: AppPreferences = { accent: null, locale: DEFAULT_LOCALE, showDebugNav: false, + demoMode: false, }; const DEFAULTS: StoredConfig = { gamePath: null, @@ -30,6 +31,7 @@ function normalizePreferences(raw: Partial | undefined): AppPref accent: accent && /^#[\da-f]{6}$/i.test(accent) ? accent : null, locale: isAppLocale(locale) ? locale : DEFAULT_LOCALE, showDebugNav: raw?.showDebugNav === true, + demoMode: raw?.demoMode === true, }; } diff --git a/src/renderer/src/features/auth/AccountSwitcher.tsx b/src/renderer/src/features/auth/AccountSwitcher.tsx index 4b9f32e..21b6e02 100644 --- a/src/renderer/src/features/auth/AccountSwitcher.tsx +++ b/src/renderer/src/features/auth/AccountSwitcher.tsx @@ -5,6 +5,8 @@ import { Avatar, StatusDot } from "../../components/ui"; import { useSelf } from "../../store/social"; import { statusMeta } from "../../lib/vrchat"; import { api } from "../../lib/api"; +import { useDemoMode } from "../../lib/debugSettings"; +import { demoName } from "../../lib/demoMode"; import type { UserStatus } from "../../../../shared/types/user"; const STATUS_CHOICES: UserStatus[] = ["join me", "active", "ask me", "busy"]; @@ -15,12 +17,16 @@ const MENU_ROW = export function AccountSwitcher() { const { accounts, switchAccount, removeAccount, beginAddAccount, logout } = useAuth(); const self = useSelf(); + const demoMode = useDemoMode(); const [open, setOpen] = useState(false); const [showAccounts, setShowAccounts] = useState(false); const active = accounts.accounts.find((a) => a.id === accounts.activeId); const others = accounts.accounts.filter((a) => a.id !== accounts.activeId); const status = self?.status ?? "offline"; + const activeName = active ? (demoMode ? demoName(active.id) : active.displayName) : "Account"; + const activeIcon = demoMode ? undefined : active?.userIcon; + const activeSub = demoMode ? statusMeta[status].label : self?.statusDescription || statusMeta[status].label; function close() { setOpen(false); @@ -39,7 +45,7 @@ export function AccountSwitcher() { aria-expanded={open} > - + - {active?.displayName ?? "Account"} + {activeName} - {self?.statusDescription || statusMeta[status].label} + {activeSub}
- {others.map((a) => ( -
- - -
- ))} + + +
+ ); + })} ) : null} diff --git a/src/renderer/src/features/friends/FriendsSidebar.tsx b/src/renderer/src/features/friends/FriendsSidebar.tsx index 2b6184d..953bfa3 100644 --- a/src/renderer/src/features/friends/FriendsSidebar.tsx +++ b/src/renderer/src/features/friends/FriendsSidebar.tsx @@ -6,6 +6,8 @@ import { useFriends, useSelf } from "../../store/social"; import { useWorldName } from "../../store/worlds"; import { parseLocation, type UserProfile } from "../../../../shared/types/user"; import { useT } from "../../lib/i18n"; +import { useDemoMode } from "../../lib/debugSettings"; +import { anonymizeUserForDemo } from "../../lib/demoMode"; import { useUserMenu } from "./useUserMenu"; import { useFriendsGrouped } from "./useFriendsGrouped"; @@ -19,6 +21,7 @@ export function FriendsSidebar({ onOpen }: { onOpen: (id: string) => void }) { const t = useT(); const friends = useFriends(); const self = useSelf(); + const demoMode = useDemoMode(); const selfId = self?.id; const { online, offline, instances, alone } = useFriendsGrouped(friends, self); @@ -40,8 +43,8 @@ export function FriendsSidebar({ onOpen }: { onOpen: (id: string) => void }) { const openContextMenu = useCallback((e: React.MouseEvent, friend: UserProfile) => { e.preventDefault(); e.stopPropagation(); - setContextMenu({ x: e.clientX, y: e.clientY, friend }); - }, []); + setContextMenu({ x: e.clientX, y: e.clientY, friend: demoMode ? anonymizeUserForDemo(friend) : friend }); + }, [demoMode]); return (