authorgravatar for 35393046+lnieuwenhuis@users.noreply.github.comLars Nieuwenhuis <35393046+lnieuwenhuis@users.noreply.github.com> 2026-09-07 09:18:17+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-07 00:18:17-07:00
logbc3dc2694b5d15613ef610d693d18ebd904b0d56
tree676bcc577c92608f2a14b00a2b8b5cb9749cd0d0
parentd8bc6831cd822b294d875364cf3aa0a17c999258
signature Signed by PGP key B5690EEEBB952194

fix(mobile): hide changed-files navigator and restore refresh in raw diff fallback (#9828)

Co-authored-by: James <jamescollard2005@gmail.com>

1 files changed, 50 insertions(+), 6 deletions(-)

apps/mobile/src/features/review/ReviewSheet.tsx+50-6
......@@ -23,6 +23,7 @@ import {
2323 FlatList,
2424 Platform,
2525 Pressable,
26 RefreshControl,
2627 ScrollView,
2728 type NativeSyntheticEvent,
2829 StyleSheet,
......@@ -399,7 +400,11 @@ export function ReviewSheet(props: ReviewSheetProps) {
399400 selectedSection,
400401 draftMessage,
401402 });
402 const NativeReviewDiffView = resolveNativeReviewDiffView()!;
403 // Resolution returns null while Expo registers the native view (or forever
404 // when the binary lacks it). Rendering a null component type crashes the
405 // app, so callers must fall back — ThreadFeed's ReviewCommentCard does the
406 // same check.
407 const NativeReviewDiffView = resolveNativeReviewDiffView();
403408 const nativeReviewDiffViewRef = useRef<NativeReviewDiffViewHandle>(null);
404409 const showcasedReviewDrawRef = useRef<string | null>(null);
405410 // Native pull-to-refresh on the diff surface (replaces the old Refresh menu item).
......@@ -597,11 +602,27 @@ export function ReviewSheet(props: ReviewSheetProps) {
597602 .filter((part): part is string => Boolean(part))
598603 .join(" · ");
599604
600 // The changed-files navigator lives in the workspace inspector column —
601 // the single right-hand pane per route — instead of an in-screen panel.
605 // The changed-files navigator drives the native diff surface via
606 // scrollToFile, so it is only useful when that surface resolved. In raw
607 // fallback mode the ref is necessarily null and the raw patch neither
608 // scrolls nor filters — registering the navigator would present working
609 // controls that cannot navigate.
602610 const showChangedFilesPane =
603 !showConnectionNotice && selectedSection !== null && parsedDiff.kind === "files";
611 !showConnectionNotice &&
612 selectedSection !== null &&
613 parsedDiff.kind === "files" &&
614 NativeReviewDiffView !== null;
604615 useRegisterWorkspaceInspector(showChangedFilesPane ? renderInspector : undefined);
616 // Raw fallback renders the patch inline with no inspector content, so the
617 // pane toggle would open an empty column — hide it in exactly that case.
618 const showChangedFilesToggle =
619 panes.supportsAuxiliaryPane &&
620 !(
621 !showConnectionNotice &&
622 selectedSection !== null &&
623 parsedDiff.kind === "files" &&
624 NativeReviewDiffView === null
625 );
605626
606627 const listHeader = useMemo(() => {
607628 const children: ReactElement[] = [];
......@@ -688,7 +709,7 @@ export function ReviewSheet(props: ReviewSheetProps) {
688709
689710 {!isAndroid && (showSectionToolbar || panes.supportsAuxiliaryPane || gitMenuAvailable) ? (
690711 <NativeHeaderToolbar placement="right">
691 {panes.supportsAuxiliaryPane ? (
712 {showChangedFilesToggle ? (
692713 <NativeHeaderToolbar.Button
693714 accessibilityLabel={
694715 panes.auxiliaryPaneVisible ? "Hide changed files" : "Show changed files"
......@@ -781,7 +802,7 @@ export function ReviewSheet(props: ReviewSheetProps) {
781802 onRetry={handleRetryEnvironment}
782803 />
783804 </View>
784 ) : selectedSection && parsedDiff.kind === "files" ? (
805 ) : selectedSection && parsedDiff.kind === "files" && NativeReviewDiffView ? (
785806 <View
786807 className="flex-1"
787808 style={{
......@@ -835,6 +856,16 @@ export function ReviewSheet(props: ReviewSheetProps) {
835856 }}
836857 showsVerticalScrollIndicator={false}
837858 className="flex-1"
859 refreshControl={
860 // The native diff surface owns pull-to-refresh via onPullToRefresh;
861 // the raw fallback (and empty states) need an explicit control —
862 // iOS has no other refresh affordance here (the explicit
863 // "Refresh current diff" menu is Android-only).
864 <RefreshControl
865 refreshing={isPullRefreshing}
866 onRefresh={() => void handlePullToRefresh()}
867 />
868 }
838869 >
839870 {listHeader}
840871 {!selectedSection ? (
......@@ -867,6 +898,19 @@ export function ReviewSheet(props: ReviewSheetProps) {
867898 </Text>
868899 </ScrollView>
869900 </View>
901 ) : parsedDiff.kind === "files" ? (
902 // The native diff surface could not be resolved on this binary;
903 // degrade to the raw patch instead of crashing the app.
904 <View className="gap-3 border-b border-border bg-card px-4 py-4">
905 <Text className="text-xs leading-normal text-foreground-muted">
906 Native diff view unavailable. Showing the raw patch.
907 </Text>
908 <ScrollView horizontal showsHorizontalScrollIndicator={false} bounces={false}>
909 <Text selectable className="font-mono text-xs leading-relaxed text-foreground">
910 {selectedSection?.diff ?? ""}
911 </Text>
912 </ScrollView>
913 </View>
870914 ) : null}
871915 </ScrollView>
872916 )}