Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| The phone app with your own g1t, on g1t.sh/download until Google Play, and Node 24 (#5) | 1 | import { router, useLocalSearchParams } from "expo-router"; |
| 2 | import { Server as ServerIcon } from "lucide-react-native"; | |
| 3 | import { useEffect, useState } from "react"; | |
| 4 | import { View } from "react-native"; | |
| 5 | ||
| 6 | import { G1tMark } from "@/components/mark"; | |
| 7 | import { Button, Loading, Screen, Text } from "@/components/ui"; | |
| 8 | import { type Found, discover } from "@/lib/discover"; | |
| 9 | import { isHosted } from "@/lib/server"; | |
| 10 | import { useSession } from "@/lib/session"; | |
| 11 | import { space, useColors } from "@/theme"; | |
| 12 | ||
| 13 | /** | |
| 14 | * `g1t://connect?server=<site>`: a link (or the QR code on a self-hosted | |
| 15 | * g1t's download page) that points the app at a g1t. It asks first: the | |
| 16 | * app talks to one g1t at a time, and switching signs out of the one | |
| 17 | * before. | |
| 18 | */ | |
| 19 | export default function Connect() { | |
| 20 | const { server: given } = useLocalSearchParams<{ server?: string }>(); | |
| 21 | const { state, changeServer } = useSession(); | |
| 22 | const colors = useColors(); | |
| 23 | const [found, setFound] = useState<Found | null>(null); | |
| 24 | const [error, setError] = useState<string | null>(null); | |
| 25 | const [busy, setBusy] = useState(false); | |
| 26 | ||
| 27 | useEffect(() => { | |
| 28 | if (!given) return setError("This link does not say which g1t."); | |
| 29 | discover(given) | |
| 30 | .then(setFound) | |
| 31 | .catch((failure: unknown) => setError(failure instanceof Error ? failure.message : "That g1t did not answer.")); | |
| 32 | }, [given]); | |
| 33 | ||
| 34 | const leave = () => (router.canGoBack() ? router.back() : router.replace("/")); | |
| 35 | const host = found ? new URL(found.server.site).host : ""; | |
| 36 | const already = found && state.server && state.server.site === found.server.site; | |
| 37 | const signedInElsewhere = state.status === "signed-in" && !already; | |
| 38 | ||
| 39 | return ( | |
| 40 | <Screen safe> | |
| 41 | <View style={{ flex: 1, padding: space.xl, justifyContent: "center", gap: space.xl }}> | |
| 42 | <G1tMark size={44} /> | |
| 43 | {!found && !error ? <Loading /> : null} | |
| 44 | {error ? ( | |
| 45 | <View style={{ gap: space.md }}> | |
| 46 | <Text size="title">Can't reach that g1t</Text> | |
| 47 | <Text tone="muted">{error}</Text> | |
| 48 | <Button title="Back" variant="secondary" onPress={leave} /> | |
| 49 | </View> | |
| 50 | ) : null} | |
| 51 | {found ? ( | |
| 52 | <View style={{ gap: space.md }}> | |
| 53 | <Text size="title">{already ? `Already on ${host}` : `Use ${host}?`}</Text> | |
| 54 | <Text tone="muted"> | |
| 55 | {isHosted(found.server) | |
| 56 | ? "g1t.sh, hosted by g1t." | |
| 57 | : `A g1t run by its own people at ${found.server.site}. The app signs in there, and talks to it alone.`} | |
| 58 | </Text> | |
| 59 | {!found.push ? ( | |
| 60 | <Text size="small" tone="faint"> | |
| 61 | This g1t sends no notifications to phones; Chat still works while the app is open. | |
| 62 | </Text> | |
| 63 | ) : null} | |
| 64 | {signedInElsewhere ? ( | |
| 65 | <Text size="small" style={{ color: colors.warn }}> | |
| 66 | You'll be signed out of {state.server ? new URL(state.server.site).host : "the g1t you are on"} first. | |
| 67 | </Text> | |
| 68 | ) : null} | |
| 69 | {already ? ( | |
| 70 | <Button title="Continue" onPress={() => router.replace("/")} /> | |
| 71 | ) : ( | |
| 72 | <Button | |
| 73 | title={`Use ${host}`} | |
| 74 | icon={ServerIcon} | |
| 75 | busy={busy} | |
| 76 | onPress={async () => { | |
| 77 | setBusy(true); | |
| 78 | await changeServer(found.server); | |
| 79 | router.replace("/sign-in"); | |
| 80 | }} | |
| 81 | /> | |
| 82 | )} | |
| 83 | {!already ? <Button title="Not now" variant="secondary" onPress={leave} /> : null} | |
| 84 | </View> | |
| 85 | ) : null} | |
| 86 | </View> | |
| 87 | </Screen> | |
| 88 | ); | |
| 89 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.