diff --git a/mobile/src/source-control/MobileCommitDetailPage.tsx b/mobile/src/source-control/MobileCommitDetailPage.tsx
index 4f2ee5d511c..152d6d4aed7 100644
--- a/mobile/src/source-control/MobileCommitDetailPage.tsx
+++ b/mobile/src/source-control/MobileCommitDetailPage.tsx
@@ -34,6 +34,8 @@ type Props = {
commit: MobileGitHistoryItem
bottomInset: number
onBack: () => void
+ // Opens a file in the shared diff screen; rows stay inert when the host offers none.
+ onOpenFile?: (filePath: string) => void
}
function splitPath(path: string): { name: string; dir: string } {
@@ -57,7 +59,8 @@ export function MobileCommitDetailPage({
worktreeId,
commit,
bottomInset,
- onBack
+ onBack,
+ onOpenFile
}: Props) {
useMobileColorScheme()
const t = useMobileTranslation()
@@ -271,19 +274,33 @@ export function MobileCommitDetailPage({
{t('sourceControl.gitHistoryList.noFileChanges', 'No file changes')}
) : (
- loadedFiles.map((file) => )
+ loadedFiles.map((file) => (
+
+ ))
)}
)
}
-function CommitFileRow({ file }: { file: MobileGitChangedFile }) {
+function CommitFileRow({
+ file,
+ onOpen
+}: {
+ file: MobileGitChangedFile
+ onOpen?: (filePath: string) => void
+}) {
useMobileColorScheme()
const status = file.status ?? 'modified'
const { name, dir } = splitPath(file.path)
return (
-
+ [styles.fileRow, pressed && onOpen && styles.fileRowPressed]}
+ disabled={!onOpen}
+ onPress={() => onOpen?.(file.path)}
+ accessibilityRole={onOpen ? 'button' : undefined}
+ accessibilityLabel={file.path}
+ >
{STATUS_LABELS[status]}
@@ -301,7 +318,7 @@ function CommitFileRow({ file }: { file: MobileGitChangedFile }) {
) : null}
-
+
)
}
@@ -358,6 +375,7 @@ const styles = themedStyleSheet(() => ({
fontFamily: typography.monoFamily,
fontWeight: '600'
},
+ fileRowPressed: { backgroundColor: colors.bgRaised },
fileMain: { flex: 1, minWidth: 0 },
fileName: { color: colors.textPrimary, fontSize: typography.bodySize },
fileNameDeleted: { textDecorationLine: 'line-through', color: colors.textMuted },
diff --git a/mobile/src/source-control/MobileCommitsScreen.test.tsx b/mobile/src/source-control/MobileCommitsScreen.test.tsx
index 8bb0a4193b3..bb4c359916f 100644
--- a/mobile/src/source-control/MobileCommitsScreen.test.tsx
+++ b/mobile/src/source-control/MobileCommitsScreen.test.tsx
@@ -297,6 +297,35 @@ describe('MobileCommitsScreen', () => {
expect(list?.props.refreshControl.props.refreshing).toBe(false)
})
+ it("opens a commit's file in the shared diff screen against that commit", async () => {
+ const openDiffForFile = vi.fn()
+ const client = createFakeRpcClient()
+ client.sendRequest = routedSend(() => Promise.resolve(historyResponse('expandable')))
+ await act(async () => {
+ renderer = create(
+ createElement(MobileCommitsScreen, {
+ client,
+ connState: 'connected',
+ worktreeId: 'wt-1',
+ hostId: 'host-1',
+ bottomInset: 0,
+ openDiffForFile
+ })
+ )
+ await settle()
+ })
+ await openFirstCommit()
+ const fileRow = renderer?.root.find(
+ (node) => String(node.type) === 'Pressable' && node.props.accessibilityLabel === 'src/app.ts'
+ )
+ await act(async () => fileRow?.props.onPress())
+ expect(openDiffForFile).toHaveBeenCalledWith({
+ kind: 'commit',
+ filePath: 'src/app.ts',
+ commitOid: 'commit-1'
+ })
+ })
+
it('wipes commits when the worktree identity changes', async () => {
let historyCalls = 0
const sendRequest = routedSend(() => {
diff --git a/mobile/src/source-control/MobileCommitsScreen.tsx b/mobile/src/source-control/MobileCommitsScreen.tsx
index 100c78fe9ee..4f508f3db89 100644
--- a/mobile/src/source-control/MobileCommitsScreen.tsx
+++ b/mobile/src/source-control/MobileCommitsScreen.tsx
@@ -8,6 +8,7 @@ import type { RpcClient } from '../transport/rpc-client'
import type { ConnectionState } from '../transport/types'
import type { MobileGitHistoryItem } from './git-history-reply-schema'
import { MobileCommitDetailPage } from './MobileCommitDetailPage'
+import type { MobileDiffFileTarget } from './use-mobile-source-control-openers'
import { MobileGitHistoryList, type MobileGitHistoryListProps } from './MobileGitHistoryList'
type OpenCommit = (commit: MobileGitHistoryItem) => void
@@ -17,12 +18,14 @@ type Props = Omit & {
embedded?: boolean
// Set by a parent whose own commit page covers more than this list, e.g. the whole Source Control screen.
onOpenCommit?: OpenCommit
+ openDiffForFile?: (target: MobileDiffFileTarget) => void
}
// The branch's commits; a commit opens over them unless the parent hosts the commit page itself.
export const MobileCommitsScreen = memo(function MobileCommitsScreen({
embedded = false,
onOpenCommit,
+ openDiffForFile,
...props
}: Props) {
const list = (open: OpenCommit) =>
@@ -37,6 +40,7 @@ export const MobileCommitsScreen = memo(function MobileCommitsScreen({
worktreeId={props.worktreeId}
bottomInset={props.bottomInset}
padTop={false}
+ openDiffForFile={openDiffForFile}
>
{list}
@@ -58,6 +62,7 @@ export function MobileCommitPageHost({
worktreeId,
bottomInset,
padTop,
+ openDiffForFile,
children
}: {
client: RpcClient | null
@@ -66,6 +71,7 @@ export function MobileCommitPageHost({
bottomInset: number
// The page covers a screen-top header, so it pads under the status bar unless an ancestor already did.
padTop: boolean
+ openDiffForFile?: (target: MobileDiffFileTarget) => void
children: (openCommit: OpenCommit) => ReactNode
}) {
const pager = useOptionPager<'commit'>()
@@ -97,6 +103,11 @@ export function MobileCommitPageHost({
commit={commit}
bottomInset={bottomInset}
onBack={close}
+ onOpenFile={
+ openDiffForFile
+ ? (filePath) => openDiffForFile({ kind: 'commit', filePath, commitOid: commit.id })
+ : undefined
+ }
/>
) : null
return (
diff --git a/mobile/src/source-control/MobileSourceControlPanel.tsx b/mobile/src/source-control/MobileSourceControlPanel.tsx
index 91b66d76f70..0346e035393 100644
--- a/mobile/src/source-control/MobileSourceControlPanel.tsx
+++ b/mobile/src/source-control/MobileSourceControlPanel.tsx
@@ -317,6 +317,7 @@ export function MobileSourceControlPanel({
worktreeId={worktreeId}
bottomInset={insets.bottom}
padTop={!embedded}
+ openDiffForFile={state.openDiffForFile}
>
{(openCommit) => (