feat(settings): unify Streamystats + Marlin URL inputs via the resolver

- jellyfinProbe (/System/Info/Public, ProductName check) + reachabilityProbe (services with no health route).

- ServerUrlStatusText: compact resolver status for ListItem-row layouts.

- Streamystats + Marlin: resolve the URL on blur (https-first, http fallback) and store the canonical URL; inline status feedback.
This commit is contained in:
Gauvain
2026-06-04 20:44:39 +02:00
parent 0f29457ff8
commit b54b0c670b
6 changed files with 133 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
import { useTranslation } from "react-i18next";
import { ActivityIndicator, View } from "react-native";
import type { ServerUrlResolverState } from "@/hooks/useServerUrlResolver";
import { Text } from "./Text";
/**
* Compact status line for the server-URL resolver, for screens whose layout
* (e.g. ListItem rows) doesn't fit the full `ServerUrlField`. Renders nothing
* while idle.
*/
export function ServerUrlStatusText({
state,
minVersion,
className = "",
}: {
state: ServerUrlResolverState;
minVersion?: string;
className?: string;
}) {
const { t } = useTranslation();
if (state.status === "idle") return null;
if (state.status === "resolving") {
return (
<View className={`flex-row items-center ${className}`}>
<ActivityIndicator size='small' color='#9ca3af' />
<Text className='text-xs text-neutral-400 ml-2'>
{t("server_url.resolving")}
</Text>
</View>
);
}
if (state.status === "ok") {
return (
<Text className={`text-xs text-green-500 ${className}`}>
{t("server_url.resolved", { url: state.resolvedUrl })}
</Text>
);
}
const message =
state.reason === "version-too-low"
? t("server_url.version_too_low", {
version: state.version ?? "?",
min: minVersion ?? "",
})
: state.reason === "wrong-service"
? t("server_url.wrong_service")
: state.reason === "invalid"
? t("server_url.invalid_url")
: t("server_url.unreachable");
return <Text className={`text-xs text-red-500 ${className}`}>{message}</Text>;
}