diff --git a/core/presentation/src/main/res/values-zh/strings.xml b/core/presentation/src/main/res/values-zh/strings.xml
index 6769961b..e56b46b1 100644
--- a/core/presentation/src/main/res/values-zh/strings.xml
+++ b/core/presentation/src/main/res/values-zh/strings.xml
@@ -318,6 +318,7 @@
Cookie
复制
撤销
+ 删除这条联络
时间
频率
卫星
diff --git a/core/presentation/src/main/res/values/strings.xml b/core/presentation/src/main/res/values/strings.xml
index 10b7a2a9..1cf5724a 100644
--- a/core/presentation/src/main/res/values/strings.xml
+++ b/core/presentation/src/main/res/values/strings.xml
@@ -349,6 +349,7 @@
Cookie
Copy
Undo
+ Delete this contact
Time
Freq
Satellite
diff --git a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/LogTab.kt b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/LogTab.kt
index 061f344b..ed1b2320 100644
--- a/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/LogTab.kt
+++ b/feature/radar/src/main/java/com/rtbishop/look4sat/feature/radar/LogTab.kt
@@ -18,6 +18,9 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
import com.rtbishop.look4sat.core.presentation.LocalSpacing
import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.widthIn
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.ui.res.painterResource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -59,6 +62,9 @@ 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.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
@@ -574,10 +580,33 @@ internal fun SwipeDeleteRow(
}
}
+ val deleteActionLabel = stringResource(id = R.string.wavelog_delete_action)
+ val undoActionLabel = stringResource(id = R.string.wavelog_delete_undo)
Box(
modifier = Modifier
.fillMaxWidth()
.onSizeChanged { rowWidth = it.width }
+ // Deleting was reachable ONLY by dragging, so TalkBack, switch access and Voice Access
+ // users could not delete a record at all - not with difficulty, at all. The Compose
+ // accessibility guide names this exact case: swipe gestures should be exposed as custom
+ // actions because they are hard or impossible for users with motor impairments.
+ .semantics {
+ customActions = buildList {
+ if (pending) {
+ add(CustomAccessibilityAction(undoActionLabel) {
+ pending = false
+ offsetX = 0f
+ true
+ })
+ } else {
+ add(CustomAccessibilityAction(deleteActionLabel) {
+ pending = true
+ offsetX = -threshold
+ true
+ })
+ }
+ }
+ }
) {
// Background layer (right-side icons: trash / undo + countdown)
Box(
@@ -603,22 +632,34 @@ internal fun SwipeDeleteRow(
fontSize = 13.sp,
fontWeight = FontWeight.Bold,
color = WaveLogYellow,
+ textAlign = TextAlign.Center,
modifier = Modifier
.clip(RoundedCornerShape(8.dp))
.background(WaveLogYellow.copy(alpha = 0.15f))
- .clickable {
+ // 48dp, the Material minimum. This was a 29dp target with a five-second
+ // countdown running behind it, so a miss was unrecoverable - the worst
+ // possible place in the screen to be hard to hit.
+ .heightIn(min = 48.dp)
+ .widthIn(min = 64.dp)
+ .clickable(role = Role.Button) {
pending = false
offsetX = 0f
}
- .padding(horizontal = 10.dp, vertical = 6.dp)
+ .wrapContentHeight(Alignment.CenterVertically)
+ .padding(horizontal = 10.dp)
)
}
} else {
- // Trash icon (always visible while swiping, yellow)
- Text(
- text = "🗑",
- fontSize = 20.sp,
- modifier = Modifier.padding(end = 16.dp)
+ // A real icon, not an emoji: emoji render differently on every device and font, and
+ // this project forbids them as icons. contentDescription is null because the row
+ // already exposes delete as a custom accessibility action.
+ Icon(
+ painter = painterResource(id = R.drawable.ic_delete),
+ contentDescription = null,
+ tint = WaveLogYellow,
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .size(24.dp)
)
}
}