authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-17 20:20:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-17 20:20:02-07:00
log18dcc43ace0a7b0d93f2fd61907b2a4e27522936
tree6e509c34ea3e4ba4163f621ad2531b289152d6e4
parent767a5dbd00d0a2050745a2ae2e29050c5282b8c0
signature Signed by PGP key B5690EEEBB952194

refactor(mobile): share connection form fields (#12364)


3 files changed, 63 insertions(+), 56 deletions(-)

apps/mobile/src/features/connection/ConnectionEnvironmentRow.tsx+19-28
...@@ -10,7 +10,7 @@ import { useCallback, useState } from "react";...@@ -10,7 +10,7 @@ import { useCallback, useState } from "react";
10import { Platform, Alert, Pressable, View } from "react-native";10import { Platform, Alert, Pressable, View } from "react-native";
11import Animated, { FadeIn, FadeOut, LinearTransition } from "react-native-reanimated";11import Animated, { FadeIn, FadeOut, LinearTransition } from "react-native-reanimated";
1212
13import { AppText as Text, AppTextInput as TextInput } from "../../components/AppText";13import { AppText as Text } from "../../components/AppText";
14import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol";14import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol";
15import { MaterialButton } from "../../components/MaterialButton";15import { MaterialButton } from "../../components/MaterialButton";
16import { MaterialIconButton } from "../../components/MaterialIconButton";16import { MaterialIconButton } from "../../components/MaterialIconButton";
...@@ -18,6 +18,7 @@ import { ThemedSwitch } from "../../components/ThemedSwitch";...@@ -18,6 +18,7 @@ import { ThemedSwitch } from "../../components/ThemedSwitch";
18import { cn } from "../../lib/cn";18import { cn } from "../../lib/cn";
19import type { ConnectedEnvironmentSummary } from "../../state/remote-runtime-types";19import type { ConnectedEnvironmentSummary } from "../../state/remote-runtime-types";
20import { serverEnvironment } from "../../state/server";20import { serverEnvironment } from "../../state/server";
21import { ConnectionFormField } from "./ConnectionFormField";
21import { ConnectionStatusDot } from "./ConnectionStatusDot";22import { ConnectionStatusDot } from "./ConnectionStatusDot";
2223
23function connectionStatusLabel(environment: ConnectedEnvironmentSummary): string | null {24function connectionStatusLabel(environment: ConnectedEnvironmentSummary): string | null {
...@@ -152,34 +153,24 @@ export function ConnectionEnvironmentRow(props: {...@@ -152,34 +153,24 @@ export function ConnectionEnvironmentRow(props: {
152 </Text>153 </Text>
153 ) : (154 ) : (
154 <>155 <>
155 <View className="gap-1.5">156 <ConnectionFormField
156 <Text className="text-2xs font-t3-bold tracking-[0.8px] uppercase text-foreground-muted">157 label="Label"
157 Label158 autoCapitalize="words"
158 </Text>159 autoCorrect={false}
159 <TextInput160 placeholder="My MacBook"
160 autoCapitalize="words"161 value={label}
161 autoCorrect={false}162 onChangeText={setLabel}
162 placeholder="My MacBook"163 />
163 value={label}
164 onChangeText={setLabel}
165 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-base text-foreground"
166 />
167 </View>
168164
169 <View className="gap-1.5">165 <ConnectionFormField
170 <Text className="text-2xs font-t3-bold tracking-[0.8px] uppercase text-foreground-muted">166 label="URL"
171 URL167 autoCapitalize="none"
172 </Text>168 autoCorrect={false}
173 <TextInput169 keyboardType="url"
174 autoCapitalize="none"170 placeholder="192.168.1.100:8080"
175 autoCorrect={false}171 value={url}
176 keyboardType="url"172 onChangeText={setUrl}
177 placeholder="192.168.1.100:8080"173 />
178 value={url}
179 onChangeText={setUrl}
180 className="rounded-[14px] border border-input-border bg-input px-4 py-3 text-base text-foreground"
181 />
182 </View>
183 </>174 </>
184 )}175 )}
185176
apps/mobile/src/features/connection/ConnectionFormField.tsx created+25
...@@ -0,0 +1,25 @@
1import { View } from "react-native";
2
3import { AppText, AppTextInput, type AppTextInputProps } from "../../components/AppText";
4import { cn } from "../../lib/cn";
5
6type ConnectionFormFieldProps = Omit<AppTextInputProps, "className"> & {
7 readonly label: string;
8 readonly className?: string;
9};
10
11/** Labeled connection input with a native wrapper retained inside form sheets. */
12export function ConnectionFormField({ label, className, ...inputProps }: ConnectionFormFieldProps) {
13 return (
14 <View collapsable={false} className={cn("gap-1.5", className)}>
15 <AppText className="text-2xs font-t3-bold tracking-[0.8px] uppercase text-foreground-muted">
16 {label}
17 </AppText>
18 <AppTextInput
19 accessibilityLabel={label}
20 {...inputProps}
21 className="rounded-[14px] px-4 py-3.5"
22 />
23 </View>
24 );
25}
apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx+19-28
...@@ -13,8 +13,9 @@ import { Alert, Linking, Platform, View } from "react-native";...@@ -13,8 +13,9 @@ import { Alert, Linking, Platform, View } from "react-native";
13import { useSafeAreaInsets } from "react-native-safe-area-context";13import { useSafeAreaInsets } from "react-native-safe-area-context";
14import { useUniwindTheme } from "../../lib/useUniwindTheme";14import { useUniwindTheme } from "../../lib/useUniwindTheme";
15import { SettingsScreen } from "../settings/components/SettingsScreen";15import { SettingsScreen } from "../settings/components/SettingsScreen";
16import { AppText as Text, AppTextInput as TextInput } from "../../components/AppText";16import { AppText as Text } from "../../components/AppText";
17import { ErrorBanner } from "../../components/ErrorBanner";17import { ErrorBanner } from "../../components/ErrorBanner";
18import { ConnectionFormField } from "./ConnectionFormField";
18import { ConnectionSheetButton } from "./ConnectionSheetButton";19import { ConnectionSheetButton } from "./ConnectionSheetButton";
19import { buildPairingUrl, extractPairingUrlFromQrPayload, parsePairingUrl } from "./pairing";20import { buildPairingUrl, extractPairingUrlFromQrPayload, parsePairingUrl } from "./pairing";
20import { useRemoteConnections } from "../../state/use-remote-environment-registry";21import { useRemoteConnections } from "../../state/use-remote-environment-registry";
...@@ -262,34 +263,24 @@ export function ConnectionsNewRouteScreen({...@@ -262,34 +263,24 @@ export function ConnectionsNewRouteScreen({
262 )263 )
263 ) : (264 ) : (
264 <View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">265 <View collapsable={false} className="gap-4 rounded-[24px] bg-card p-4">
265 <View collapsable={false} className="gap-1.5">266 <ConnectionFormField
266 <Text className="text-2xs font-t3-bold tracking-[0.8px] uppercase text-foreground-muted">267 label="Host"
267 Host268 autoCapitalize="none"
268 </Text>269 autoCorrect={false}
269 <TextInput270 keyboardType="url"
270 autoCapitalize="none"271 placeholder="192.168.1.100:8080"
271 autoCorrect={false}272 value={hostInput}
272 keyboardType="url"273 onChangeText={handleHostChange}
273 placeholder="192.168.1.100:8080"274 />
274 value={hostInput}
275 onChangeText={handleHostChange}
276 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
277 />
278 </View>
279275
280 <View collapsable={false} className="gap-1.5">276 <ConnectionFormField
281 <Text className="text-2xs font-t3-bold tracking-[0.8px] uppercase text-foreground-muted">277 label="Pairing code"
282 Pairing code278 autoCapitalize="none"
283 </Text>279 autoCorrect={false}
284 <TextInput280 placeholder="abc-123-xyz"
285 autoCapitalize="none"281 value={codeInput}
286 autoCorrect={false}282 onChangeText={handleCodeChange}
287 placeholder="abc-123-xyz"283 />
288 value={codeInput}
289 onChangeText={handleCodeChange}
290 className="rounded-[14px] border border-input-border bg-input px-4 py-3.5 text-base text-foreground"
291 />
292 </View>
293284
294 {pairingConnectionError ? <ErrorBanner message={pairingConnectionError} /> : null}285 {pairingConnectionError ? <ErrorBanner message={pairingConnectionError} /> : null}
295286