fix: settings screen design tweaks for mobile
- Center settings cog icon vertically in host card - Normalize icon sizes (relay/host/settings all use iconSize.sm) - Hide theme picker labels on mobile (icon-only) - Simplify audio test copy, remove verbose description
This commit is contained in:
@@ -23,6 +23,7 @@ type SegmentedControlProps<T extends string> = {
|
|||||||
value: T;
|
value: T;
|
||||||
onValueChange: (value: T) => void;
|
onValueChange: (value: T) => void;
|
||||||
size?: SegmentedControlSize;
|
size?: SegmentedControlSize;
|
||||||
|
hideLabels?: boolean;
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
testID?: string;
|
testID?: string;
|
||||||
};
|
};
|
||||||
@@ -32,6 +33,7 @@ export function SegmentedControl<T extends string>({
|
|||||||
value,
|
value,
|
||||||
onValueChange,
|
onValueChange,
|
||||||
size = "md",
|
size = "md",
|
||||||
|
hideLabels = false,
|
||||||
style,
|
style,
|
||||||
testID,
|
testID,
|
||||||
}: SegmentedControlProps<T>) {
|
}: SegmentedControlProps<T>) {
|
||||||
@@ -72,12 +74,14 @@ export function SegmentedControl<T extends string>({
|
|||||||
{option.icon({ color: iconColor, size: iconSize })}
|
{option.icon({ color: iconColor, size: iconSize })}
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
<Text
|
{hideLabels ? null : (
|
||||||
style={[styles.label, labelSizeStyle, isSelected && styles.labelSelected]}
|
<Text
|
||||||
numberOfLines={1}
|
style={[styles.label, labelSizeStyle, isSelected && styles.labelSelected]}
|
||||||
>
|
numberOfLines={1}
|
||||||
{option.label}
|
>
|
||||||
</Text>
|
{option.label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -78,16 +78,16 @@ function formatActiveConnectionBadge(input: {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (activeConnection.type === "relay") {
|
if (activeConnection.type === "relay") {
|
||||||
return { icon: <Globe size={theme.iconSize.xs} color={theme.colors.foregroundMuted} />, text: "Relay" };
|
return { icon: <Globe size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />, text: "Relay" };
|
||||||
}
|
}
|
||||||
if (activeConnection.type === "directSocket") {
|
if (activeConnection.type === "directSocket") {
|
||||||
return { icon: <Monitor size={theme.iconSize.xs} color={theme.colors.foregroundMuted} />, text: "Local" };
|
return { icon: <Monitor size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />, text: "Local" };
|
||||||
}
|
}
|
||||||
if (activeConnection.type === "directPipe") {
|
if (activeConnection.type === "directPipe") {
|
||||||
return { icon: <Monitor size={theme.iconSize.xs} color={theme.colors.foregroundMuted} />, text: "Local" };
|
return { icon: <Monitor size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />, text: "Local" };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
icon: <Monitor size={theme.iconSize.xs} color={theme.colors.foregroundMuted} />,
|
icon: <Monitor size={theme.iconSize.sm} color={theme.colors.foregroundMuted} />,
|
||||||
text: activeConnection.display,
|
text: activeConnection.display,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -230,6 +230,8 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
borderRadius: theme.borderRadius.md,
|
borderRadius: theme.borderRadius.md,
|
||||||
gap: 0,
|
gap: 0,
|
||||||
marginLeft: theme.spacing[2],
|
marginLeft: theme.spacing[2],
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
},
|
},
|
||||||
advancedTrigger: {
|
advancedTrigger: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
@@ -685,7 +687,7 @@ export default function SettingsScreen() {
|
|||||||
return Uint8Array.from(bytes).buffer;
|
return Uint8Array.from(bytes).buffer;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setPlaybackTestResult("Playback command completed.");
|
setPlaybackTestResult(null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
console.error("[Settings] Playback test failed", error);
|
console.error("[Settings] Playback test failed", error);
|
||||||
@@ -878,6 +880,7 @@ export default function SettingsScreen() {
|
|||||||
</View>
|
</View>
|
||||||
<SegmentedControl
|
<SegmentedControl
|
||||||
size="sm"
|
size="sm"
|
||||||
|
hideLabels={Platform.OS !== "web"}
|
||||||
value={settings.theme}
|
value={settings.theme}
|
||||||
onValueChange={handleThemeChange}
|
onValueChange={handleThemeChange}
|
||||||
options={[
|
options={[
|
||||||
@@ -910,10 +913,7 @@ export default function SettingsScreen() {
|
|||||||
<View style={[settingsStyles.card, styles.audioCard]}>
|
<View style={[settingsStyles.card, styles.audioCard]}>
|
||||||
<View style={styles.audioRow}>
|
<View style={styles.audioRow}>
|
||||||
<View style={styles.audioRowContent}>
|
<View style={styles.audioRowContent}>
|
||||||
<Text style={styles.audioRowTitle}>Test audio playback</Text>
|
<Text style={styles.audioRowTitle}>Test audio</Text>
|
||||||
<Text style={styles.aboutHintText}>
|
|
||||||
Plays a built-in PCM sample through the current app audio engine.
|
|
||||||
</Text>
|
|
||||||
{playbackTestResult ? (
|
{playbackTestResult ? (
|
||||||
<Text style={styles.aboutHintText}>{playbackTestResult}</Text>
|
<Text style={styles.aboutHintText}>{playbackTestResult}</Text>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -1463,7 +1463,7 @@ function DaemonCard({
|
|||||||
>
|
>
|
||||||
{({ hovered = false, pressed = false }) => (
|
{({ hovered = false, pressed = false }) => (
|
||||||
<Settings
|
<Settings
|
||||||
size={theme.iconSize.md}
|
size={theme.iconSize.sm}
|
||||||
color={
|
color={
|
||||||
hovered || pressed ? theme.colors.foreground : theme.colors.foregroundMuted
|
hovered || pressed ? theme.colors.foreground : theme.colors.foregroundMuted
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user