mirror of
https://github.com/Termix-SSH/Mobile.git
synced 2026-07-28 05:51:43 +02:00
6c40d2f0cc
* 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>
126 lines
4.3 KiB
TypeScript
126 lines
4.3 KiB
TypeScript
import { View, ActivityIndicator } from "react-native";
|
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
import { AlertTriangle, Download } from "lucide-react-native";
|
|
import { useAppContext } from "../AppContext";
|
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import { getVersionInfo, getLatestGitHubRelease } from "../main-axios";
|
|
import { useState, useEffect } from "react";
|
|
import Constants from "expo-constants";
|
|
import { Text, Button, Label } from "@/app/components/ui";
|
|
import { useThemeColor } from "@/app/contexts/ThemeContext";
|
|
|
|
export default function UpdateRequired() {
|
|
const insets = useSafeAreaInsets();
|
|
const color = useThemeColor();
|
|
const { setShowUpdateScreen } = useAppContext();
|
|
const [latestRelease, setLatestRelease] = useState<{
|
|
version: string;
|
|
tagName: string;
|
|
publishedAt: string;
|
|
} | null>(null);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
const currentMobileAppVersion = Constants.expoConfig?.version || "1.0.0";
|
|
|
|
useEffect(() => {
|
|
const fetchVersionInfo = async () => {
|
|
try {
|
|
const [, release] = await Promise.all([
|
|
getVersionInfo(),
|
|
getLatestGitHubRelease(),
|
|
]);
|
|
setLatestRelease(release);
|
|
} catch {
|
|
// best-effort
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
fetchVersionInfo();
|
|
}, []);
|
|
|
|
const handleDismiss = async () => {
|
|
try {
|
|
await AsyncStorage.setItem(
|
|
"dismissedUpdateVersion",
|
|
latestRelease?.version || "unknown",
|
|
);
|
|
} finally {
|
|
setShowUpdateScreen(false);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<View
|
|
className="flex-1 items-center justify-center bg-background"
|
|
style={{ paddingTop: insets.top }}
|
|
>
|
|
<ActivityIndicator size="large" color={color("accent-brand")} />
|
|
<Text className="mt-4 text-sm text-muted-foreground">
|
|
Loading version information…
|
|
</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View className="flex-1 bg-background" style={{ paddingTop: insets.top }}>
|
|
<View className="flex-row items-center gap-2.5 border-b border-border px-5 py-4">
|
|
<AlertTriangle size={20} color="#eab308" />
|
|
<Text weight="bold" className="text-lg text-foreground">
|
|
Update Available
|
|
</Text>
|
|
</View>
|
|
|
|
<View className="flex-1 px-5 py-6">
|
|
<View className="border border-border bg-card p-5">
|
|
<View className="mb-3 flex-row items-center gap-2.5">
|
|
<Download size={18} color={color("accent-brand")} />
|
|
<Text weight="bold" className="text-base text-foreground">
|
|
New version available
|
|
</Text>
|
|
</View>
|
|
|
|
<Text className="mb-5 text-sm leading-5 text-muted-foreground">
|
|
A newer version of the mobile app is available. Some features may
|
|
not work correctly until you update.
|
|
</Text>
|
|
|
|
<View className="border border-border bg-muted/40 p-3.5">
|
|
<Label className="mb-3">Version Information</Label>
|
|
<View className="gap-2">
|
|
<View className="flex-row justify-between">
|
|
<Text className="text-xs text-muted-foreground">Installed</Text>
|
|
<Text className="text-xs text-destructive">
|
|
v{currentMobileAppVersion}
|
|
</Text>
|
|
</View>
|
|
<View className="flex-row justify-between">
|
|
<Text className="text-xs text-muted-foreground">Latest</Text>
|
|
<Text className="text-xs text-accent-brand">
|
|
v{latestRelease?.version || "Unknown"}
|
|
</Text>
|
|
</View>
|
|
{latestRelease?.tagName ? (
|
|
<View className="flex-row justify-between">
|
|
<Text className="text-xs text-muted-foreground">Tag</Text>
|
|
<Text className="text-xs text-muted-foreground">
|
|
{latestRelease.tagName}
|
|
</Text>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View className="px-5" style={{ paddingBottom: insets.bottom + 20 }}>
|
|
<Button variant="accent" size="lg" onPress={handleDismiss}>
|
|
Continue Anyway
|
|
</Button>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|