| author | |
| committer | |
| log | 4bd0ecca19934dce38e16cd42eba5bf81c170d91 |
| tree | dd4f68e9e6a88dd31f1d2bdec4fc5bb512b7d810 |
| parent | 328dc27d63dd4b164d0211b56c8bc9100b74f3fe |
| signature | Signed by PGP key B5690EEEBB952194 |
8 files changed, 39 insertions(+), 18 deletions(-)
apps/mobile/src/features/cloud/ConnectOnboardingRouteScreen.tsx+22-10| ... | ... | @@ -54,15 +54,15 @@ function ConfiguredConnectOnboardingRouteScreen() { |
| 54 | 54 | cloudEnvironments: null, |
| 55 | 55 | }); |
| 56 | 56 | |
| 57 | // Pull-to-refresh tracks its own spinner instead of discovery's refreshing | |
| 58 | // flag, so background refreshes (e.g. the sign-in one) don't yank the | |
| 59 | // content down. | |
| 60 | const [isPullRefreshing, setIsPullRefreshing] = useState(false); | |
| 61 | const handlePullRefresh = useCallback(() => { | |
| 57 | const [isRefreshing, setIsRefreshing] = useState(false); | |
| 58 | const handleRefresh = useCallback(() => { | |
| 62 | 59 | void (async () => { |
| 63 | setIsPullRefreshing(true); | |
| 64 | await refreshRelayEnvironments(); | |
| 65 | setIsPullRefreshing(false); | |
| 60 | setIsRefreshing(true); | |
| 61 | try { | |
| 62 | await refreshRelayEnvironments(); | |
| 63 | } finally { | |
| 64 | setIsRefreshing(false); | |
| 65 | } | |
| 66 | 66 | })(); |
| 67 | 67 | }, [refreshRelayEnvironments]); |
| 68 | 68 | |
| ... | ... | @@ -87,7 +87,16 @@ function ConfiguredConnectOnboardingRouteScreen() { |
| 87 | 87 | {Platform.OS === "android" ? ( |
| 88 | 88 | <AndroidSheetHeader |
| 89 | 89 | title="Set up T3 Connect" |
| 90 | actions={[{ accessibilityLabel: "Close", icon: "xmark", onPress: handleClose }]} | |
| 90 | actions={[ | |
| 91 | { | |
| 92 | accessibilityLabel: "Refresh environments", | |
| 93 | disabled: isRefreshing, | |
| 94 | icon: "arrow.clockwise", | |
| 95 | loading: isRefreshing, | |
| 96 | onPress: handleRefresh, | |
| 97 | }, | |
| 98 | { accessibilityLabel: "Close", icon: "xmark", onPress: handleClose }, | |
| 99 | ]} | |
| 91 | 100 | /> |
| 92 | 101 | ) : ( |
| 93 | 102 | <NativeHeaderToolbar placement="right"> |
| ... | ... | @@ -95,6 +104,7 @@ function ConfiguredConnectOnboardingRouteScreen() { |
| 95 | 104 | </NativeHeaderToolbar> |
| 96 | 105 | )} |
| 97 | 106 | <ScrollView |
| 107 | nestedScrollEnabled | |
| 98 | 108 | alwaysBounceVertical |
| 99 | 109 | contentInsetAdjustmentBehavior="automatic" |
| 100 | 110 | showsVerticalScrollIndicator={false} |
| ... | ... | @@ -106,7 +116,9 @@ function ConfiguredConnectOnboardingRouteScreen() { |
| 106 | 116 | paddingTop: 16, |
| 107 | 117 | }} |
| 108 | 118 | refreshControl={ |
| 109 | <RefreshControl refreshing={isPullRefreshing} onRefresh={handlePullRefresh} /> | |
| 119 | Platform.OS === "ios" ? ( | |
| 120 | <RefreshControl refreshing={isRefreshing} onRefresh={handleRefresh} /> | |
| 121 | ) : undefined | |
| 110 | 122 | } |
| 111 | 123 | > |
| 112 | 124 | {isSignedIn ? ( |
apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx+1| ... | ... | @@ -212,6 +212,7 @@ export function ConnectionsNewRouteScreen({ |
| 212 | 212 | ]} |
| 213 | 213 | > |
| 214 | 214 | <ScrollView |
| 215 | nestedScrollEnabled | |
| 215 | 216 | contentInsetAdjustmentBehavior="automatic" |
| 216 | 217 | keyboardShouldPersistTaps="handled" |
| 217 | 218 | showsVerticalScrollIndicator={false} |
apps/mobile/src/features/threads/ThreadAgentsSheet.tsx+1| ... | ... | @@ -56,6 +56,7 @@ export function ThreadAgentsSheet({ route }: StaticScreenProps<AgentsTarget>) { |
| 56 | 56 | |
| 57 | 57 | const content = ( |
| 58 | 58 | <ScrollView |
| 59 | nestedScrollEnabled | |
| 59 | 60 | className="flex-1" |
| 60 | 61 | // The iOS header is translucent and floats over this view; UIKit has to |
| 61 | 62 | // inset the content or the first row sits underneath the title. |
apps/mobile/src/features/threads/ThreadQueueControl.tsx+1| ... | ... | @@ -179,6 +179,7 @@ export function ThreadQueueSheet({ route }: StaticScreenProps<QueueTarget>) { |
| 179 | 179 | queuedRuns.map(({ run }) => ({ id: run.id, ...rowLayouts.current.get(run.id) })); |
| 180 | 180 | const content = ( |
| 181 | 181 | <ScrollView |
| 182 | nestedScrollEnabled | |
| 182 | 183 | className="flex-1" |
| 183 | 184 | scrollEnabled={draggedRunId === null} |
| 184 | 185 | // The iOS header is translucent and floats over this view; UIKit has to |
apps/mobile/src/features/threads/git/GitBranchesSheet.tsx+1| ... | ... | @@ -84,6 +84,7 @@ export function GitBranchesSheet(_props: GitBranchesSheetProps) { |
| 84 | 84 | ) : null} |
| 85 | 85 | <MaterialScreenContent fitToContents> |
| 86 | 86 | <ScrollView |
| 87 | nestedScrollEnabled | |
| 87 | 88 | className="android:shrink android:grow-0 ios:flex-1" |
| 88 | 89 | keyboardShouldPersistTaps="handled" |
| 89 | 90 | showsVerticalScrollIndicator={false} |
apps/mobile/src/features/threads/git/GitCommitSheet.tsx+1| ... | ... | @@ -103,6 +103,7 @@ export function GitCommitSheet(_props: GitCommitSheetProps) { |
| 103 | 103 | ) : null} |
| 104 | 104 | <MaterialScreenContent fitToContents> |
| 105 | 105 | <ScrollView |
| 106 | nestedScrollEnabled | |
| 106 | 107 | className="android:shrink android:grow-0 ios:flex-1" |
| 107 | 108 | keyboardShouldPersistTaps="handled" |
| 108 | 109 | showsVerticalScrollIndicator={false} |
apps/mobile/src/features/threads/git/GitConfirmSheet.tsx+1| ... | ... | @@ -141,6 +141,7 @@ export function GitConfirmSheet(props: GitConfirmSheetProps) { |
| 141 | 141 | |
| 142 | 142 | <MaterialScreenContent fitToContents> |
| 143 | 143 | <ScrollView |
| 144 | nestedScrollEnabled | |
| 144 | 145 | className="android:shrink android:grow-0 ios:flex-1" |
| 145 | 146 | showsVerticalScrollIndicator={false} |
| 146 | 147 | contentContainerClassName="android:gap-2 android:p-2" |
apps/mobile/src/features/threads/git/GitOverviewSheet.tsx+11-8| ... | ... | @@ -252,21 +252,22 @@ function GitOverviewSheetContent(props: GitOverviewSheetProps) { |
| 252 | 252 | |
| 253 | 253 | const behindCount = gitStatus.data?.behindCount ?? 0; |
| 254 | 254 | |
| 255 | // Deterministic pull-to-refresh state. Tying RefreshControl to the query's | |
| 255 | // Deterministic refresh state. Tying RefreshControl to the query's | |
| 256 | 256 | // isPending flag left the spinner stuck (the status query reports pending |
| 257 | 257 | // during quiet background refreshes too). |
| 258 | const [isPullRefreshing, setIsPullRefreshing] = useState(false); | |
| 259 | const handlePullRefresh = useCallback(async () => { | |
| 260 | setIsPullRefreshing(true); | |
| 258 | const [isRefreshing, setIsRefreshing] = useState(false); | |
| 259 | const handleRefresh = useCallback(async () => { | |
| 260 | setIsRefreshing(true); | |
| 261 | 261 | try { |
| 262 | 262 | await gitActions.refreshSelectedThreadGitStatus(); |
| 263 | 263 | } finally { |
| 264 | setIsPullRefreshing(false); | |
| 264 | setIsRefreshing(false); | |
| 265 | 265 | } |
| 266 | 266 | }, [gitActions]); |
| 267 | 267 | |
| 268 | 268 | const content = ( |
| 269 | 269 | <ScrollView |
| 270 | nestedScrollEnabled | |
| 270 | 271 | alwaysBounceVertical |
| 271 | 272 | className="flex-1 android:bg-sheet-solid ios:bg-screen" |
| 272 | 273 | contentInsetAdjustmentBehavior={Platform.OS === "ios" ? "automatic" : "never"} |
| ... | ... | @@ -278,7 +279,9 @@ function GitOverviewSheetContent(props: GitOverviewSheetProps) { |
| 278 | 279 | gap: Platform.OS === "android" ? 8 : 14, |
| 279 | 280 | }} |
| 280 | 281 | refreshControl={ |
| 281 | <RefreshControl refreshing={isPullRefreshing} onRefresh={() => void handlePullRefresh()} /> | |
| 282 | Platform.OS === "ios" || isInspector ? ( | |
| 283 | <RefreshControl refreshing={isRefreshing} onRefresh={() => void handleRefresh()} /> | |
| 284 | ) : undefined | |
| 282 | 285 | } |
| 283 | 286 | > |
| 284 | 287 | <View |
| ... | ... | @@ -474,11 +477,11 @@ function GitOverviewSheetContent(props: GitOverviewSheetProps) { |
| 474 | 477 | { |
| 475 | 478 | id: "refresh", |
| 476 | 479 | title: "Refresh repository status", |
| 477 | attributes: { disabled: busy || isPullRefreshing }, | |
| 480 | attributes: { disabled: busy || isRefreshing }, | |
| 478 | 481 | }, |
| 479 | 482 | ]} |
| 480 | 483 | onPressAction={({ nativeEvent }) => { |
| 481 | if (nativeEvent.event === "refresh") void handlePullRefresh(); | |
| 484 | if (nativeEvent.event === "refresh") void handleRefresh(); | |
| 482 | 485 | }} |
| 483 | 486 | > |
| 484 | 487 | {(open) => ( |