@@ -34,8 +34,10 @@ import androidx.compose.ui.Modifier
34import androidx.compose.ui.draw.clip
34import androidx.compose.ui.draw.clip
35import androidx.compose.ui.platform.LocalContext
35import androidx.compose.ui.platform.LocalContext
36import androidx.compose.ui.semantics.Role
36import androidx.compose.ui.semantics.Role
37+import androidx.compose.ui.semantics.contentDescription
37import androidx.compose.ui.semantics.role
38import androidx.compose.ui.semantics.role
38import androidx.compose.ui.semantics.semantics
39import androidx.compose.ui.semantics.semantics
40+import androidx.compose.ui.semantics.stateDescription
39import androidx.compose.ui.text.font.FontFamily
41import androidx.compose.ui.text.font.FontFamily
40import androidx.compose.ui.res.stringResource
42import androidx.compose.ui.res.stringResource
41import androidx.compose.ui.unit.dp
43import androidx.compose.ui.unit.dp
@@ -92,12 +94,17 @@ private fun ReasoningBlock(text: String, streaming: Boolean, modifier: Modifier)
92 if (text.isBlank()) return
94 if (text.isBlank()) return
93 val context = LocalContext.current
95 val context = LocalContext.current
94 var expanded by remember { mutableStateOf(false) }
96 var expanded by remember { mutableStateOf(false) }
97+ val expandedState = stringResource(R.string.state_expanded)
98+ val collapsedState = stringResource(R.string.state_collapsed)
95 Column(modifier = modifier.fillMaxWidth()) {
99 Column(modifier = modifier.fillMaxWidth()) {
97 modifier = Modifier
101 modifier = Modifier
98 .clickable { expanded = !expanded }
102 .clickable { expanded = !expanded }
99 .padding(vertical = 4.dp)
103 .padding(vertical = 4.dp)
100− .semantics { role = Role.Button },
105+ role = Role.Button
106+ stateDescription = if (expanded) expandedState else collapsedState
101 verticalAlignment = Alignment.CenterVertically,
108 verticalAlignment = Alignment.CenterVertically,
103 if (streaming) {
110 if (streaming) {
@@ -167,6 +174,8 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
167 if (detail != null) {
174 if (detail != null) {
168 val collapsed = remember(detail) { detail.take(COLLAPSED_LIMIT) }
175 val collapsed = remember(detail) { detail.take(COLLAPSED_LIMIT) }
169 var expanded by remember(detail) { mutableStateOf(false) }
176 var expanded by remember(detail) { mutableStateOf(false) }
177+ val expandedState = stringResource(R.string.state_expanded)
178+ val collapsedState = stringResource(R.string.state_collapsed)
170 val display = if (expanded || detail.length <= COLLAPSED_LIMIT) detail else collapsed
179 val display = if (expanded || detail.length <= COLLAPSED_LIMIT) detail else collapsed
171 if (looksLikeDiff(display)) {
180 if (looksLikeDiff(display)) {
172 DiffView(display)
181 DiffView(display)
@@ -182,6 +191,9 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
182 TextButton(
191 TextButton(
183 onClick = { expanded = !expanded },
192 onClick = { expanded = !expanded },
184 contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 0.dp),
193 contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 0.dp),
194+ modifier = Modifier.semantics {
195+ stateDescription = if (expanded) expandedState else collapsedState
187 if (expanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
199 if (expanded) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
@@ -210,13 +222,26 @@ private fun ToolCallView(part: ToolPart, modifier: Modifier) {
210private fun ToolStatusIcon(state: ToolState) {
222private fun ToolStatusIcon(state: ToolState) {
211 when (state) {
223 when (state) {
212 is ToolPending, is ToolRunning ->
224 is ToolPending, is ToolRunning ->
213− CircularProgressIndicator(modifier = Modifier.size(16.dp), strokeWidth = 2.dp)
225+ CircularProgressIndicator(
226+ modifier = Modifier.size(16.dp).semantics { contentDescription = "" },
214 is ToolCompleted ->
229 is ToolCompleted ->
231+ Icons.Filled.CheckCircle,
232+ contentDescription = stringResource(R.string.tool_completed),
233+ modifier = Modifier.size(16.dp),
215− Icon(Icons.Filled.CheckCircle, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.primary)
234+ tint = MaterialTheme.colorScheme.primary,
216 is ToolError ->
236 is ToolError ->
239+ contentDescription = stringResource(R.string.tool_error),
240+ modifier = Modifier.size(16.dp),
217− Icon(Icons.Filled.Error, null, Modifier.size(16.dp), tint = MaterialTheme.colorScheme.error)
241+ tint = MaterialTheme.colorScheme.error,
218 is ToolUnknown ->
243 is ToolUnknown ->
219− Icon(Icons.Filled.Bolt, null, Modifier.size(16.dp))
244+ Icon(Icons.Filled.Bolt, contentDescription = null, modifier = Modifier.size(16.dp))