Skip to content

Commit 9bc0c33

Browse files
refactor(mobile): settings use web's pages and groups (#25686)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 5432d8e commit 9bc0c33

22 files changed

Lines changed: 342 additions & 289 deletions

‎apps/mobile/src/Stack.tsx‎

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ import { SettingsEnvironmentDetailRouteScreen } from "./features/settings/Settin
9797
import { SettingsEnvironmentsRouteScreen } from "./features/settings/SettingsEnvironmentsRouteScreen";
9898
import { SettingsFollowUpRouteScreen } from "./features/settings/SettingsFollowUpRouteScreen";
9999
import {
100-
SettingsEnvironmentAgentBehaviorRouteScreen,
101100
SettingsEnvironmentMaintenanceRouteScreen,
102-
SettingsEnvironmentNewThreadsRouteScreen,
101+
SettingsThreadsRouteScreen,
102+
SettingsWorktreesRouteScreen,
103103
SettingsEnvironmentSourceControlRouteScreen,
104104
} from "./features/settings/SettingsServerControlsRouteScreen";
105105
import {
@@ -125,7 +125,7 @@ import { UsageRouteScreen } from "./features/usage/UsageRouteScreen";
125125
import { SettingsAboutRouteScreen } from "./features/settings/SettingsAboutRouteScreen";
126126
import { SettingsNotificationsRouteScreen } from "./features/settings/SettingsNotificationsRouteScreen";
127127
import { SettingsRouteScreen } from "./features/settings/SettingsRouteScreen";
128-
import { SettingsThreadsRouteScreen } from "./features/settings/SettingsThreadsRouteScreen";
128+
import { SettingsLabsRouteScreen } from "./features/settings/ThreadSettingsSections";
129129
import { SettingsEnvironmentFilterProvider } from "./features/settings/settings-environment-filter";
130130
import { openSettings, settingsOpenIn } from "./features/settings/settings-navigation";
131131
import { DEFAULT_SETTINGS_PAGE } from "./features/workspace/workspace-tab-navigation";
@@ -261,25 +261,36 @@ const SETTINGS_SCREENS = {
261261
linking: "settings/environments/:environmentId",
262262
options: { ...SETTINGS_PAGE_OPTIONS, title: "Environment" },
263263
}),
264+
// Old links to New threads and Agent behavior open Threads, which absorbed them.
264265
SettingsEnvironmentNewThreads: createNativeStackScreen({
265-
screen: SettingsEnvironmentNewThreadsRouteScreen,
266+
screen: SettingsThreadsRouteScreen,
266267
linking: "settings/new-threads",
267-
options: { ...SETTINGS_PAGE_OPTIONS, title: "New threads" },
268+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Threads" },
268269
}),
269270
SettingsEnvironmentSourceControl: createNativeStackScreen({
270271
screen: SettingsEnvironmentSourceControlRouteScreen,
271272
linking: "settings/source-control",
272273
options: { ...SETTINGS_PAGE_OPTIONS, title: "Source control" },
273274
}),
274275
SettingsEnvironmentAgentBehavior: createNativeStackScreen({
275-
screen: SettingsEnvironmentAgentBehaviorRouteScreen,
276+
screen: SettingsThreadsRouteScreen,
276277
linking: "settings/agent-behavior",
277-
options: { ...SETTINGS_PAGE_OPTIONS, title: "Agent behavior" },
278+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Threads" },
279+
}),
280+
SettingsWorktrees: createNativeStackScreen({
281+
screen: SettingsWorktreesRouteScreen,
282+
linking: "settings/worktrees",
283+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Worktrees" },
284+
}),
285+
SettingsLabs: createNativeStackScreen({
286+
screen: SettingsLabsRouteScreen,
287+
linking: "settings/labs",
288+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Labs" },
278289
}),
279290
SettingsProviderAccounts: createNativeStackScreen({
280291
screen: SettingsProviderAccountsRouteScreen,
281292
linking: "settings/provider-accounts",
282-
options: { ...SETTINGS_PAGE_OPTIONS, title: "Provider accounts" },
293+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Providers" },
283294
}),
284295
SettingsEnvironmentMaintenance: createNativeStackScreen({
285296
screen: SettingsEnvironmentMaintenanceRouteScreen,
@@ -294,12 +305,12 @@ const SETTINGS_SCREENS = {
294305
SettingsThreads: createNativeStackScreen({
295306
screen: SettingsThreadsRouteScreen,
296307
linking: "settings/thread-preferences",
297-
options: { ...SETTINGS_PAGE_OPTIONS, title: "Thread behavior" },
308+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Threads" },
298309
}),
299310
SettingsAbout: createNativeStackScreen({
300311
screen: SettingsAboutRouteScreen,
301312
linking: "settings/about",
302-
options: { ...SETTINGS_PAGE_OPTIONS, title: "About T3 Code" },
313+
options: { ...SETTINGS_PAGE_OPTIONS, title: "About" },
303314
}),
304315
SettingsEnvironmentNew: createNativeStackScreen({
305316
screen: ConnectionsNewRouteScreen,
@@ -314,7 +325,7 @@ const SETTINGS_SCREENS = {
314325
linking: "settings/archive",
315326
options: {
316327
...SETTINGS_PAGE_OPTIONS,
317-
title: "Archived Threads",
328+
title: "Archive",
318329
},
319330
}),
320331
SettingsNavigation: createNativeStackScreen({
@@ -335,21 +346,21 @@ const SETTINGS_SCREENS = {
335346
linking: "settings/project-grouping",
336347
options: {
337348
...SETTINGS_PAGE_OPTIONS,
338-
title: "Organization",
349+
title: "General",
339350
},
340351
}),
341352
SettingsOrganization: createNativeStackScreen({
342353
screen: SettingsProjectGroupingRouteScreen,
343354
linking: "settings/organization",
344355
options: {
345356
...SETTINGS_PAGE_OPTIONS,
346-
title: "Organization",
357+
title: "General",
347358
},
348359
}),
349360
SettingsProjectOverview: createNativeStackScreen({
350361
screen: SettingsProjectOverviewRouteScreen,
351362
linking: "settings/project",
352-
options: { ...SETTINGS_PAGE_OPTIONS, title: "Project overview" },
363+
options: { ...SETTINGS_PAGE_OPTIONS, title: "Projects" },
353364
}),
354365
SettingsKeyboard: createNativeStackScreen({
355366
screen: SettingsKeyboardRouteScreen,
@@ -372,15 +383,15 @@ const SETTINGS_SCREENS = {
372383
linking: "settings/follow-ups",
373384
options: {
374385
...SETTINGS_PAGE_OPTIONS,
375-
title: "Follow-ups",
386+
title: "Chat",
376387
},
377388
}),
378389
SettingsScheduledTasks: createNativeStackScreen({
379390
screen: SettingsScheduledTasksRouteScreen,
380391
linking: "settings/scheduled-tasks",
381392
options: {
382393
...SETTINGS_PAGE_OPTIONS,
383-
title: "Scheduled Tasks",
394+
title: "Scheduled tasks",
384395
headerTitleStyle: { fontSize: 16, fontWeight: "800" },
385396
},
386397
}),

‎apps/mobile/src/components/ui/ListChoiceRow.tsx‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ export function ListChoiceRow(props: {
2626
onPress={props.onPress}
2727
android_ripple={{ color: rippleStyle.backgroundColor }}
2828
unstable_pressDelay={Platform.OS === "android" ? 50 : undefined}
29-
className={cn(
30-
props.selected ? "bg-subtle" : "bg-grouped-card",
31-
props.separated && "border-t border-border-subtle",
32-
)}
29+
// Like UIKit and Material lists, only the checkmark or radio marks the selected row.
30+
className={cn("bg-grouped-card", props.separated && "border-t border-border-subtle")}
3331
>
3432
<ListRowLayout
3533
label={props.label}

‎apps/mobile/src/features/settings/SettingsAboutRouteScreen.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function SettingsAboutRouteScreen() {
2323
const insets = useSafeAreaInsets();
2424

2525
return (
26-
<SettingsScreen title="About T3 Code">
26+
<SettingsScreen title="About">
2727
<ScrollView
2828
contentInsetAdjustmentBehavior="automatic"
2929
showsVerticalScrollIndicator={false}

‎apps/mobile/src/features/settings/SettingsFollowUpRouteScreen.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export function SettingsFollowUpRouteScreen() {
4545
{Platform.OS === "android" ? (
4646
<>
4747
<NativeStackScreenOptions options={{ headerShown: false }} />
48-
<AndroidScreenHeader title="Follow-ups" onBack={() => navigation.goBack()} />
48+
<AndroidScreenHeader title="Chat" onBack={() => navigation.goBack()} />
4949
</>
5050
) : null}
5151
<ScrollView

‎apps/mobile/src/features/settings/SettingsMicrophoneRouteScreen.tsx‎

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
microphoneOrder,
2020
} from "../../lib/microphonePriority";
2121
import { mobilePreferencesAtom, updateMobilePreferencesAtom } from "../../state/preferences";
22+
import { ListRowLayout } from "../../components/ui/ListRowLayout";
2223
import { SettingsActionRow } from "./components/SettingsActionRow";
2324
import { SettingsDragHandle } from "./components/SettingsDragHandle";
2425
import { SettingsSection } from "./components/SettingsSection";
@@ -252,10 +253,9 @@ function MicrophoneRow(props: {
252253
style={style}
253254
onLayout={(event) => props.onHeight(event.nativeEvent.layout.height)}
254255
className={cn(
255-
"flex-row items-center gap-4 pl-4",
256+
"flex-row items-center",
256257
props.position > 1 && !lifted && "border-t border-border-subtle",
257258
lifted && "bg-grouped-card shadow-md",
258-
!props.reorderable && "pr-4",
259259
)}
260260
>
261261
{props.editing && props.onForget ? (
@@ -264,7 +264,7 @@ function MicrophoneRow(props: {
264264
accessibilityLabel={`Forget ${title}`}
265265
hitSlop={8}
266266
onPress={props.onForget}
267-
className="active:opacity-70"
267+
className="pl-4 active:opacity-70"
268268
>
269269
<SymbolView
270270
name="xmark.circle.fill"
@@ -274,28 +274,20 @@ function MicrophoneRow(props: {
274274
/>
275275
</Pressable>
276276
) : props.editing ? (
277-
<View style={{ width: REMOVE_SIZE }} />
277+
<View className="pl-4">
278+
<View style={{ width: REMOVE_SIZE }} />
279+
</View>
278280
) : null}
279281
<View
280282
accessible
281283
accessibilityLabel={`${title}, ${kind.label}, ${props.position} of ${props.count}`}
282-
className="min-w-0 flex-1 flex-row items-center gap-4 py-4"
284+
className="min-w-0 flex-1"
283285
>
284-
<SymbolView
285-
name={kind.icon}
286-
size={22}
287-
tintColorClassName="accent-icon"
288-
type="monochrome"
289-
weight="regular"
286+
<ListRowLayout
287+
icon={kind.icon}
288+
label={title}
289+
description={isMicrophoneDevice(entry) ? kind.label : kind.rowDescription}
290290
/>
291-
<View className="min-w-0 flex-1 gap-0.5">
292-
<Text numberOfLines={1} className="text-lg text-foreground">
293-
{title}
294-
</Text>
295-
<Text numberOfLines={1} className="text-sm text-foreground-muted">
296-
{isMicrophoneDevice(entry) ? kind.label : kind.rowDescription}
297-
</Text>
298-
</View>
299291
</View>
300292
{props.reorderable ? (
301293
<SettingsDragHandle

‎apps/mobile/src/features/settings/SettingsProjectGroupingRouteScreen.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import { mobilePreferencesAtom, updateMobilePreferencesAtom } from "../../state/preferences";
1313
import { SettingsChoiceRow } from "./components/SettingsChoiceRow";
1414
import { SettingsSection } from "./components/SettingsSection";
15+
import { WorkingSectionSettings } from "./ThreadSettingsSections";
1516

1617
const GROUPING_OPTIONS: ReadonlyArray<{
1718
readonly mode: SidebarProjectGroupingMode;
@@ -45,7 +46,7 @@ export function SettingsProjectGroupingRouteScreen() {
4546
: null;
4647

4748
return (
48-
<SettingsScreen title="Organization">
49+
<SettingsScreen title="General">
4950
<ScrollView
5051
contentInsetAdjustmentBehavior="automatic"
5152
showsVerticalScrollIndicator={false}
@@ -66,6 +67,7 @@ export function SettingsProjectGroupingRouteScreen() {
6667
/>
6768
))}
6869
</SettingsSection>
70+
<WorkingSectionSettings />
6971
</ScrollView>
7072
</SettingsScreen>
7173
);

‎apps/mobile/src/features/settings/SettingsProjectOverviewRouteScreen.tsx‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,19 @@ export function SettingsProjectOverviewRouteScreen() {
8383
return (
8484
<>
8585
<SettingsEnvironmentFilterHeader />
86-
<SettingsScreen title="Project overview" trailing={<AndroidSettingsEnvironmentFilter />}>
86+
<SettingsScreen title="Projects" trailing={<AndroidSettingsEnvironmentFilter />}>
8787
<ScrollView
8888
contentInsetAdjustmentBehavior="automatic"
8989
showsVerticalScrollIndicator={false}
9090
className="flex-1"
9191
contentContainerClassName="gap-6 px-5 pt-4"
9292
contentContainerStyle={{ paddingBottom: Math.max(insets.bottom, 18) + 18 }}
9393
>
94-
{members.length === 0 ? (
94+
{selectedProjectKey === null ? (
95+
<Text className="px-2 text-base text-foreground-muted">
96+
Choose a project with the filter above to manage its name, checkouts and removal.
97+
</Text>
98+
) : members.length === 0 ? (
9599
<Text className="px-2 text-base text-foreground-muted">
96100
This project has no checkout on the selected connected environments. Change the filter
97101
above.

‎apps/mobile/src/features/settings/SettingsProviderAccountsRouteScreen.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function SettingsProviderAccountsRouteScreen() {
3838
return (
3939
<>
4040
<SettingsEnvironmentFilterHeader />
41-
<SettingsScreen title="Provider accounts" trailing={<AndroidSettingsEnvironmentFilter />}>
41+
<SettingsScreen title="Providers" trailing={<AndroidSettingsEnvironmentFilter />}>
4242
<ScreenScrollView
4343
className="flex-1"
4444
contentInsetAdjustmentBehavior="automatic"

‎apps/mobile/src/features/settings/SettingsRouteScreen.tsx‎

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ function SettingsList(props: { readonly connections: readonly SettingsListRow[]
185185
}}
186186
>
187187
{sections.length ? (
188-
sections.map((section) => (
189-
<SettingsSection key={section.title ?? "tabs"} title={section.title}>
188+
sections.map((section, index) => (
189+
<SettingsSection key={section.title ?? `untitled-${index}`} title={section.title}>
190190
{section.rows.map(({ id, ...row }) => (
191191
<SettingsRow key={id} {...row} />
192192
))}
@@ -229,11 +229,13 @@ function useSettingsIndexSections(): SettingsListSection[] {
229229
): SettingsListRow => ({ id: target, icon, label, target, ...extra });
230230
const serverPage = (target: SettingsPageTarget, icon: SettingsListRow["icon"], label: string) =>
231231
page(target, icon, label, { disabled: noServerTargets });
232+
// The same pages and groups as Settings on web, minus what mobile has no setting for.
232233
return [
233234
{
234-
title: "Interface",
235235
rows: [
236+
page("SettingsOrganization", "gearshape", "General"),
236237
page("SettingsAppearance", "paintbrush", "Appearance"),
238+
page("SettingsFollowUp", "bubble.left.and.bubble.right", "Chat"),
237239
...(navigationCustomizationAvailable()
238240
? [page("SettingsNavigation", "line.3.horizontal", "Navigation tabs")]
239241
: []),
@@ -246,34 +248,33 @@ function useSettingsIndexSections(): SettingsListSection[] {
246248
],
247249
},
248250
{
249-
title: "Automations",
250-
rows: [page("SettingsScheduledTasks", "clock", "Scheduled tasks")],
251-
},
252-
{
253-
title: "Projects & threads",
251+
title: "Agents",
254252
rows: [
255-
...(selectedProjectKey !== null
256-
? [page("SettingsProjectOverview", "folder", "Overview", { value: projectLabel })]
257-
: []),
258-
page("SettingsOrganization", "folder", "Organization"),
259-
page("SettingsThreads", "text.bubble", "Thread behavior"),
260-
page("SettingsFollowUp", "arrow.turn.left.up", "Follow-ups"),
261-
page("SettingsArchive", "archivebox", "Archived Threads"),
253+
serverPage("SettingsProviderAccounts", "person.crop.circle", "Providers"),
254+
serverPage("SettingsThreads", "text.bubble", "Threads"),
255+
page("SettingsScheduledTasks", "clock", "Scheduled tasks"),
262256
],
263257
},
264258
{
265-
title: "Server settings",
259+
title: "Code",
266260
rows: [
267-
serverPage("SettingsProviderAccounts", "person.crop.circle", "Provider accounts"),
268-
serverPage("SettingsEnvironmentNewThreads", "text.bubble", "New threads"),
261+
page(
262+
"SettingsProjectOverview",
263+
"folder",
264+
"Projects",
265+
selectedProjectKey !== null ? { value: projectLabel } : undefined,
266+
),
269267
serverPage("SettingsEnvironmentSourceControl", "arrow.triangle.branch", "Source control"),
270-
serverPage("SettingsEnvironmentAgentBehavior", "text.alignleft", "Agent behavior"),
271-
serverPage("SettingsEnvironmentMaintenance", "arrow.clockwise", "Maintenance"),
268+
serverPage("SettingsWorktrees", "square.on.square", "Worktrees"),
272269
],
273270
},
274271
{
275-
title: "App",
276-
rows: [page("SettingsAbout", "info.circle", "About T3 Code")],
272+
rows: [
273+
serverPage("SettingsEnvironmentMaintenance", "arrow.clockwise", "Maintenance"),
274+
page("SettingsLabs", "sparkles", "Labs"),
275+
page("SettingsAbout", "info.circle", "About"),
276+
page("SettingsArchive", "archivebox", "Archive"),
277+
],
277278
},
278279
];
279280
}

0 commit comments

Comments
 (0)