Merge pull request #2920 from remychantenay/android-label-name-length-validation

Android: Add label name length validation upon creation
This commit is contained in:
Jackson Harper
2023-10-17 16:47:32 +08:00
committed by GitHub
3 changed files with 47 additions and 30 deletions

View File

@ -3,6 +3,7 @@
package app.omnivore.omnivore.ui.components package app.omnivore.omnivore.ui.components
import LabelChip import LabelChip
import android.widget.Toast
import androidx.compose.foundation.* import androidx.compose.foundation.*
import androidx.compose.foundation.interaction.FocusInteraction import androidx.compose.foundation.interaction.FocusInteraction
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
@ -219,12 +220,12 @@ class LabelChipView(label: SavedItemLabel) : Chip(label.name) {
val label = label val label = label
} }
fun findOrCreateLabel(labelsViewModel: LabelsViewModel, labels: List<SavedItemLabel>, name: TextFieldValue): SavedItemLabel { fun findOrCreateLabel(labelsViewModel: LabelsViewModel, labels: List<SavedItemLabel>, name: String): SavedItemLabel {
val found = labels.find { it.name == name.text } val found = labels.find { it.name == name }
if (found != null) { if (found != null) {
return found return found
} }
return labelsViewModel.createNewSavedItemLabelWithTemp(name.text, LabelSwatchHelper.random()) return labelsViewModel.createNewSavedItemLabelWithTemp(name, LabelSwatchHelper.random())
} }
@Composable @Composable
@ -308,7 +309,7 @@ fun LabelsSelectionSheetContent(
LabelChipView(it) LabelChipView(it)
} ?: null } ?: null
} else { } else {
LabelChipView(findOrCreateLabel(labelsViewModel = labelsViewModel, labels = labels, name = it)) LabelChipView(findOrCreateLabel(labelsViewModel = labelsViewModel, labels = labels, name = it.text))
} }
}, },
chipLeadingIcon = { chip -> CircleIcon(colorHex = chip.label.color) }, chipLeadingIcon = { chip -> CircleIcon(colorHex = chip.label.color) },
@ -341,19 +342,34 @@ fun LabelsSelectionSheetContent(
) )
if (!isLibraryMode && filterTextValue.text.isNotEmpty() && currentLabel == null) { if (!isLibraryMode && filterTextValue.text.isNotEmpty() && currentLabel == null) {
val context = LocalContext.current
Row( Row(
horizontalArrangement = Arrangement.Start, horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable { .clickable {
val label = findOrCreateLabel( val labelName = filterTextValue.text.trim()
labelsViewModel = labelsViewModel, when(labelsViewModel.validateLabelName(labelName)) {
labels = labels, LabelsViewModel.Error.LabelNameTooLong -> {
name = filterTextValue Toast.makeText(
) context,
state.addChip(LabelChipView(label)) context.getString(R.string.label_selection_sheet_label_too_long_error_msg,
filterTextValue = TextFieldValue() labelsViewModel.labelNameMaxLength),
Toast.LENGTH_SHORT
).show()
}
null -> {
val label = findOrCreateLabel(
labelsViewModel = labelsViewModel,
labels = labels,
name = labelName
)
state.addChip(LabelChipView(label))
filterTextValue = TextFieldValue()
}
}
} }
.padding(horizontal = 10.dp) .padding(horizontal = 10.dp)
.padding(top = 10.dp, bottom = 5.dp) .padding(top = 10.dp, bottom = 5.dp)
@ -364,7 +380,7 @@ fun LabelsSelectionSheetContent(
contentDescription = null, contentDescription = null,
modifier = Modifier.padding(end = 8.dp) modifier = Modifier.padding(end = 8.dp)
) )
Text(text = stringResource(R.string.label_selection_sheet_text_create, filterTextValue.text)) Text(text = stringResource(R.string.label_selection_sheet_text_create, filterTextValue.text.trim()))
} }
} }

View File

@ -1,34 +1,16 @@
package app.omnivore.omnivore.ui.components package app.omnivore.omnivore.ui.components
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.* import androidx.lifecycle.*
import app.omnivore.omnivore.DatastoreKeys
import app.omnivore.omnivore.DatastoreRepository import app.omnivore.omnivore.DatastoreRepository
import app.omnivore.omnivore.dataService.* import app.omnivore.omnivore.dataService.*
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
import app.omnivore.omnivore.graphql.generated.type.SetLabelsInput
import app.omnivore.omnivore.models.ServerSyncStatus import app.omnivore.omnivore.models.ServerSyncStatus
import app.omnivore.omnivore.networking.* import app.omnivore.omnivore.networking.*
import app.omnivore.omnivore.persistence.entities.SavedItem
import app.omnivore.omnivore.persistence.entities.SavedItemAndSavedItemLabelCrossRef
import app.omnivore.omnivore.persistence.entities.SavedItemLabel import app.omnivore.omnivore.persistence.entities.SavedItemLabel
import app.omnivore.omnivore.ui.components.LabelSwatchHelper
import app.omnivore.omnivore.ui.library.SavedItemAction
import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull
import com.google.gson.Gson
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.distinctUntilChanged
import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.ZoneOffset import java.time.ZoneOffset
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@ -42,6 +24,24 @@ class LabelsViewModel @Inject constructor(
private val dataService: DataService, private val dataService: DataService,
private val networker: Networker private val networker: Networker
): ViewModel() { ): ViewModel() {
val labelNameMaxLength = 64
enum class Error {
LabelNameTooLong
}
/**
* Checks whether or not the provided label name is valid.
* @param labelName The name of the label.
* @return null if valid, [Error] otherwise.
*/
fun validateLabelName(labelName: String): Error? {
if (labelName.count() > labelNameMaxLength) {
return Error.LabelNameTooLong
}
return null
}
fun createNewSavedItemLabelWithTemp(labelName: String, hexColorValue: String): SavedItemLabel { fun createNewSavedItemLabelWithTemp(labelName: String, hexColorValue: String): SavedItemLabel {
val tempId = UUID.randomUUID().toString() val tempId = UUID.randomUUID().toString()

View File

@ -103,6 +103,7 @@
<string name="label_selection_sheet_action_search">Search</string> <string name="label_selection_sheet_action_search">Search</string>
<string name="label_selection_sheet_action_save">Save</string> <string name="label_selection_sheet_action_save">Save</string>
<string name="label_selection_sheet_text_create">Create a new label named \"%1$s\"</string> <string name="label_selection_sheet_text_create">Create a new label named \"%1$s\"</string>
<string name="label_selection_sheet_label_too_long_error_msg">The name provided is too long (must be less or equal than %1$d characters)</string>
<!-- LibraryFilterBar --> <!-- LibraryFilterBar -->
<string name="library_filter_bar_label_labels">Labels</string> <string name="library_filter_bar_label_labels">Labels</string>