Fix missing auth banner in tailssh

This commit is contained in:
世界
2026-07-06 21:15:32 +08:00
parent 43eebd1373
commit 0445098157
3 changed files with 60 additions and 0 deletions
@@ -12,6 +12,8 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
@@ -27,6 +29,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
@@ -39,9 +42,16 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withLink
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.viewmodel.compose.viewModel
@@ -298,6 +308,24 @@ fun TailscaleSSHTerminalScreen(
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(top = 16.dp),
)
val banner = activeSession.terminalSession.authBanner
if (!banner.isNullOrBlank()) {
val linkColor = MaterialTheme.colorScheme.primary
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
.widthIn(max = 480.dp),
) {
Text(
remember(banner, linkColor) { bannerAnnotatedString(banner, linkColor) },
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(12.dp),
)
}
}
}
}
}
@@ -331,6 +359,30 @@ private class TerminalViewRef {
var view: TerminalView? = null
}
private val bannerUrlRegex = Regex("""https?://\S+""")
private fun bannerAnnotatedString(text: String, linkColor: Color) = buildAnnotatedString {
var lastIndex = 0
for (match in bannerUrlRegex.findAll(text)) {
if (match.range.first > lastIndex) {
append(text.substring(lastIndex, match.range.first))
}
val url = match.value
withLink(
LinkAnnotation.Url(
url,
TextLinkStyles(SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline)),
),
) {
append(url)
}
lastIndex = match.range.last + 1
}
if (lastIndex < text.length) {
append(text.substring(lastIndex))
}
}
private fun resolveTypeface(fontFamily: String, customFontPath: String): Typeface? {
if (customFontPath.isNotBlank()) {
val typeface = ImportedFontStore.loadTypeface(customFontPath)
@@ -45,6 +45,7 @@ class TailscaleSSHTerminalViewModel : BaseViewModel<TailscaleSSHTerminalState, N
}
override fun onAuthBanner(message: String) {
updateState { copy(sessions = sessions.toList(), version = version + 1) }
}
})
@@ -26,6 +26,7 @@ public class TailscaleSSHTerminalSession extends TerminalSession {
private TailscaleSSHSession sshSession;
private PhaseCallback phaseCallback;
private volatile Phase phase = Phase.CONNECTING;
private volatile String authBanner;
private int exitCode;
private String exitSignal;
private String exitErrorMessage;
@@ -56,6 +57,10 @@ public class TailscaleSSHTerminalSession extends TerminalSession {
return phase;
}
public String getAuthBanner() {
return authBanner;
}
public int getSSHExitCode() {
return exitCode;
}
@@ -125,6 +130,7 @@ public class TailscaleSSHTerminalSession extends TerminalSession {
public void onReady() {
phase = Phase.RUNNING;
authBanner = null;
mainHandler.post(
() -> {
if (phaseCallback != null) {
@@ -134,6 +140,7 @@ public class TailscaleSSHTerminalSession extends TerminalSession {
}
public void onAuthBanner(String message) {
authBanner = message;
mainHandler.post(
() -> {
if (phaseCallback != null) {