fix: disable Add Artifact until a dialect is picked
Submitting without a dialect was rejected in the view model, which
called onFailure, which navigated to ImplementationPendingRoute("Failed
Artifact") -- a whole screen away from the form, saying nothing about
which field was wrong, and leaving the way back to the only sensible fix
as the back button.
That is a bad way to report any missing field, but the dialect is the
one where it is unrecoverable in place. A blank name or url is answered
by typing; a dialect has to already exist, and since dialects moved to
the group screen there is nothing on this form that can conjure one. So
an unpicked dialect is not a mistake to report after the fact, it is a
state the button should not be pressable in.
Material 3 gives ExtendedFloatingActionButton no `enabled` parameter, so
this paints the disabled colours from ButtonDefaults.buttonColors() --
the same ones every other disabled button in the app resolves from the
theme, rather than an alpha invented here -- and returns early from
onClick.
Also marks it disabled to accessibility services. Colours alone leave a
screen reader announcing a button it is happy to press, and pressing it
does nothing, which is worse than a button that says it is unavailable.
A group with no dialects at all is covered by the same condition, since
there is then nothing to select.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,10 +20,12 @@ import androidx.compose.material.icons.filled.LocalOffer
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -33,6 +35,7 @@ import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -42,6 +45,8 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.semantics.disabled
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -110,6 +115,16 @@ fun AddArtifactScreen(
|
||||
// one is picked; dialects are defined from the group detail screen.
|
||||
var selectedDialectId: String? by remember { mutableStateOf(null) }
|
||||
|
||||
// Of the required fields this is the only one the screen cannot ask
|
||||
// for again: a dialect has to already exist, and nothing here can
|
||||
// create one. So an unpicked dialect is a dead end rather than
|
||||
// something to submit and be told about, and the button says so.
|
||||
val canAddArtifact = selectedDialectId != null
|
||||
|
||||
// M3 gives a FAB no `enabled`, so borrow the disabled colours every
|
||||
// other button in the app uses rather than inventing a shade here.
|
||||
val buttonColors = ButtonDefaults.buttonColors()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
@@ -126,7 +141,27 @@ fun AddArtifactScreen(
|
||||
actions = {},
|
||||
floatingActionButton = {
|
||||
ExtendedFloatingActionButton(
|
||||
modifier = if (canAddArtifact) {
|
||||
Modifier
|
||||
} else {
|
||||
// Looking unavailable is not being unavailable:
|
||||
// without this a screen reader still announces
|
||||
// a button it is happy to press.
|
||||
Modifier.semantics { disabled() }
|
||||
},
|
||||
containerColor = if (canAddArtifact) {
|
||||
FloatingActionButtonDefaults.containerColor
|
||||
} else {
|
||||
buttonColors.disabledContainerColor
|
||||
},
|
||||
contentColor = if (canAddArtifact) {
|
||||
contentColorFor(FloatingActionButtonDefaults.containerColor)
|
||||
} else {
|
||||
buttonColors.disabledContentColor
|
||||
},
|
||||
onClick = {
|
||||
if (!canAddArtifact) return@ExtendedFloatingActionButton
|
||||
|
||||
addArtifactViewModel.addArtifact(
|
||||
localChatRoom = addArtifactUIState.localChatRoom,
|
||||
nameField = nameFieldState,
|
||||
|
||||
Reference in New Issue
Block a user