fix(android): gate canvas restore on node connectivity

This commit is contained in:
Ayaan Zaidi
2026-02-25 11:31:45 +05:30
committed by Ayaan Zaidi
parent 41870fac16
commit b065265b73
3 changed files with 16 additions and 9 deletions

View File

@@ -26,6 +26,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app) {
val discoveryStatusText: StateFlow<String> = runtime.discoveryStatusText
val isConnected: StateFlow<Boolean> = runtime.isConnected
val isNodeConnected: StateFlow<Boolean> = runtime.nodeConnected
val statusText: StateFlow<String> = runtime.statusText
val serverName: StateFlow<String?> = runtime.serverName
val remoteAddress: StateFlow<String?> = runtime.remoteAddress

View File

@@ -181,6 +181,8 @@ class NodeRuntime(context: Context) {
private val _isConnected = MutableStateFlow(false)
val isConnected: StateFlow<Boolean> = _isConnected.asStateFlow()
private val _nodeConnected = MutableStateFlow(false)
val nodeConnected: StateFlow<Boolean> = _nodeConnected.asStateFlow()
private val _statusText = MutableStateFlow("Offline")
val statusText: StateFlow<String> = _statusText.asStateFlow()
@@ -224,7 +226,6 @@ class NodeRuntime(context: Context) {
private var didAutoRequestCanvasRehydrate = false
private val canvasRehydrateSeq = AtomicLong(0)
private var operatorConnected = false
private var nodeConnected = false
private var operatorStatusText: String = "Offline"
private var nodeStatusText: String = "Offline"
@@ -270,7 +271,7 @@ class NodeRuntime(context: Context) {
identityStore = identityStore,
deviceAuthStore = deviceAuthStore,
onConnected = { _, _, _ ->
nodeConnected = true
_nodeConnected.value = true
nodeStatusText = "Connected"
didAutoRequestCanvasRehydrate = false
_canvasA2uiHydrated.value = false
@@ -281,7 +282,7 @@ class NodeRuntime(context: Context) {
requestCanvasRehydrate(source = "node_connect", force = false)
},
onDisconnected = { message ->
nodeConnected = false
_nodeConnected.value = false
nodeStatusText = message
didAutoRequestCanvasRehydrate = false
_canvasA2uiHydrated.value = false
@@ -329,9 +330,9 @@ class NodeRuntime(context: Context) {
_isConnected.value = operatorConnected
_statusText.value =
when {
operatorConnected && nodeConnected -> "Connected"
operatorConnected && !nodeConnected -> "Connected (node offline)"
!operatorConnected && nodeConnected -> "Connected (operator offline)"
operatorConnected && _nodeConnected.value -> "Connected"
operatorConnected && !_nodeConnected.value -> "Connected (node offline)"
!operatorConnected && _nodeConnected.value -> "Connected (operator offline)"
operatorStatusText.isNotBlank() && operatorStatusText != "Offline" -> operatorStatusText
else -> nodeStatusText
}
@@ -361,7 +362,11 @@ class NodeRuntime(context: Context) {
fun requestCanvasRehydrate(source: String = "manual", force: Boolean = true) {
scope.launch {
if (!nodeConnected) return@launch
if (!_nodeConnected.value) {
_canvasRehydratePending.value = false
_canvasRehydrateErrorText.value = "Node offline. Reconnect and retry."
return@launch
}
if (!force && didAutoRequestCanvasRehydrate) return@launch
didAutoRequestCanvasRehydrate = true
val requestId = canvasRehydrateSeq.incrementAndGet()
@@ -725,7 +730,7 @@ class NodeRuntime(context: Context) {
contextJson = contextJson,
)
val connected = nodeConnected
val connected = _nodeConnected.value
var error: String? = null
if (connected) {
try {

View File

@@ -125,12 +125,13 @@ fun PostOnboardingTabs(viewModel: MainViewModel, modifier: Modifier = Modifier)
@Composable
private fun ScreenTabScreen(viewModel: MainViewModel) {
val isConnected by viewModel.isConnected.collectAsState()
val isNodeConnected by viewModel.isNodeConnected.collectAsState()
val canvasUrl by viewModel.canvasCurrentUrl.collectAsState()
val canvasA2uiHydrated by viewModel.canvasA2uiHydrated.collectAsState()
val canvasRehydratePending by viewModel.canvasRehydratePending.collectAsState()
val canvasRehydrateErrorText by viewModel.canvasRehydrateErrorText.collectAsState()
val isA2uiUrl = canvasUrl?.contains("/__openclaw__/a2ui/") == true
val showRestoreCta = isConnected && (canvasUrl.isNullOrBlank() || (isA2uiUrl && !canvasA2uiHydrated))
val showRestoreCta = isConnected && isNodeConnected && (canvasUrl.isNullOrBlank() || (isA2uiUrl && !canvasA2uiHydrated))
val restoreCtaText =
when {
canvasRehydratePending -> "Restore requested. Waiting for agent…"