feat(aiturk): hide what the paired IDE cannot serve, plain error sentences, reconnect on return
When paired with AITURK IDE: - an "unknown method" (-32601) answer and the proxy's 403/route-404 are shown as plain sentences, never as raw JsonRpcError text; a method the IDE does not have is not sent again on the same socket - Account connectors, Vault, Keys and Files are hidden (the IDE has no connectors.* / vault.* and its phone proxy refuses /api/env and /api/files) - an idle-closed chat socket is reopened when the app returns to the foreground; idle tunnel connections are dropped on a network change - an unsaved chat no longer polls /api/sessions/<id> - the pairing screen shows the app version A plain Hermes connection is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B8ppceaR5s6cvMnm7uGRnf
This commit is contained in:
1 parent
c2d828b90a
commit
827c74b3c3
18 files changed
+709
-22
No files matched your search
@@ -0,0 +1,60 @@
|
||||
package com.m57.hermescontrol.ui.aiturkpair
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Computer
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.navigation3.runtime.NavKey
|
||||
import com.m57.hermescontrol.AccountConnectorsScreen
|
||||
import com.m57.hermescontrol.FilesScreen
|
||||
import com.m57.hermescontrol.KeysScreen
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.SettingsVault
|
||||
import com.m57.hermescontrol.data.aiturk.AiturkCompat
|
||||
import com.m57.hermescontrol.ui.common.EmptyState
|
||||
import com.m57.hermescontrol.ui.common.HermesScaffold
|
||||
import com.m57.hermescontrol.ui.common.NavIcon
|
||||
|
||||
/**
|
||||
* Screens a paired AITURK IDE cannot serve, hidden from the drawer and the
|
||||
* settings list while that pairing is the active connection:
|
||||
*
|
||||
* - Account connectors, Credential vault: the IDE's agent has no
|
||||
* `connectors.*` / `vault.*` methods;
|
||||
* - Keys, Files: the IDE's phone proxy refuses `/api/env` and `/api/files`
|
||||
* on purpose (secrets and the computer's files stay on the computer).
|
||||
*
|
||||
* A plain Hermes dashboard connection shows everything, as upstream does.
|
||||
*/
|
||||
object AiturkFeatureGate {
|
||||
val HIDDEN_WHEN_LINKED: Set<NavKey> = setOf(AccountConnectorsScreen, KeysScreen, FilesScreen, SettingsVault)
|
||||
|
||||
fun shows(
|
||||
key: NavKey,
|
||||
linked: Boolean = AiturkCompat.isLinked(),
|
||||
): Boolean = !(linked && key in HIDDEN_WHEN_LINKED)
|
||||
}
|
||||
|
||||
/** Shown instead of a hidden screen that is still reached (restored back stack, shortcut). */
|
||||
@Composable
|
||||
fun AiturkUnavailableScreen(
|
||||
@StringRes titleRes: Int,
|
||||
onOpenDrawer: (() -> Unit)?,
|
||||
) {
|
||||
HermesScaffold(
|
||||
title = { Text(stringResource(titleRes)) },
|
||||
navigationIcon = onOpenDrawer?.let { NavIcon.Menu(it) },
|
||||
) { padding ->
|
||||
EmptyState(
|
||||
title = stringResource(R.string.aiturk_feature_unavailable),
|
||||
subtitle = stringResource(R.string.aiturk_feature_unavailable_hint),
|
||||
icon = Icons.Filled.Computer,
|
||||
modifier = Modifier.padding(padding).testTag("aiturk_unavailable"),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
@@ -61,6 +62,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.journeyapps.barcodescanner.ScanContract
|
||||
import com.journeyapps.barcodescanner.ScanOptions
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.data.aiturk.AiturkCompat
|
||||
import com.m57.hermescontrol.data.aiturk.AiturkPairing
|
||||
import com.m57.hermescontrol.data.remote.requiresLocalNetworkPermission
|
||||
|
||||
@@ -286,6 +288,15 @@ fun AiturkPairScreen(
|
||||
TextButton(onClick = onBack, enabled = !state.busy) {
|
||||
Text(stringResource(R.string.aiturk_pair_back))
|
||||
}
|
||||
|
||||
// So the user can tell which build is installed when support asks.
|
||||
Text(
|
||||
text = stringResource(R.string.aiturk_app_version, AiturkCompat.versionLabel()),
|
||||
modifier = Modifier.testTag("aiturk_app_version"),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user