Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function TabLayout() {
<Tabs
screenOptions={{
tabBarActiveTintColor: isDark ? "#ffffff" : "#0a0a0a",
tabBarInactiveTintColor: isDark ? "#666666" : "#999999",
tabBarInactiveTintColor: isDark ? "#9a9a9a" : "#999999",
tabBarStyle: {
backgroundColor: isDark ? "#0a0a0a" : "#ffffff",
borderTopColor: isDark ? "#1a1a1a" : "#e5e5e5",
Expand Down
2 changes: 1 addition & 1 deletion app/(tabs)/connections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function ConnectionItem({
)}
</View>
<TouchableOpacity onPress={onEdit} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}>
<Ionicons name="ellipsis-vertical" size={20} color={isDark ? "#666666" : "#999999"} />
<Ionicons name="ellipsis-vertical" size={20} color={isDark ? "#9a9a9a" : "#999999"} />
</TouchableOpacity>
</TouchableOpacity>
)
Expand Down
22 changes: 16 additions & 6 deletions app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { useTranslation } from "react-i18next"
import { useSessions } from "../../src/stores/sessions"
import { useConnections } from "../../src/stores/connections"
import { useEvents } from "../../src/stores/events"
import { isHealthy } from "../../src/lib/sse-liveness"
import { useCatalog } from "../../src/stores/catalog"
import type BottomSheet from "@gorhom/bottom-sheet"
import type { Session, Project } from "../../src/lib/sdk"
Expand Down Expand Up @@ -105,7 +106,7 @@ function SessionItem({
)}
</View>
</View>
<Ionicons name="chevron-forward" size={20} color={isDark ? "#666666" : "#999999"} />
<Ionicons name="chevron-forward" size={20} color={isDark ? "#9a9a9a" : "#999999"} />
</TouchableOpacity>
)
}
Expand Down Expand Up @@ -140,7 +141,7 @@ function GroupHeader({
<Ionicons
name={row.collapsed ? "chevron-forward" : "chevron-down"}
size={16}
color={isDark ? "#666666" : "#999999"}
color={isDark ? "#9a9a9a" : "#999999"}
/>
</TouchableOpacity>
)
Expand Down Expand Up @@ -198,6 +199,9 @@ export default function SessionsScreen() {
// Directories collapsed in the grouped session list. Empty by default —
// all groups start expanded (#67).
const [collapsedDirs, setCollapsedDirs] = useState<Set<string>>(new Set())
// The indicator tracks the transport, not "did we try to connect" — see
// src/lib/sse-liveness.ts.
const transportHealthy = useEvents((s) => isHealthy(s.transport))

const toggleGroup = useCallback((directory: string) => {
setCollapsedDirs((prev) => {
Expand Down Expand Up @@ -527,7 +531,13 @@ export default function SessionsScreen() {
testID="connection-status-bar"
>
<View style={styles.connectionInfo}>
<View style={[styles.connectionDot, { backgroundColor: "#22c55e" }]} testID="connection-status-dot" />
{/* Reflects verified SSE liveness, not merely "a connection is
selected". This was hardcoded green, so the indicator claimed
health even while the stream was dead. */}
<View
style={[styles.connectionDot, { backgroundColor: transportHealthy ? "#22c55e" : "#f59e0b" }]}
testID="connection-status-dot"
/>
<Text style={[styles.connectionName, isDark && styles.textDark]} numberOfLines={1}>
{activeConnection.name}
</Text>
Expand All @@ -540,7 +550,7 @@ export default function SessionsScreen() {
</>
)}
</View>
<Ionicons name="swap-horizontal-outline" size={16} color={isDark ? "#666666" : "#999999"} />
<Ionicons name="swap-horizontal-outline" size={16} color={isDark ? "#9a9a9a" : "#999999"} />
</TouchableOpacity>

{error && (
Expand Down Expand Up @@ -723,7 +733,7 @@ export default function SessionsScreen() {
{t("sessionsList.newSessionModal.browseFoldersHint")}
</Text>
</View>
<Ionicons name="chevron-forward" size={16} color={isDark ? "#666666" : "#999999"} />
<Ionicons name="chevron-forward" size={16} color={isDark ? "#9a9a9a" : "#999999"} />
</TouchableOpacity>

{/* Manual path input fallback */}
Expand All @@ -733,7 +743,7 @@ export default function SessionsScreen() {
<TextInput
style={[styles.modalInput, isDark && styles.modalInputDark]}
placeholder={serverHome ? `${serverHome}/...` : "/path/to/project"}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={customDir}
onChangeText={(text) => {
// Expand ~ to server home directory
Expand Down
10 changes: 5 additions & 5 deletions app/(tabs)/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export default function SettingsScreen() {
description={t("settings.security.lockNow.description")}
isDark={isDark}
onPress={lock}
right={<Ionicons name="chevron-forward" size={20} color={isDark ? "#666666" : "#999999"} />}
right={<Ionicons name="chevron-forward" size={20} color={isDark ? "#9a9a9a" : "#999999"} />}
/>
)}
</SettingSection>
Expand Down Expand Up @@ -252,7 +252,7 @@ export default function SettingsScreen() {
description={t("settings.privacy.privacyPolicy.description")}
isDark={isDark}
onPress={() => Linking.openURL(PRIVACY_POLICY_URL)}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#666666" : "#999999"} />}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#9a9a9a" : "#999999"} />}
/>
</SettingSection>

Expand All @@ -263,7 +263,7 @@ export default function SettingsScreen() {
description={localeLabels[locale]}
isDark={isDark}
onPress={handleLanguagePress}
right={<Ionicons name="chevron-forward" size={20} color={isDark ? "#666666" : "#999999"} />}
right={<Ionicons name="chevron-forward" size={20} color={isDark ? "#9a9a9a" : "#999999"} />}
/>
<SettingRow
icon="information-circle"
Expand All @@ -290,15 +290,15 @@ export default function SettingsScreen() {
description={t("settings.about.github.description")}
isDark={isDark}
onPress={() => Linking.openURL("https://github.com/anomalyco/opencode")}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#666666" : "#999999"} />}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#9a9a9a" : "#999999"} />}
/>
<SettingRow
icon="document-text"
label={t("settings.about.docs.label")}
description={t("settings.about.docs.description")}
isDark={isDark}
onPress={() => Linking.openURL("https://opencode.ai/docs")}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#666666" : "#999999"} />}
right={<Ionicons name="open-outline" size={20} color={isDark ? "#9a9a9a" : "#999999"} />}
/>
</SettingSection>

Expand Down
8 changes: 8 additions & 0 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ function RootLayout() {
if (next === "background" && useAuth.getState().settings.requireBiometric) {
useAuth.getState().lock()
}
// Recover the event stream on foreground. Returning from background is
// exactly when a socket is most likely to be half-open -- doze, a Wi-Fi/
// cellular handover -- and without this nothing re-checked it, so the app
// could sit showing stale data until the user navigated. resume() is a
// no-op when the transport is already live or an attempt is in flight.
if (next === "active") {
useEvents.getState().resume()
}
})
return () => sub.remove()
}, [])
Expand Down
10 changes: 5 additions & 5 deletions app/connection/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export default function EditConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder={t("connection.shared.namePlaceholder")}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={name}
onChangeText={setName}
/>
Expand All @@ -234,7 +234,7 @@ export default function EditConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="http://192.168.1.100:4096"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={url}
onChangeText={setUrl}
autoCapitalize="none"
Expand All @@ -247,7 +247,7 @@ export default function EditConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="/path/to/project"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={directory}
onChangeText={setDirectory}
autoCapitalize="none"
Expand All @@ -262,7 +262,7 @@ export default function EditConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="admin"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={username}
onChangeText={setUsername}
autoCapitalize="none"
Expand All @@ -273,7 +273,7 @@ export default function EditConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="••••••••"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={password}
onChangeText={setPassword}
secureTextEntry
Expand Down
20 changes: 10 additions & 10 deletions app/connection/add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, styles.ipInput, isDark && styles.inputDark]}
placeholder="192.168.1.100"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={ip}
onChangeText={setIp}
autoCapitalize="none"
Expand All @@ -344,7 +344,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, styles.portInput, isDark && styles.inputDark]}
placeholder="4096"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={port}
onChangeText={setPort}
keyboardType="number-pad"
Expand All @@ -357,7 +357,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder={t("connection.add.quick.namePlaceholder")}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={name}
onChangeText={setName}
/>
Expand All @@ -367,7 +367,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder={t("connection.add.quick.passwordPlaceholder")}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={password}
onChangeText={setPassword}
secureTextEntry
Expand Down Expand Up @@ -480,7 +480,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark, { marginTop: 12 }]}
placeholder="your@email.com"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={waitlistEmail}
onChangeText={setWaitlistEmail}
autoCapitalize="none"
Expand Down Expand Up @@ -573,7 +573,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder={t("connection.shared.namePlaceholder")}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={name}
onChangeText={setName}
/>
Expand All @@ -589,7 +589,7 @@ export default function AddConnectionScreen() {
? "https://your-tunnel.trycloudflare.com"
: "https://api.opencode.ai"
}
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={url}
onChangeText={setUrl}
autoCapitalize="none"
Expand All @@ -611,7 +611,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="/path/to/project"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={directory}
onChangeText={setDirectory}
autoCapitalize="none"
Expand All @@ -626,7 +626,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="admin"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={username}
onChangeText={setUsername}
autoCapitalize="none"
Expand All @@ -637,7 +637,7 @@ export default function AddConnectionScreen() {
<TextInput
style={[styles.input, isDark && styles.inputDark]}
placeholder="password"
placeholderTextColor={isDark ? "#666666" : "#999999"}
placeholderTextColor={isDark ? "#9a9a9a" : "#999999"}
value={password}
onChangeText={setPassword}
secureTextEntry
Expand Down
Loading