























@@ -42,6 +42,7 @@ import androidx.compose.material.icons.automirrored.filled.Send
4242import androidx.compose.material.icons.automirrored.filled.VolumeOff
4343import androidx.compose.material.icons.automirrored.filled.VolumeUp
4444import androidx.compose.material.icons.filled.Close
45+import androidx.compose.material.icons.filled.Cloud
4546import androidx.compose.material.icons.filled.GraphicEq
4647import androidx.compose.material.icons.filled.Info
4748import androidx.compose.material.icons.filled.Mic
@@ -78,6 +79,7 @@ import androidx.core.content.ContextCompat
7879fun VoiceScreen(
7980viewModel: MainViewModel,
8081onOpenCommand: () -> Unit,
82+onOpenGatewaySettings: () -> Unit,
8183onOpenVoiceSettings: () -> Unit,
8284) {
8385val context = LocalContext.current
@@ -113,6 +115,7 @@ fun VoiceScreen(
113115114116val activeConversation = if (voiceCaptureMode == VoiceCaptureMode.TalkMode) talkModeConversation else micConversation
115117val voiceActive = micEnabled || micIsSending || talkModeEnabled
118+val gatewayReady = gatewayStatus.isVoiceGatewayReady()
116119val activeStatus =
117120 voiceStatusLabel(
118121 gatewayStatus = gatewayStatus,
@@ -161,7 +164,7 @@ fun VoiceScreen(
161164 verticalArrangement = Arrangement.spacedBy(8.dp),
162165 ) {
163166VoiceHeader(
164- statusText = if (voiceActive) activeStatus else "Your voice command center.",
167+ statusText = if (voiceActive || !gatewayReady) activeStatus else "Your voice command center.",
165168 speakerEnabled = speakerEnabled,
166169 onToggleSpeaker = { viewModel.setSpeakerEnabled(!speakerEnabled) },
167170 onOpenCommand = onOpenCommand,
@@ -175,6 +178,7 @@ fun VoiceScreen(
175178 talkModeListening = talkModeListening,
176179 talkModeSpeaking = talkModeSpeaking,
177180 micLiveTranscript = micLiveTranscript,
181+ gatewayReady = gatewayReady,
178182 onStartTalk = {
179183 runVoiceAction(
180184 action = VoiceAction.Talk,
@@ -198,6 +202,7 @@ fun VoiceScreen(
198202 run = { viewModel.setMicEnabled(!micEnabled) },
199203 )
200204 },
205+ onConnectGateway = onOpenGatewaySettings,
201206 )
202207203208if (!hasMicPermission) {
@@ -582,8 +587,10 @@ private fun VoiceHero(
582587talkModeListening: Boolean,
583588talkModeSpeaking: Boolean,
584589micLiveTranscript: String?,
590+gatewayReady: Boolean,
585591onStartTalk: () -> Unit,
586592onStartDictation: () -> Unit,
593+onConnectGateway: () -> Unit,
587594) {
588595Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(10.dp)) {
589596VoiceOrb(
@@ -607,6 +614,7 @@ private fun VoiceHero(
607614 talkModeListening -> "Listening"
608615 talkModeEnabled -> "Talk is live"
609616 micEnabled -> "Dictation is listening"
617+!gatewayReady -> "Gateway offline"
610618else -> "Ready to talk"
611619 },
612620 style = ClawTheme.type.body,
@@ -634,24 +642,46 @@ private fun VoiceHero(
634642ClawPanel(contentPadding = PaddingValues(horizontal = 0.dp, vertical = 0.dp)) {
635643VoiceModeRow(
636644 title = if (talkModeEnabled) "End Talk" else "Realtime Talk",
637- subtitle = if (talkModeEnabled) "Conversation is live" else "Natural conversation in real time",
645+ subtitle =
646+when {
647+ talkModeEnabled -> "Conversation is live"
648+ gatewayReady -> "Natural conversation in real time"
649+else -> "Connect gateway to start"
650+ },
638651 icon = if (talkModeEnabled) Icons.Default.PhoneDisabled else Icons.Default.RecordVoiceOver,
639652 onClick = onStartTalk,
653+ enabled = gatewayReady || talkModeEnabled,
640654 )
641655VoiceModeRow(
642656 title = if (micEnabled) "Stop Dictation" else "Dictation",
643- subtitle = if (micEnabled) "Listening for one turn" else "Convert speech to text",
657+ subtitle =
658+when {
659+ micEnabled -> "Listening for one turn"
660+ gatewayReady -> "Convert speech to text"
661+else -> "Connect gateway to start"
662+ },
644663 icon = if (micEnabled) Icons.Default.MicOff else Icons.Default.TextFields,
645664 onClick = onStartDictation,
665+ enabled = gatewayReady || micEnabled,
646666 )
647667 }
648668649669VoiceProviderCard(gatewayStatus = gatewayStatus)
650670651671VoicePrimaryAction(
652- text = if (talkModeEnabled) "End Talk" else "Start Talk",
653- icon = if (talkModeEnabled) Icons.Default.PhoneDisabled else Icons.Default.Phone,
654- onClick = onStartTalk,
672+ text =
673+when {
674+ talkModeEnabled -> "End Talk"
675+ gatewayReady -> "Start Talk"
676+else -> "Connect Gateway"
677+ },
678+ icon =
679+when {
680+ talkModeEnabled -> Icons.Default.PhoneDisabled
681+ gatewayReady -> Icons.Default.Phone
682+else -> Icons.Default.Cloud
683+ },
684+ onClick = if (gatewayReady || talkModeEnabled) onStartTalk else onConnectGateway,
655685 )
656686 }
657687}
@@ -662,8 +692,9 @@ private fun VoiceModeRow(
662692subtitle: String,
663693icon: androidx.compose.ui.graphics.vector.ImageVector,
664694onClick: () -> Unit,
695+enabled: Boolean = true,
665696) {
666-Surface(onClick = onClick, color = Color.Transparent, contentColor = ClawTheme.colors.text) {
697+Surface(onClick = onClick, enabled = enabled, color = Color.Transparent, contentColor = ClawTheme.colors.text) {
667698Row(
668699 modifier = Modifier.fillMaxWidth().heightIn(min = 60.dp).padding(horizontal = 10.dp, vertical = 6.dp),
669700 verticalAlignment = Alignment.CenterVertically,
@@ -672,19 +703,26 @@ private fun VoiceModeRow(
672703Surface(
673704 modifier = Modifier.size(34.dp),
674705 shape = CircleShape,
675- color = ClawTheme.colors.surface,
676- contentColor = ClawTheme.colors.text,
706+ color = if (enabled) ClawTheme.colors.surface else ClawTheme.colors.canvas,
707+ contentColor = if (enabled) ClawTheme.colors.text else ClawTheme.colors.textSubtle,
677708 border = BorderStroke(1.dp, ClawTheme.colors.border),
678709 ) {
679710Box(contentAlignment = Alignment.Center) {
680711Icon(imageVector = icon, contentDescription = null, modifier = Modifier.size(16.dp))
681712 }
682713 }
683714Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) {
684-Text(text = title, style = ClawTheme.type.body, color = ClawTheme.colors.text, maxLines = 1)
715+Text(text = title, style = ClawTheme.type.body, color = if (enabled) ClawTheme.colors.text else ClawTheme.colors.textMuted, maxLines = 1)
685716Text(text = subtitle, style = ClawTheme.type.caption.copy(fontSize = 12.5.sp, lineHeight = 16.sp), color = ClawTheme.colors.textMuted, maxLines = 1)
686717 }
687-Icon(imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, contentDescription = null, modifier = Modifier.size(21.dp), tint = ClawTheme.colors.textMuted)
718+if (enabled) {
719+Icon(
720+ imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
721+ contentDescription = null,
722+ modifier = Modifier.size(21.dp),
723+ tint = ClawTheme.colors.textMuted,
724+ )
725+ }
688726 }
689727 }
690728}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。