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:
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_select_transponder">选择转发器</string>
|
||||||
<string name="wavelog_call_hint">对方呼号</string>
|
<string name="wavelog_call_hint">对方呼号</string>
|
||||||
<string name="wavelog_mode_hint">模式</string>
|
<string name="wavelog_mode_hint">模式</string>
|
||||||
|
<string name="wavelog_mode_edit">修改模式</string>
|
||||||
<string name="wavelog_saved">已存入本地日志</string>
|
<string name="wavelog_saved">已存入本地日志</string>
|
||||||
<string name="wavelog_upload_done">已上传 %1$d 条, %2$d 条仍在队列</string>
|
<string name="wavelog_upload_done">已上传 %1$d 条, %2$d 条仍在队列</string>
|
||||||
<string name="wavelog_upload_all_ok">已上传 %1$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_select_transponder">Select transponder</string>
|
||||||
<string name="wavelog_call_hint">Callsign</string>
|
<string name="wavelog_call_hint">Callsign</string>
|
||||||
<string name="wavelog_mode_hint">Mode</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_saved">Saved to local log</string>
|
||||||
<string name="wavelog_upload_done">Uploaded %1$d, %2$d still queued</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>
|
<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.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.semantics.Role
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
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.
|
// previous one's mode and uploaded a value the operator never chose.
|
||||||
var mode by remember(radio.uuid) { mutableStateOf(radio.uplinkMode ?: "FM") }
|
var mode by remember(radio.uuid) { mutableStateOf(radio.uplinkMode ?: "FM") }
|
||||||
var modeEditable by remember(radio.uuid) { mutableStateOf(false) }
|
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
|
// 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
|
// 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
|
// 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
|
// 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.
|
// tapped to reveal the mode field. Padding alone left it around 20dp.
|
||||||
.heightIn(min = 48.dp)
|
.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)
|
.padding(horizontal = LocalSpacing.current.extraExtraSmall)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
Reference in new issue
Block a user