From d4ca80091a16bd2e0ea3d88c166a648a062a541f Mon Sep 17 00:00:00 2001 From: kitakkun <48154936+kitakkun@users.noreply.github.com> Date: Sun, 19 Jul 2026 06:00:20 +0900 Subject: [PATCH] feat(settings): show idb / idb_companion setup status in health check iOS simulator input control (e.g. the Device Mirror plugin) depends on idb, which is a two-part install (pip client + brew companion) that is easy to get half-done. Surface both executables in the health check section alongside the existing ADB row, extracting the shared row layout into ToolPathRow. --- .../settings/DefaultDiagnosticsQueryKey.kt | 4 ++ .../jetwhale/host/data/util/IdbUtil.kt | 37 +++++++++++++ .../host/model/DebuggingToolsDiagnostics.kt | 3 ++ .../composeResources/values-ja/strings.xml | 4 ++ .../main/composeResources/values/strings.xml | 4 ++ .../settings/general/GeneralSettingsScreen.kt | 53 ++++++++++++++----- .../general/GeneralSettingsScreenPresenter.kt | 2 + .../general/GeneralSettingsScreenUiState.kt | 2 + 8 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/util/IdbUtil.kt diff --git a/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/settings/DefaultDiagnosticsQueryKey.kt b/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/settings/DefaultDiagnosticsQueryKey.kt index c0c32ee87..3c67032aa 100644 --- a/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/settings/DefaultDiagnosticsQueryKey.kt +++ b/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/settings/DefaultDiagnosticsQueryKey.kt @@ -2,6 +2,8 @@ package com.kitakkun.jetwhale.host.data.settings import com.kitakkun.jetwhale.host.data.AppDataDirectoryProvider import com.kitakkun.jetwhale.host.data.util.findAdbPath +import com.kitakkun.jetwhale.host.data.util.findIdbCompanionPath +import com.kitakkun.jetwhale.host.data.util.findIdbPath import com.kitakkun.jetwhale.host.model.DebuggingToolsDiagnostics import com.kitakkun.jetwhale.host.model.DiagnosticsQueryKey import dev.zacsweers.metro.AppScope @@ -21,6 +23,8 @@ class DefaultDiagnosticsQueryKey( val appDataPath = appDataDirectoryProvider.getAppDataPath() DebuggingToolsDiagnostics( adbPath = adbPath, + idbPath = findIdbPath(), + idbCompanionPath = findIdbCompanionPath(), appDataPath = appDataPath, ) }, diff --git a/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/util/IdbUtil.kt b/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/util/IdbUtil.kt new file mode 100644 index 000000000..7858d6324 --- /dev/null +++ b/jetwhale-host/core/data/src/main/kotlin/com/kitakkun/jetwhale/host/data/util/IdbUtil.kt @@ -0,0 +1,37 @@ +package com.kitakkun.jetwhale.host.data.util + +import java.io.File + +/** + * Finds the absolute path to the idb client executable (Facebook's iOS debug bridge, used to + * drive iOS simulator input), checking common installation locations and then the PATH. + * + * @return The absolute path to idb if found, otherwise an empty string + */ +fun findIdbPath(): String = findExecutable( + name = "idb", + candidatePaths = listOf( + "/usr/local/bin/idb", + "/opt/homebrew/bin/idb", + ), +) + +/** + * Finds the absolute path to the idb_companion executable (the gRPC daemon the idb client talks + * to; installed separately, typically via `brew install idb-companion`). + * + * @return The absolute path to idb_companion if found, otherwise an empty string + */ +fun findIdbCompanionPath(): String = findExecutable( + name = "idb_companion", + candidatePaths = listOf( + "/usr/local/bin/idb_companion", + "/opt/homebrew/bin/idb_companion", + ), +) + +private fun findExecutable(name: String, candidatePaths: List): String { + candidatePaths.firstOrNull { File(it).canExecute() }?.let { return it } + val pathDirs = System.getenv("PATH")?.split(File.pathSeparator).orEmpty() + return pathDirs.map { File(it, name) }.firstOrNull { it.canExecute() }?.absolutePath.orEmpty() +} diff --git a/jetwhale-host/core/model/src/main/kotlin/com/kitakkun/jetwhale/host/model/DebuggingToolsDiagnostics.kt b/jetwhale-host/core/model/src/main/kotlin/com/kitakkun/jetwhale/host/model/DebuggingToolsDiagnostics.kt index fa8a5dcae..45d6669d7 100644 --- a/jetwhale-host/core/model/src/main/kotlin/com/kitakkun/jetwhale/host/model/DebuggingToolsDiagnostics.kt +++ b/jetwhale-host/core/model/src/main/kotlin/com/kitakkun/jetwhale/host/model/DebuggingToolsDiagnostics.kt @@ -2,5 +2,8 @@ package com.kitakkun.jetwhale.host.model data class DebuggingToolsDiagnostics( val adbPath: String, + // Empty when the tool is not installed. + val idbPath: String, + val idbCompanionPath: String, val appDataPath: String, ) diff --git a/jetwhale-host/feature/settings/src/main/composeResources/values-ja/strings.xml b/jetwhale-host/feature/settings/src/main/composeResources/values-ja/strings.xml index b2d7671e3..01e92591a 100644 --- a/jetwhale-host/feature/settings/src/main/composeResources/values-ja/strings.xml +++ b/jetwhale-host/feature/settings/src/main/composeResources/values-ja/strings.xml @@ -61,6 +61,10 @@ ヘルスチェック ADB実行可能ファイルのパス ADBコマンドが見つかりません + idb実行可能ファイルのパス + idbコマンドが見つかりません + idb_companion実行可能ファイルのパス + idb_companionコマンドが見つかりません アプリケーションログを表示 ログをフィルター… フィルター diff --git a/jetwhale-host/feature/settings/src/main/composeResources/values/strings.xml b/jetwhale-host/feature/settings/src/main/composeResources/values/strings.xml index a1c7d547f..8a453afa5 100644 --- a/jetwhale-host/feature/settings/src/main/composeResources/values/strings.xml +++ b/jetwhale-host/feature/settings/src/main/composeResources/values/strings.xml @@ -61,6 +61,10 @@ Health Check ADB Executable Path ADB command not found + idb Executable Path + idb command not found + idb_companion Executable Path + idb_companion command not found View Application Logs Filter logs… Filter diff --git a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreen.kt b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreen.kt index 8fc4374d1..d8a8170a1 100644 --- a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreen.kt +++ b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreen.kt @@ -46,6 +46,10 @@ import com.kitakkun.jetwhale.host.settings.component.SettingsItemRow import com.kitakkun.jetwhale.host.settings.component.SwitchSettingsItemView import com.kitakkun.jetwhale.host.settings.current_version import com.kitakkun.jetwhale.host.settings.health_check +import com.kitakkun.jetwhale.host.settings.idb_companion_executable_path +import com.kitakkun.jetwhale.host.settings.idb_companion_unavailable +import com.kitakkun.jetwhale.host.settings.idb_executable_path +import com.kitakkun.jetwhale.host.settings.idb_unavailable import com.kitakkun.jetwhale.host.settings.install_update import com.kitakkun.jetwhale.host.settings.language_option import com.kitakkun.jetwhale.host.settings.maintenance @@ -152,24 +156,45 @@ fun GeneralSettingsScreen( } item { SettingOptionView(stringResource(Res.string.health_check)) { - SettingsItemRow(stringResource(Res.string.adb_executable_path)) { - Text( - text = uiState.adbPath.ifEmpty { stringResource(Res.string.adb_unavailable) }, - ) - Spacer(Modifier.width(8.dp)) - if (uiState.adbPath.isNotEmpty()) { - Icon( - imageVector = Icons.Default.Check, - tint = MaterialTheme.colorScheme.primary, - contentDescription = null, - ) - } - } + ToolPathRow( + label = stringResource(Res.string.adb_executable_path), + path = uiState.adbPath, + unavailableText = stringResource(Res.string.adb_unavailable), + ) + ToolPathRow( + label = stringResource(Res.string.idb_executable_path), + path = uiState.idbPath, + unavailableText = stringResource(Res.string.idb_unavailable), + ) + ToolPathRow( + label = stringResource(Res.string.idb_companion_executable_path), + path = uiState.idbCompanionPath, + unavailableText = stringResource(Res.string.idb_companion_unavailable), + ) } } } } +@Composable +private fun ToolPathRow( + label: String, + path: String, + unavailableText: String, +) { + SettingsItemRow(label) { + Text(text = path.ifEmpty { unavailableText }) + Spacer(Modifier.width(8.dp)) + if (path.isNotEmpty()) { + Icon( + imageVector = Icons.Default.Check, + tint = MaterialTheme.colorScheme.primary, + contentDescription = null, + ) + } + } +} + @Composable private fun UpdateCheckStatusView( isChecking: Boolean, @@ -253,6 +278,8 @@ private fun GeneralSettingsScreenPreview() { language = AppLanguage.English, appDataPath = "~/.jetwhale", adbPath = "/path/to/adb", + idbPath = "/path/to/idb", + idbCompanionPath = "", currentVersion = "1.0.0-alpha08", checkForUpdatesOnStartup = true, isCheckingForUpdates = false, diff --git a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenPresenter.kt b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenPresenter.kt index 511fc90bd..276bad7b5 100644 --- a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenPresenter.kt +++ b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenPresenter.kt @@ -62,6 +62,8 @@ fun generalSettingsScreenPresenter( language = appearanceSettings.appLanguage, appDataPath = diagnostics.appDataPath, adbPath = diagnostics.adbPath, + idbPath = diagnostics.idbPath, + idbCompanionPath = diagnostics.idbCompanionPath, currentVersion = presenterContext.hostVersionInfo.version, checkForUpdatesOnStartup = debuggerBehaviorSettings.checkForUpdatesOnStartup, isCheckingForUpdates = updateCheckMutation.isPending, diff --git a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenUiState.kt b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenUiState.kt index 122850dee..57660cfa6 100644 --- a/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenUiState.kt +++ b/jetwhale-host/feature/settings/src/main/kotlin/com/kitakkun/jetwhale/host/settings/general/GeneralSettingsScreenUiState.kt @@ -12,6 +12,8 @@ data class GeneralSettingsScreenUiState( val availableColorSchemes: ImmutableList, val appDataPath: String, val adbPath: String, + val idbPath: String, + val idbCompanionPath: String, val currentVersion: String, val checkForUpdatesOnStartup: Boolean, val isCheckingForUpdates: Boolean,