import { router } from "expo-router";
import { useEffect } from "react";
import {
ActivityIndicator,
Pressable,
ScrollView,
StyleSheet,
Text,
TextInput,
View,
} from "react-native";
import { useSocket } from "@/contexts/SocketContext";
import { colors, monoFont } from "@/lib/theme";
import type { SavedComputer } from "@/lib/types";
function SavedComputerRow({
computer,
connecting,
onConnect,
onRemove,
}: {
computer: SavedComputer;
connecting: boolean;
onConnect: () => void;
onRemove: () => void;
}) {
return (
[styles.savedRowMain, pressed && styles.savedRowPressed]}
disabled={connecting}
onPress={onConnect}
>
{computer.name}
{computer.host}:{computer.port}
[styles.removeButton, pressed && styles.removeButtonPressed]}
disabled={connecting}
onPress={onRemove}
hitSlop={8}
>
×
);
}
export default function ConnectScreen() {
const {
host,
port,
computerName,
connected,
connecting,
error,
savedComputers,
setHost,
setPort,
setComputerName,
connect,
connectToSavedComputer,
removeSavedComputerEntry,
} = useSocket();
useEffect(() => {
if (connected) {
router.replace("/sessions");
}
}, [connected]);
return (
Pi Mobile
Remote control for Pi agents on your computer.
Computer name
Computer IP
Port
{error ? {error} : null}
void connect()}
>
{connecting ? (
) : (
Connect
)}
{savedComputers.length > 0 ? (
Saved computers
{savedComputers.map((computer) => (
void connectToSavedComputer(computer)}
onRemove={() => void removeSavedComputerEntry(computer.id)}
/>
))}
) : (
Successful connections are saved here so you can reconnect with one tap.
)}
);
}
const styles = StyleSheet.create({
scroll: {
flex: 1,
},
container: {
padding: 24,
gap: 16,
paddingBottom: 40,
},
brand: {
fontSize: 36,
fontWeight: "700",
color: "#f5f5f5",
marginTop: 24,
},
subtitle: {
color: "#a3a3a3",
fontSize: 16,
lineHeight: 22,
},
card: {
marginTop: 24,
gap: 12,
},
label: {
color: "#d4d4d4",
fontSize: 14,
fontWeight: "600",
},
input: {
backgroundColor: "#171717",
borderWidth: 1,
borderColor: "#262626",
borderRadius: 12,
color: "#f5f5f5",
paddingHorizontal: 14,
paddingVertical: 12,
fontSize: 16,
},
button: {
marginTop: 8,
backgroundColor: "#f5f5f5",
borderRadius: 12,
alignItems: "center",
justifyContent: "center",
minHeight: 48,
},
buttonDisabled: {
opacity: 0.7,
},
buttonText: {
color: "#0a0a0a",
fontSize: 16,
fontWeight: "700",
},
error: {
color: "#f87171",
fontSize: 14,
},
savedSection: {
marginTop: 8,
gap: 10,
},
savedSectionTitle: {
color: colors.textSecondary,
fontSize: 13,
fontWeight: "700",
textTransform: "uppercase",
letterSpacing: 0.6,
fontFamily: monoFont,
},
savedRow: {
flexDirection: "row",
alignItems: "center",
backgroundColor: colors.surface,
borderRadius: 12,
borderWidth: 1,
borderColor: colors.border,
overflow: "hidden",
},
savedRowMain: {
flex: 1,
paddingHorizontal: 14,
paddingVertical: 12,
gap: 2,
},
savedRowPressed: {
backgroundColor: colors.surfaceDeep,
},
savedName: {
color: colors.text,
fontSize: 16,
fontWeight: "600",
},
savedAddress: {
color: colors.textSecondary,
fontSize: 13,
fontFamily: monoFont,
},
removeButton: {
paddingHorizontal: 16,
paddingVertical: 12,
alignSelf: "stretch",
justifyContent: "center",
borderLeftWidth: 1,
borderLeftColor: colors.border,
},
removeButtonPressed: {
backgroundColor: colors.surfaceDeep,
},
removeButtonText: {
color: colors.textMuted,
fontSize: 22,
fontWeight: "300",
lineHeight: 22,
},
savedHint: {
marginTop: 8,
color: colors.textMuted,
fontSize: 14,
lineHeight: 20,
},
});