Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
1af518a
feat(mobile): workspace page with chat/diff tabs, ACP-backed home ses…
saddlepaddle Jul 11, 2026
e3268bc
fix(mobile): use ghost icon button for workspace-row new chat
saddlepaddle Jul 11, 2026
fffe582
feat(mobile): native workspace navigation — glass header + liquid gla…
saddlepaddle Jul 11, 2026
1c24aff
fix(mobile): drop custom header chrome on workspace page for native t…
saddlepaddle Jul 11, 2026
461acdd
fix(mobile): native workspace header — real back button, title+branch…
saddlepaddle Jul 11, 2026
7b06765
fix(mobile): blur workspace header backdrop, truncate title before to…
saddlepaddle Jul 11, 2026
fe5be7c
fix(mobile): drop workspace header blur, keep fully transparent bar
saddlepaddle Jul 11, 2026
c346563
feat(mobile): full workspace menu in header tridot, remove live-sessi…
saddlepaddle Jul 11, 2026
6e59fad
fix(mobile): align workspace row menu with header tridot (copy branch…
saddlepaddle Jul 11, 2026
9a3a948
fix(mobile): standardize workspace menus on the row-menu layout (rena…
saddlepaddle Jul 11, 2026
685911b
feat(mobile): workspace diff surface, consolidated workspace screen, …
saddlepaddle Jul 12, 2026
83535d3
fix(mobile): diff cache correctness + large-changeset fetch stampede
saddlepaddle Jul 12, 2026
184633c
fix(mobile): stable empty snapshot for viewed-files selector (infinit…
saddlepaddle Jul 12, 2026
f59cb32
fix(mobile): resolve commit avatars by member display name when git e…
saddlepaddle Jul 12, 2026
7a416c6
feat(mobile): syntax-highlighted diff rows with GitHub-style dual-ton…
saddlepaddle Jul 12, 2026
72c1c84
fix(mobile): hide composer action chip while expanded (overlap + resi…
saddlepaddle Jul 12, 2026
48238a2
feat(mobile): GitHub-parity diff viewer — draft review comments, hori…
saddlepaddle Jul 12, 2026
b77be25
fix(mobile): use AnimatedLegendList for sticky headers (reanimated sc…
saddlepaddle Jul 12, 2026
eda6ed9
fix(mobile): keep composer chip visible, glide it with a layout sprin…
saddlepaddle Jul 12, 2026
860d385
fix(mobile): extra chip clearance in expanded composer state
saddlepaddle Jul 12, 2026
7caf317
fix(mobile): widen expanded composer chip clearance
saddlepaddle Jul 12, 2026
0c446a2
fix(mobile): drive diff pan with PanResponder — dev-client worklets p…
saddlepaddle Jul 12, 2026
9dceb0e
fix(mobile): restore chip layout spring with z-order guard and wider …
saddlepaddle Jul 12, 2026
2c34228
fix(mobile): nudge expanded composer chip gap to 26px
saddlepaddle Jul 12, 2026
dc85ab8
chore(mobile): format composer chip className
saddlepaddle Jul 12, 2026
fe4d258
fix(mobile): drop in-list LOC summary row — lives in the native header
saddlepaddle Jul 12, 2026
31881b3
fix(mobile): drop stale renderItem deps after summary-row removal
saddlepaddle Jul 12, 2026
b5eca4b
perf(mobile): eager pipelined diff loading + exact fixed row heights …
saddlepaddle Jul 12, 2026
48ff6e6
fix(mobile): liquid-glass finish-review chip and jump button
saddlepaddle Jul 12, 2026
962a20f
fix(mobile): review overlay — green finish CTA beside larger jump but…
saddlepaddle Jul 12, 2026
85c6747
fix(mobile): review overlay buttons via native SwiftUI glass/glassPro…
saddlepaddle Jul 12, 2026
87b73ba
fix(mobile): review controls as native bottom toolbar bar buttons (pr…
saddlepaddle Jul 12, 2026
e605da3
fix(mobile): send-to-chat CTA as GitHub-style capsule with disclosure…
saddlepaddle Jul 12, 2026
7c9e7cf
fix(mobile): send-to-chat CTA back to native prominent bar button (cu…
saddlepaddle Jul 12, 2026
35ebdb8
fix(mobile): jump-to-file icon as doc-with-arrow
saddlepaddle Jul 12, 2026
022d110
feat(mobile): add flash-list 2.3.2 + bump diff font to 14px (renderer…
saddlepaddle Jul 12, 2026
d0a1dc3
fix(mobile): jump-to-file uses the SF jump glyph
saddlepaddle Jul 12, 2026
4f76b4a
fix(mobile): human route titles for back-button menus (Home, Chat)
saddlepaddle Jul 12, 2026
0f171c4
feat(mobile): rebuild diff renderer — hunk-segment text blobs + Flash…
saddlepaddle Jul 12, 2026
f347df1
fix(mobile): vertical commit glyph to match the timeline
saddlepaddle Jul 12, 2026
88ced00
fix(mobile): desktop-aligned file status badges, comment count under …
saddlepaddle Jul 12, 2026
50847c4
fix(mobile): typographic chevron on send-to-chat CTA
saddlepaddle Jul 12, 2026
de98865
fix(mobile): stable Workspace route title for nav menus, drop text ch…
saddlepaddle Jul 12, 2026
78e2462
fix(mobile): edge-only back gesture on diff screens so horizontal scr…
saddlepaddle Jul 12, 2026
ae6fe5a
fix(mobile): correctness fixes from diff-viewer review
saddlepaddle Jul 12, 2026
084652f
feat(mobile): native files-changed header, file bars, and tap menus
saddlepaddle Jul 14, 2026
1f81b1a
feat(mobile): animate diff section collapse and stabilize list item i…
saddlepaddle Jul 14, 2026
3bde13d
feat(mobile): animated cell container for diff section collapse
saddlepaddle Jul 21, 2026
58f5b6a
Merge remote-tracking branch 'origin/main' into setup-mobile-dev-servers
saddlepaddle Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions apps/mobile/app/(authenticated)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ export default function AuthenticatedLayout() {
<CollectionsProvider>
<PromptInputProvider>
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="(home)" />
{/* Root headers are hidden — `title` here only names routes in
back-button long-press menus (otherwise raw route names leak,
e.g. "(home)"). */}
<Stack.Screen name="(home)" options={{ title: "Home" }} />
<Stack.Screen
name="settings/index"
options={settingsScreenOptions("Settings")}
Expand All @@ -53,23 +56,35 @@ export default function AuthenticatedLayout() {
/>
<Stack.Screen
name="workspace/[id]/chat/[sessionId]"
options={{ ...glassHeaderOptions, title: "" }}
options={{ ...glassHeaderOptions, title: "Chat" }}
/>
<Stack.Screen
name="workspace/[id]/chat/acp/[sessionId]"
options={{ ...glassHeaderOptions, title: "" }}
options={{ ...glassHeaderOptions, title: "Chat" }}
/>
<Stack.Screen
name="workspace/[id]/diff"
options={{ ...glassHeaderOptions, title: "Changes" }}
/>
<Stack.Screen
name="workspace/[id]/files-changed"
options={{ ...glassHeaderOptions, title: "Files changed" }}
options={{
// Solid themed header (matches the sticky file bars), not glass.
headerShown: true,
headerBackButtonDisplayMode: "minimal",
headerShadowVisible: false,
title: "Files changed",
// Right-swipes are horizontal diff scrolling — back stays edge-only.
fullScreenGestureEnabled: false,
}}
/>
<Stack.Screen
name="workspace/[id]/file"
options={{ ...glassHeaderOptions, title: "" }}
options={{
...glassHeaderOptions,
title: "",
fullScreenGestureEnabled: false,
}}
/>
<Stack.Screen
name="workspace/[id]/commits"
Expand All @@ -81,6 +96,36 @@ export default function AuthenticatedLayout() {
title: "Commits",
}}
/>
<Stack.Screen
name="workspace/[id]/line-comment"
options={{
presentation: "formSheet",
sheetAllowedDetents: [0.75],
sheetGrabberVisible: true,
...glassHeaderOptions,
title: "Add comment",
}}
/>
<Stack.Screen
name="workspace/[id]/finish-review"
options={{
presentation: "formSheet",
sheetAllowedDetents: [0.75],
sheetGrabberVisible: true,
...glassHeaderOptions,
title: "Finish review",
}}
/>
<Stack.Screen
name="workspace/[id]/jump-to-file"
options={{
presentation: "formSheet",
sheetAllowedDetents: [0.75],
sheetGrabberVisible: true,
...glassHeaderOptions,
title: "Jump to file",
}}
/>
</Stack>
</PromptInputProvider>
</CollectionsProvider>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { FinishReviewSheet } from "@/screens/(authenticated)/workspace/[id]/finish-review";

export default FinishReviewSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { JumpToFileSheet } from "@/screens/(authenticated)/workspace/[id]/jump-to-file";

export default JumpToFileSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { LineCommentSheet } from "@/screens/(authenticated)/workspace/[id]/line-comment";

export default LineCommentSheet;
Binary file modified apps/mobile/components/ai-elements/code-block.tsx
Binary file not shown.
1 change: 1 addition & 0 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@shikijs/core": "4.2.0",
"@shikijs/langs": "4.2.0",
"@shikijs/themes": "4.2.0",
"@shopify/flash-list": "2.3.2",
"@superset/auth": "workspace:*",
"@superset/db": "workspace:*",
"@superset/host-client": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,16 @@ import {
StyleSheet,
View,
} from "react-native";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import Animated, {
FadeIn,
FadeOut,
LinearTransition,
} from "react-native-reanimated";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { usePromptInputController } from "@/components/ai-elements/prompt-input";
import type { HostWorkspaceItem } from "@/hooks/useHostWorkspaces";
import { getHostServiceClientByUrl } from "@/lib/host-service/client";
import { cn } from "@/lib/utils";
import { useAfterTransitionEnd } from "@/screens/(authenticated)/(home)/hooks/useAfterTransitionEnd";
import {
type ChatTarget,
Expand Down Expand Up @@ -334,7 +339,26 @@ export function NewChatWidget({
className="px-3"
style={{ paddingBottom: focused ? 8 : insets.bottom + 8 }}
>
{above ? <View className="flex-row pb-2 pl-1">{above}</View> : null}
{/* The pill resizes natively (SwiftUI spring) while RN relayouts land
in discrete jumps — the layout spring makes the chip glide between
those jumps; z-10 keeps mid-animation frames above the glass. */}
{above ? (
<Animated.View
className="z-10"
layout={LinearTransition.springify().duration(350)}
>
{/* Extra clearance while expanded: the settled glass renders
taller than the frame matchContents reports. */}
<View
className={cn(
"flex-row pl-1",
expanded ? "pb-[26px]" : "pb-2.5",
)}
>
{above}
</View>
</Animated.View>
) : null}
<Host matchContents={{ vertical: true }} style={{ width: "100%" }}>
<VStack
spacing={0}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { type ComponentProps, type ReactNode, useRef } from "react";
import { Pressable, StyleSheet } from "react-native";
import {
Pressable,
type StyleProp,
StyleSheet,
type ViewStyle,
} from "react-native";
import Animated, {
useAnimatedStyle,
useSharedValue,
Expand All @@ -17,11 +22,13 @@ const HOLD_FADE_MS = 150;

export function PressableScale({
children,
style,
onPressIn,
onPressOut,
...props
}: Omit<ComponentProps<typeof Pressable>, "children"> & {
}: Omit<ComponentProps<typeof Pressable>, "children" | "style"> & {
children?: ReactNode;
style?: StyleProp<ViewStyle>;
}) {
const pressed = useSharedValue(0);
const holdFadeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
Expand All @@ -35,7 +42,7 @@ export function PressableScale({
return (
<AnimatedPressable
{...props}
style={containerStyle}
style={[style, containerStyle]}
onPressIn={(event) => {
pressed.value = withTiming(1, { duration: PRESS_IN_MS });
if (holdFadeTimer.current) clearTimeout(holdFadeTimer.current);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ export function WorkspaceScreen() {

return (
<View className="bg-background flex-1">
<Stack.Screen
options={{ ...glassHeaderOptions, title: workspace?.name ?? "" }}
>
<Stack.Screen options={{ ...glassHeaderOptions, title: "Workspace" }}>
<Stack.Title asChild>
<View className="max-w-64 items-center">
<Text className="font-semibold text-[17px]" numberOfLines={1}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQueries } from "@tanstack/react-query";
import { Stack, useLocalSearchParams, useRouter } from "expo-router";
import { ArrowRight, GitCommitHorizontal } from "lucide-react-native";
import { ArrowRight, GitCommitVertical } from "lucide-react-native";
import { useMemo } from "react";
import { FlatList, View } from "react-native";
import { Icon } from "@/components/ui/icon";
Expand Down Expand Up @@ -68,7 +68,7 @@ export function CommitsSheet() {
<Text className="font-semibold text-[17px]">Commits</Text>
<View className="flex-row items-center gap-1.5">
<Icon
as={GitCommitHorizontal}
as={GitCommitVertical}
className="text-muted-foreground size-3.5"
/>
<Text className="text-muted-foreground text-xs">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { View } from "react-native";
import { Text } from "@/components/ui/text";
import { cn } from "@/lib/utils";

// Mirrors the desktop changes-view language (ChangesView/utils/status.tsx):
// VS Code-style boxed glyphs — green +, yellow dot, red −, blue →, purple copy.
const STATUS_STYLE: Record<string, { glyph: string; className: string }> = {
added: { glyph: "+", className: "border-green-400 text-green-400" },
untracked: { glyph: "+", className: "border-green-400 text-green-400" },
modified: { glyph: "•", className: "border-yellow-400 text-yellow-400" },
deleted: { glyph: "−", className: "border-red-400 text-red-400" },
renamed: { glyph: "→", className: "border-blue-400 text-blue-400" },
copied: { glyph: "⧉", className: "border-purple-400 text-purple-400" },
};

const FALLBACK_STYLE = {
glyph: "•",
className: "border-muted-foreground text-muted-foreground",
};

export function FileStatusBadge({ status }: { status: string }) {
const style = STATUS_STYLE[status] ?? FALLBACK_STYLE;
return (
<View
className={cn(
"size-5 items-center justify-center rounded border-[1.5px]",
style.className,
)}
>
<Text className={cn("font-bold text-[11px]", style.className)}>
{style.glyph}
</Text>
</View>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { FileStatusBadge } from "./FileStatusBadge";
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
Circle,
CircleDot,
FileDiff,
GitCommitHorizontal,
GitCommitVertical,
XCircle,
} from "lucide-react-native";
import { useCallback, useState } from "react";
Expand Down Expand Up @@ -141,7 +141,7 @@ export function WorkspaceDiffScreen() {
}
/>
<CardRow
icon={GitCommitHorizontal}
icon={GitCommitVertical}
label={
commits.length === 1 ? "1 commit" : `${commits.length} commits`
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useQuery } from "@tanstack/react-query";
import * as Clipboard from "expo-clipboard";
import { Stack, useLocalSearchParams } from "expo-router";
import { ActivityIndicator, ScrollView, View } from "react-native";
import { ActivityIndicator, ScrollView, Share, View } from "react-native";
import { CodeBlockContent } from "@/components/ai-elements/code-block";
import { Text } from "@/components/ui/text";
import { useWorkspaceHost } from "@/hooks/useWorkspaceHost";
Expand All @@ -10,38 +10,7 @@ import {
getHostServiceClientByUrl,
} from "@/lib/host-service/client";
import type { ChangesetSource } from "../hooks/useWorkspaceChangeset";

const LANGUAGE_BY_EXTENSION: Record<string, string> = {
ts: "typescript",
mts: "typescript",
cts: "typescript",
tsx: "tsx",
js: "javascript",
mjs: "javascript",
cjs: "javascript",
jsx: "tsx",
json: "json",
jsonc: "json",
md: "markdown",
mdx: "markdown",
py: "python",
rs: "rust",
go: "go",
css: "css",
html: "html",
yml: "yaml",
yaml: "yaml",
sql: "sql",
sh: "bash",
bash: "bash",
zsh: "bash",
diff: "diff",
};

function languageForPath(path: string): string {
const extension = path.split(".").pop()?.toLowerCase() ?? "";
return LANGUAGE_BY_EXTENSION[extension] ?? "text";
}
import { languageForPath } from "../utils/languageForPath";

export function FileViewerScreen() {
const { id, path, source } = useLocalSearchParams<{
Expand Down Expand Up @@ -75,25 +44,56 @@ export function FileViewerScreen() {

const contents = query.data?.newFile.contents ?? "";
const fileName = path?.split("/").pop() ?? "File";
const directory = path?.includes("/")
? path.slice(0, path.lastIndexOf("/"))
: null;

return (
<>
<Stack.Screen options={{ title: fileName }} />
<Stack.Toolbar placement="right">
<Stack.Toolbar.Button
icon="doc.on.doc"
accessibilityLabel="Copy path"
onPress={() => void Clipboard.setStringAsync(path ?? "")}
/>
</Stack.Toolbar>
<Stack.Screen options={{ title: fileName }}>
<Stack.Title asChild>
<View className="max-w-72 items-center">
<Text className="font-semibold text-[15px]" numberOfLines={1}>
{fileName}
</Text>
{directory ? (
<Text
className="text-muted-foreground text-[10.5px]"
numberOfLines={1}
>
{directory}
</Text>
) : null}
</View>
</Stack.Title>
<Stack.Toolbar placement="right">
<Stack.Toolbar.Menu icon="ellipsis" accessibilityLabel="File actions">
<Stack.Toolbar.MenuAction
icon="doc.on.doc"
onPress={() => void Clipboard.setStringAsync(path ?? "")}
>
Copy relative path
</Stack.Toolbar.MenuAction>
<Stack.Toolbar.MenuAction
icon="doc.on.doc"
onPress={() => void Clipboard.setStringAsync(fileName)}
>
Copy file name
</Stack.Toolbar.MenuAction>
<Stack.Toolbar.MenuAction
icon="square.and.arrow.up"
onPress={() => void Share.share({ message: contents })}
>
Share via…
</Stack.Toolbar.MenuAction>
</Stack.Toolbar.Menu>
</Stack.Toolbar>
</Stack.Screen>
<ScrollView
className="bg-background flex-1"
contentInsetAdjustmentBehavior="automatic"
contentContainerStyle={{ paddingBottom: 48 }}
>
<Text className="text-muted-foreground px-4 pb-2 pt-1 text-xs">
{path}
</Text>
{query.isLoading ? (
<View className="items-center py-20">
<ActivityIndicator />
Expand Down
Loading
Loading