Refactor socket handlers to improve performance and enhance thinking level management

This commit is contained in:
2026-07-09 13:14:52 -05:00
parent a0cfc5ba4a
commit 62cbc5357b
+98 -45
View File
@@ -3,13 +3,18 @@ import { useMemo, useState } from "react";
import {
ActivityIndicator,
FlatList,
Keyboard,
KeyboardAvoidingView,
Modal,
Platform,
Pressable,
StyleSheet,
Text,
TextInput,
useWindowDimensions,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { colors, monoFont } from "@/lib/theme";
import type { ModelRef, ModelSummary } from "@/lib/types";
@@ -39,6 +44,10 @@ export function ModelSelector({
}: ModelSelectorProps) {
const [open, setOpen] = useState(false);
const [query, setQuery] = useState("");
const { height: windowHeight } = useWindowDimensions();
const insets = useSafeAreaInsets();
const sheetHeight = Math.round(windowHeight * 0.78);
const filteredModels = useMemo(() => {
const needle = query.trim().toLowerCase();
if (!needle) {
@@ -55,6 +64,17 @@ export function ModelSelector({
? models.find((model) => model.provider === selected.provider && model.id === selected.id)
: undefined;
const close = () => {
Keyboard.dismiss();
setQuery("");
setOpen(false);
};
const handleSelect = (model: ModelRef) => {
onSelect(model);
close();
};
return (
<>
<Pressable
@@ -77,12 +97,24 @@ export function ModelSelector({
)}
</Pressable>
<Modal visible={open} animationType="slide" transparent onRequestClose={() => setOpen(false)}>
<View style={styles.overlay}>
<View style={styles.sheet}>
<Modal visible={open} animationType="slide" transparent onRequestClose={close}>
<KeyboardAvoidingView
style={styles.overlay}
behavior={Platform.OS === "ios" ? "padding" : "height"}
>
<Pressable style={styles.backdrop} onPress={close} accessibilityLabel="Close model selector" />
<View
style={[
styles.sheet,
{
height: sheetHeight,
paddingBottom: Math.max(insets.bottom, 16),
},
]}
>
<View style={styles.header}>
<Text style={styles.title}>Choose model</Text>
<Pressable onPress={() => setOpen(false)} hitSlop={10}>
<Pressable onPress={close} hitSlop={10} accessibilityLabel="Close">
<Ionicons name="close" size={22} color={colors.textSecondary} />
</Pressable>
</View>
@@ -94,48 +126,53 @@ export function ModelSelector({
style={styles.search}
autoCorrect={false}
autoCapitalize="none"
returnKeyType="search"
/>
{error ? <Text style={styles.error}>{error}</Text> : null}
{models.length === 0 ? (
<Text style={styles.empty}>{loading ? "Loading models…" : "No available models"}</Text>
) : (
<FlatList
data={filteredModels}
keyExtractor={(model) => `${model.provider}:${model.id}`}
keyboardShouldPersistTaps="handled"
renderItem={({ item }) => {
const isSelected =
item.provider === selected?.provider && item.id === selected?.id;
return (
<Pressable
style={({ pressed }) => [
styles.option,
pressed && styles.pressed,
isSelected && styles.selected,
]}
onPress={() => {
onSelect({ provider: item.provider, id: item.id });
setOpen(false);
}}
>
<View style={styles.optionText}>
<Text style={styles.optionId}>{item.id}</Text>
<Text style={styles.optionMeta}>
{item.providerDisplayName ?? item.provider}
{item.name && item.name !== item.id ? ` · ${item.name}` : ""}
</Text>
</View>
{isSelected ? (
<Ionicons name="checkmark" size={18} color={colors.accent} />
) : null}
</Pressable>
);
}}
ListEmptyComponent={<Text style={styles.empty}>No matching models</Text>}
/>
)}
<View style={styles.listRegion}>
{models.length === 0 ? (
<Text style={styles.empty}>{loading ? "Loading models…" : "No available models"}</Text>
) : (
<FlatList
style={styles.list}
data={filteredModels}
keyExtractor={(model) => `${model.provider}:${model.id}`}
keyboardShouldPersistTaps="handled"
keyboardDismissMode="on-drag"
contentContainerStyle={
filteredModels.length === 0 ? styles.listEmptyContent : styles.listContent
}
renderItem={({ item }) => {
const isSelected =
item.provider === selected?.provider && item.id === selected?.id;
return (
<Pressable
style={({ pressed }) => [
styles.option,
pressed && styles.pressed,
isSelected && styles.selected,
]}
onPress={() => handleSelect({ provider: item.provider, id: item.id })}
>
<View style={styles.optionText}>
<Text style={styles.optionId}>{item.id}</Text>
<Text style={styles.optionMeta}>
{item.providerDisplayName ?? item.provider}
{item.name && item.name !== item.id ? ` · ${item.name}` : ""}
</Text>
</View>
{isSelected ? (
<Ionicons name="checkmark" size={18} color={colors.accent} />
) : null}
</Pressable>
);
}}
ListEmptyComponent={<Text style={styles.empty}>No matching models</Text>}
/>
)}
</View>
</View>
</View>
</KeyboardAvoidingView>
</Modal>
</>
);
@@ -160,14 +197,15 @@ const styles = StyleSheet.create({
pressed: { backgroundColor: colors.surface },
disabled: { opacity: 0.45 },
overlay: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0, 0, 0, 0.65)" },
backdrop: { ...StyleSheet.absoluteFillObject },
sheet: {
maxHeight: "78%",
backgroundColor: colors.surface,
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
borderWidth: 1,
borderColor: colors.border,
padding: 16,
paddingHorizontal: 16,
paddingTop: 16,
gap: 12,
},
header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between" },
@@ -183,6 +221,21 @@ const styles = StyleSheet.create({
fontFamily: monoFont,
fontSize: 13,
},
listRegion: {
flex: 1,
minHeight: 0,
},
list: {
flex: 1,
},
listContent: {
paddingBottom: 8,
},
listEmptyContent: {
flexGrow: 1,
justifyContent: "flex-start",
paddingTop: 8,
},
option: {
flexDirection: "row",
alignItems: "center",