fix(app): align and simplify provider rows

This commit is contained in:
Mohamed Boudra
2026-07-24 12:46:46 +02:00
parent fc10c79e26
commit 48b14d27a5
2 changed files with 38 additions and 25 deletions
@@ -44,6 +44,7 @@ const { theme, snapshotState, configState, patchConfigMock, openProviderSettings
); );
vi.mock("react-native", () => ({ vi.mock("react-native", () => ({
Platform: { OS: "web" },
View: ({ children, testID }: { children?: React.ReactNode; testID?: string }) => View: ({ children, testID }: { children?: React.ReactNode; testID?: string }) =>
React.createElement("div", { "data-testid": testID }, children), React.createElement("div", { "data-testid": testID }, children),
Text: ({ children }: { children?: React.ReactNode }) => Text: ({ children }: { children?: React.ReactNode }) =>
@@ -90,7 +91,7 @@ vi.mock("react-native-unistyles", () => ({
create: (factory: unknown) => create: (factory: unknown) =>
typeof factory === "function" ? (factory as (t: typeof theme) => unknown)(theme) : factory, typeof factory === "function" ? (factory as (t: typeof theme) => unknown)(theme) : factory,
}, },
useUnistyles: () => ({ theme }), useUnistyles: () => ({ theme, rt: { breakpoint: "md" } }),
})); }));
vi.mock("lucide-react-native", () => { vi.mock("lucide-react-native", () => {
@@ -10,6 +10,7 @@ import {
type PressableStateCallbackType, type PressableStateCallbackType,
} from "react-native"; } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { useIsCompactFormFactor } from "@/constants/layout";
import { settingsStyles } from "@/styles/settings"; import { settingsStyles } from "@/styles/settings";
import { useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useHostRuntimeIsConnected } from "@/runtime/host-runtime";
import { useHostFeature } from "@/runtime/host-features"; import { useHostFeature } from "@/runtime/host-features";
@@ -178,6 +179,7 @@ function ProviderRow({
}: ProviderRowProps) { }: ProviderRowProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const { theme } = useUnistyles(); const { theme } = useUnistyles();
const isCompact = useIsCompactFormFactor();
const ProviderIcon = getProviderIcon(def.id); const ProviderIcon = getProviderIcon(def.id);
const providerError = const providerError =
enabled && enabled &&
@@ -229,10 +231,10 @@ function ProviderRow({
<Text style={settingsStyles.rowTitle} numberOfLines={1}> <Text style={settingsStyles.rowTitle} numberOfLines={1}>
{def.label} {def.label}
</Text> </Text>
<Text style={styles.separator}>·</Text> {!isCompact ? <Text style={styles.separator}>·</Text> : null}
<StatusIndicator status={providerStatus} /> <StatusIndicator status={providerStatus} compact={isCompact} />
</View> </View>
{providerError ? ( {providerError && !isCompact ? (
<Text style={styles.errorText} numberOfLines={3}> <Text style={styles.errorText} numberOfLines={3}>
{providerError} {providerError}
</Text> </Text>
@@ -246,18 +248,20 @@ function ProviderRow({
disabled={isToggling || isRemoving} disabled={isToggling || isRemoving}
accessibilityLabel={t("settings.providers.enableProvider", { name: def.label })} accessibilityLabel={t("settings.providers.enableProvider", { name: def.label })}
/> />
{canRemove ? ( <View style={styles.menuSlot}>
<ProviderActionsMenu {canRemove ? (
providerId={def.id} <ProviderActionsMenu
providerLabel={def.label} providerId={def.id}
isRemoving={isRemoving} providerLabel={def.label}
iconSize={theme.iconSize.sm} isRemoving={isRemoving}
foregroundColor={theme.colors.foreground} iconSize={theme.iconSize.sm}
foregroundMutedColor={theme.colors.foregroundMuted} foregroundColor={theme.colors.foreground}
dangerColor={theme.colors.statusDanger} foregroundMutedColor={theme.colors.foregroundMuted}
onRemove={onRemove} dangerColor={theme.colors.statusDanger}
/> onRemove={onRemove}
) : null} />
) : null}
</View>
</View> </View>
</> </>
)} )}
@@ -278,7 +282,7 @@ function getDotColor(tone: StatusTone, theme: ReturnType<typeof useUnistyles>["t
} }
} }
function StatusIndicator({ status }: { status: ProviderStatus }) { function StatusIndicator({ status, compact }: { status: ProviderStatus; compact: boolean }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { theme } = useUnistyles(); const { theme } = useUnistyles();
const dotStyle = useMemo( const dotStyle = useMemo(
@@ -293,15 +297,19 @@ function StatusIndicator({ status }: { status: ProviderStatus }) {
) : ( ) : (
<View style={dotStyle} /> <View style={dotStyle} />
)} )}
<Text style={styles.statusLabel}>{status.label}</Text> {!compact ? (
{status.modelCount !== null ? (
<> <>
<Text style={styles.separator}>·</Text> <Text style={styles.statusLabel}>{status.label}</Text>
<Text style={styles.statusLabel}> {status.modelCount !== null ? (
{status.modelCount === 1 <>
? t("settings.providers.models.one") <Text style={styles.separator}>·</Text>
: t("settings.providers.models.many", { count: status.modelCount })} <Text style={styles.statusLabel}>
</Text> {status.modelCount === 1
? t("settings.providers.models.one")
: t("settings.providers.models.many", { count: status.modelCount })}
</Text>
</>
) : null}
</> </>
) : null} ) : null}
</View> </View>
@@ -536,6 +544,10 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
}, },
menuSlot: {
width: 32,
height: 32,
},
menuButtonHovered: { menuButtonHovered: {
backgroundColor: theme.colors.surface2, backgroundColor: theme.colors.surface2,
}, },