Merge pull request #2920 from remychantenay/android-label-name-length-validation
Android: Add label name length validation upon creation
This commit is contained in:
@ -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,20 +342,35 @@ 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 labelName = filterTextValue.text.trim()
|
||||||
|
when(labelsViewModel.validateLabelName(labelName)) {
|
||||||
|
LabelsViewModel.Error.LabelNameTooLong -> {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(R.string.label_selection_sheet_label_too_long_error_msg,
|
||||||
|
labelsViewModel.labelNameMaxLength),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
null -> {
|
||||||
val label = findOrCreateLabel(
|
val label = findOrCreateLabel(
|
||||||
labelsViewModel = labelsViewModel,
|
labelsViewModel = labelsViewModel,
|
||||||
labels = labels,
|
labels = labels,
|
||||||
name = filterTextValue
|
name = labelName
|
||||||
)
|
)
|
||||||
|
|
||||||
state.addChip(LabelChipView(label))
|
state.addChip(LabelChipView(label))
|
||||||
filterTextValue = TextFieldValue()
|
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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user