refactor: pick an artifact's dialect, do not invent one while adding it
Adding an artifact offered a "New dialect" chip that swapped in three more fields -- name, country, language -- and minted a dialect on the way to creating the artifact. Now that a group defines its dialects on its own screen, that path is a second, worse way to do the same thing: it creates a dialect as a side effect of an unrelated action, in a form where the fields belong to neither entity clearly, and with no sight of what the group has already defined beyond a row of chips. Drop it. The chip row is now exactly the dialects that exist, and selectedDialectId changes meaning from "null = create a new one" to "null = nothing picked yet" -- which the FAB rejects alongside the other required fields, rather than falling through to creating something. A group with no dialects yet gets a line saying so and pointing at the group screen, instead of a lone chip that opens a form. addArtifact loses the three TextFieldStates and existingDialectId for a single dialectId, and with them the branch that called addDialect and threaded its id back in. Validation is now one condition rather than one per path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6ff9fd2d38
commit
e14be2d187
2 files changed
+24
-147
No files matched your search
+20
-117
@@ -18,9 +18,6 @@ import androidx.compose.material.icons.filled.Label
|
||||
import androidx.compose.material.icons.filled.Link
|
||||
import androidx.compose.material.icons.filled.LocalOffer
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.Public
|
||||
import androidx.compose.material.icons.filled.Title
|
||||
import androidx.compose.material.icons.filled.Translate
|
||||
import androidx.compose.material3.BottomAppBar
|
||||
import androidx.compose.material3.BottomAppBarDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
@@ -108,12 +105,9 @@ fun AddArtifactScreen(
|
||||
val nameFieldState = rememberTextFieldState()
|
||||
val urlFieldState = rememberTextFieldState()
|
||||
val versionLabelFieldState = rememberTextFieldState("1.0")
|
||||
val dialectNameFieldState = rememberTextFieldState()
|
||||
val dialectCountryFieldState = rememberTextFieldState()
|
||||
val dialectLanguageFieldState = rememberTextFieldState()
|
||||
|
||||
// null = "New dialect" (show the create fields); otherwise the id of
|
||||
// an existing dialect to reuse.
|
||||
// The id of the group dialect this artifact is written in. Null until
|
||||
// one is picked; dialects are defined from the group detail screen.
|
||||
var selectedDialectId: String? by remember { mutableStateOf(null) }
|
||||
|
||||
Scaffold(
|
||||
@@ -138,10 +132,7 @@ fun AddArtifactScreen(
|
||||
nameField = nameFieldState,
|
||||
urlField = urlFieldState,
|
||||
versionLabelField = versionLabelFieldState,
|
||||
existingDialectId = selectedDialectId,
|
||||
dialectNameField = dialectNameFieldState,
|
||||
dialectCountryField = dialectCountryFieldState,
|
||||
dialectLanguageField = dialectLanguageFieldState,
|
||||
dialectId = selectedDialectId,
|
||||
onSuccess = { artifactId ->
|
||||
// Open the newly created artifact, removing this
|
||||
// add screen from the back stack.
|
||||
@@ -266,112 +257,24 @@ fun AddArtifactScreen(
|
||||
|
||||
Text("Source dialect")
|
||||
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
addArtifactUIState.dialects.forEach { dialect ->
|
||||
FilterChip(
|
||||
selected = selectedDialectId == dialect.id,
|
||||
onClick = { selectedDialectId = dialect.id },
|
||||
label = { Text(dialect.name) }
|
||||
)
|
||||
if (addArtifactUIState.dialects.isEmpty()) {
|
||||
Text(
|
||||
text = "No dialects have been defined in this group yet. Add one from the group's detail screen first.",
|
||||
style = MaterialTheme.typography.bodySmall
|
||||
)
|
||||
} else {
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
addArtifactUIState.dialects.forEach { dialect ->
|
||||
FilterChip(
|
||||
selected = selectedDialectId == dialect.id,
|
||||
onClick = { selectedDialectId = dialect.id },
|
||||
label = { Text(dialect.name) }
|
||||
)
|
||||
}
|
||||
}
|
||||
FilterChip(
|
||||
selected = selectedDialectId == null,
|
||||
onClick = { selectedDialectId = null },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Add,
|
||||
contentDescription = "Create a new dialect"
|
||||
)
|
||||
},
|
||||
label = { Text("New dialect") }
|
||||
)
|
||||
}
|
||||
|
||||
// Only collect new-dialect details when not reusing an existing one.
|
||||
if (selectedDialectId == null) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = dialectNameFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Title,
|
||||
contentDescription = "Name of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Dialect Name"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. Sesotho"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = dialectCountryFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Public,
|
||||
contentDescription = "Country of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Country"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. Lesotho"
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.background(BottomAppBarDefaults.containerColor),
|
||||
state = dialectLanguageFieldState,
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
disabledBorderColor = Color.Transparent
|
||||
),
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Translate,
|
||||
contentDescription = "Language of the dialect"
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(
|
||||
text = "Language"
|
||||
)
|
||||
},
|
||||
placeholder = {
|
||||
Text(
|
||||
text = "eg. st"
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Add Visibility
|
||||
|
||||
+4
-30
@@ -62,10 +62,7 @@ class AddArtifactViewModel(
|
||||
nameField: TextFieldState,
|
||||
urlField: TextFieldState,
|
||||
versionLabelField: TextFieldState,
|
||||
existingDialectId: HexKey?,
|
||||
dialectNameField: TextFieldState,
|
||||
dialectCountryField: TextFieldState,
|
||||
dialectLanguageField: TextFieldState,
|
||||
dialectId: HexKey?,
|
||||
visibility: String = MantraRepository.DEFAULT_VISIBILITY,
|
||||
license: String = MantraRepository.DEFAULT_LICENSE,
|
||||
onSuccess: (artifactId: String) -> Unit,
|
||||
@@ -75,16 +72,10 @@ class AddArtifactViewModel(
|
||||
val name = nameField.text.toString()
|
||||
val url = urlField.text.toString()
|
||||
val versionLabel = versionLabelField.text.toString()
|
||||
val dialectName = dialectNameField.text.toString()
|
||||
val dialectCountry = dialectCountryField.text.toString()
|
||||
val dialectLanguage = dialectLanguageField.text.toString()
|
||||
|
||||
// When no existing dialect is selected, the new-dialect fields are required.
|
||||
val creatingNewDialect = existingDialectId.isNullOrBlank()
|
||||
val newDialectIncomplete = dialectName.isBlank() || dialectCountry.isBlank() || dialectLanguage.isBlank()
|
||||
if (name.isBlank() || url.isBlank() || versionLabel.isBlank() ||
|
||||
(creatingNewDialect && newDialectIncomplete)
|
||||
) {
|
||||
// addArtifact requires an existing source dialect; they are defined
|
||||
// from the group detail screen, not here.
|
||||
if (name.isBlank() || url.isBlank() || versionLabel.isBlank() || dialectId.isNullOrBlank()) {
|
||||
onFailure.invoke()
|
||||
return
|
||||
}
|
||||
@@ -95,20 +86,6 @@ class AddArtifactViewModel(
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val artifactInnerEvent = runCatching {
|
||||
// Reuse the selected dialect, or create a new source dialect and
|
||||
// reference it by id. addArtifact requires a valid dialectId.
|
||||
val dialectId = if (creatingNewDialect) {
|
||||
mantraRepository.addDialect(
|
||||
localChatRoom = localChatRoom,
|
||||
name = dialectName,
|
||||
country = dialectCountry,
|
||||
language = dialectLanguage,
|
||||
userPublicKey = activeUserPublicKey,
|
||||
)?.id ?: return@runCatching null
|
||||
} else {
|
||||
existingDialectId
|
||||
}
|
||||
|
||||
mantraRepository.addArtifact(
|
||||
localChatRoom = localChatRoom,
|
||||
name = name,
|
||||
@@ -127,9 +104,6 @@ class AddArtifactViewModel(
|
||||
nameField.clearText()
|
||||
urlField.clearText()
|
||||
versionLabelField.clearText()
|
||||
dialectNameField.clearText()
|
||||
dialectCountryField.clearText()
|
||||
dialectLanguageField.clearText()
|
||||
|
||||
viewModelScope.launch(Dispatchers.Main) {
|
||||
onSuccess.invoke(artifactInnerEvent.id)
|
||||
|
||||
Reference in new issue
Block a user