Files
Luke Gustafson 6c40d2f0cc v1.4.0 (#31)
* fix: register physical Tab key on iPadOS/iOS hardware keyboards (#14)

The native module only registered Shift+Tab but not bare Tab, so iOS
intercepted it for UI focus navigation. Register an unmodified Tab
UIKeyCommand with wantsPriorityOverSystemBehavior and handle both
Tab and Shift+Tab in the same JS branch.

Fixes Termix-SSH/Support#557

* fix: pass jumpHosts, forceKeyboardInteractive, and overrideCredentialUsername to terminal connection (#15)

These fields were defined on SSHHost but omitted from the terminal
hostConfig passthrough. Without jumpHosts the backend cannot route
through jump servers; without forceKeyboardInteractive hosts that
require keyboard-interactive auth fail silently; without
overrideCredentialUsername shared credentials use the wrong username.

Fixes Termix-SSH/Support#422
Fixes Termix-SSH/Support#638

* fix: improve mobile terminal scroll recovery (#17)

* Add mobile remote desktop sessions (#18)

* feat: add mobile remote desktop sessions

* feat: add remote desktop input controls

* feat: polish remote desktop controls

* feat: add mobile terminal font selection (#19)

* feat: add mobile shift tab hotkey (#20)

* feat: initial UI redesign

* feat: revamp server login system

* chore: update app icon/background color

* fix: remove unused fields in the settings tab

* feat: improve the user pin system and update all settings modals to use new ui

* fix: active server not updating unless app restarts

* feat: add version in settings

* feat: improve host page UI (updated host form and added credential management)

* fix: preserve composed iOS terminal input

* ci: restore mobile checks

* feat: rewrite of connection system for all types

* fix: preserve mobile jump hosts (#30)

* fix: guard android user ca trust (#29)

* fix: capture ios hardware tab key (#27)

* fix: reset terminal input after special keys (#28)

* fix: open oidc in system browser (#26)

* fix: preserve websocket auth context (#25)

* fix: keep none-auth terminal prompts alive (#23)

* fix: allow local network SSL in Android app (#21)

* feat: allow oidc passkeys

* feat: bundeled xterm into app and added docker loading screen

* feat: add 2fa, api key, and active sessions to settings and addressed multiple bug fixes and inconsistencies with termix web

* chore: update repo images and readme

* chore: update readme to split table for screenshots

* chore: rename ios to apple in build workflow

* fix: android build failure

* feat: add snippet management and fix several bugs

* fix: web login and oidc incorrect logic

* chore: run linter

---------

Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:49:50 -05:00

149 lines
4.5 KiB
TypeScript

import { Stack } from "expo-router";
import { AppProvider, useAppContext } from "./AppContext";
import { TerminalSessionsProvider } from "./contexts/TerminalSessionsContext";
import { TerminalCustomizationProvider } from "./contexts/TerminalCustomizationContext";
import { KeyboardProvider } from "./contexts/KeyboardContext";
import { KeyboardCustomizationProvider } from "./contexts/KeyboardCustomizationContext";
import {
ThemeProvider,
useTheme,
useThemeColor,
} from "./contexts/ThemeContext";
import { AppLockProvider, useAppLock } from "./contexts/AppLockContext";
import { LockScreen } from "@/app/components/LockScreen";
import AuthFlow from "@/app/authentication/AuthFlow";
import { View, Text, ActivityIndicator, TouchableOpacity } from "react-native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { StatusBar } from "expo-status-bar";
import { Toaster } from "sonner-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { useFonts } from "expo-font";
import { FONT_MAP, MONO_FONT, MONO_FONT_BOLD } from "./constants/fonts";
import "../global.css";
import UpdateRequired from "@/app/authentication/UpdateRequired";
function RootLayoutContent() {
const {
authFlowVisible,
openAuthFlow,
showUpdateScreen,
isLoading,
setIsLoading,
} = useAppContext();
const accent = useThemeColor()("accent-brand");
if (isLoading) {
return (
<View className="flex-1 items-center justify-center bg-background">
<ActivityIndicator size="large" color={accent} />
<Text
className="mt-4 text-base text-foreground"
style={{ fontFamily: MONO_FONT }}
>
Initializing
</Text>
<TouchableOpacity
onPress={() => {
setIsLoading(false);
openAuthFlow("server");
}}
className="mt-6 border border-border bg-card px-6 py-3"
>
<Text
className="text-foreground"
style={{ fontFamily: MONO_FONT_BOLD }}
>
Cancel
</Text>
</TouchableOpacity>
</View>
);
}
if (showUpdateScreen) return <UpdateRequired />;
// The tab shell always renders once loaded. When the user isn't connected,
// the tabs themselves show a "no server connected" empty state. The auth flow
// is layered on top as a dismissible full-screen overlay.
return (
<View className="flex-1 bg-background">
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ headerShown: false }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
<AppLockGate />
{authFlowVisible ? (
<View className="absolute inset-0 bg-background">
<AuthFlow />
</View>
) : null}
</View>
);
}
function AppLockGate() {
const { enabled, locked } = useAppLock();
if (!enabled || !locked) return null;
return <LockScreen />;
}
function ThemedToaster() {
const { isDark } = useTheme();
const card = useThemeColor()("card");
const border = useThemeColor()("border");
return (
<Toaster
theme={isDark ? "dark" : "light"}
position="top-center"
toastOptions={{
style: {
backgroundColor: card,
borderWidth: 1,
borderColor: border,
borderRadius: 0,
},
}}
richColors={false}
closeButton
duration={4000}
/>
);
}
function ThemedStatusBar() {
const { isDark } = useTheme();
return <StatusBar style={isDark ? "light" : "dark"} />;
}
export default function RootLayout() {
const [fontsLoaded] = useFonts(FONT_MAP);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<SafeAreaProvider>
<ThemeProvider>
<ThemedStatusBar />
{!fontsLoaded ? (
<View className="flex-1 bg-background" />
) : (
<AppLockProvider>
<AppProvider>
<TerminalSessionsProvider>
<TerminalCustomizationProvider>
<KeyboardProvider>
<KeyboardCustomizationProvider>
<RootLayoutContent />
<ThemedToaster />
</KeyboardCustomizationProvider>
</KeyboardProvider>
</TerminalCustomizationProvider>
</TerminalSessionsProvider>
</AppProvider>
</AppLockProvider>
)}
</ThemeProvider>
</SafeAreaProvider>
</GestureHandlerRootView>
);
}