fix(log): TalkBack could not find the mode row

The tappable mode row used a bare `clickable`, which declares no role. TalkBack read it as
two pieces of text with nothing to say it could be activated, so the only way to correct a
wrong mode was invisible to anyone using a screen reader - and the row had just become the
only way to reach that field.

Role.Button plus an onClickLabel naming the action. The label lives in the resource files
like every other user-visible string.

Caught by self-review against the project's own accessibility pattern in Components.kt
rather than by a test; Compose UI is not unit-tested here, so this class of defect is only
ever found by reading.
This commit is contained in:
mckero committed 2026-08-26 06:17:38 +00:00
1 parent 3d3db784a3
commit a3e3932f73
3 files changed
+7 -1

No files matched your search

@@ -277,6 +277,7 @@
<string name="wavelog_select_transponder">选择转发器</string>
<string name="wavelog_call_hint">对方呼号</string>
<string name="wavelog_mode_hint">模式</string>
<string name="wavelog_mode_edit">修改模式</string>
<string name="wavelog_saved">已存入本地日志</string>
<string name="wavelog_upload_done">已上传 %1$d 条, %2$d 条仍在队列</string>
<string name="wavelog_upload_all_ok">已上传 %1$d 条</string>
@@ -308,6 +308,7 @@
<string name="wavelog_select_transponder">Select transponder</string>
<string name="wavelog_call_hint">Callsign</string>
<string name="wavelog_mode_hint">Mode</string>
<string name="wavelog_mode_edit">Edit the mode</string>
<string name="wavelog_saved">Saved to local log</string>
<string name="wavelog_upload_done">Uploaded %1$d, %2$d still queued</string>
<string name="wavelog_upload_all_ok">Uploaded %1$d QSO</string>
@@ -58,6 +58,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
@@ -279,6 +280,7 @@ private fun ExpandedLogInput(
// previous one's mode and uploaded a value the operator never chose.
var mode by remember(radio.uuid) { mutableStateOf(radio.uplinkMode ?: "FM") }
var modeEditable by remember(radio.uuid) { mutableStateOf(false) }
val editModeLabel = stringResource(id = R.string.wavelog_mode_edit)
// Calls logged during this pass, so a repeat can be mentioned without being blocked: the same
// station on a later pass is a legitimate new contact. This replaces a 300ms window that
// swallowed what it guessed were accidental double submissions - a guess that could discard
@@ -442,7 +444,9 @@ private fun ExpandedLogInput(
// 48dp is the Material Design minimum for anything tappable, and this row is
// tapped to reveal the mode field. Padding alone left it around 20dp.
.heightIn(min = 48.dp)
.clickable { modeEditable = true }
// Role.Button so TalkBack announces it as interactive. A bare clickable
// declares no role, so the row read as two labels and the tap was undiscoverable.
.clickable(role = Role.Button, onClickLabel = editModeLabel) { modeEditable = true }
.padding(horizontal = LocalSpacing.current.extraExtraSmall)
) {
Text(