I want to compare two String objects coming out of two different lists and no matter if i use
equals(), contentEquals() or ==, it is always false.
Has it something to do with how the strings of the first list are put into it?
edit: it's getting weirder look at the log outcome in this picture:
DictWord.dictWords.forEach {
Log.i("testen", "it is: $it and equals 'black'? - ${it.equals("black")}")
Log.i("testen", "it is: $it and equals $newWord - ${it.equals(newWord)}")
Log.i("testen", "it is: $it and equals $newWord - ${it.contentEquals("black")}")
Log.i("testen", "it is: $it and == $newWord - ${it == newWord}")
Log.i("black", "it is: 'black' and equals $newWord - ${"black" == newWord}")
... subStrainsAdapter.addHeaderAndSubmitList(null)
var textList = mutableListOf<String>()
var movingText = ""
thoughtContent.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(
s: CharSequence,
start: Int, count: Int, after: Int) {}
override fun onTextChanged(
s: CharSequence,
start: Int, before: Int, count: Int)
{movingText += s.last()}
})
//SUBSTRAIN INPUT - goes to onSubStrainEditEnd above when ENTER hit
thoughtContent.setOnKeyListener(object : View.OnKeyListener {
#RequiresApi(Build.VERSION_CODES.Q)
override fun onKey(v: View?, key: Int, event: KeyEvent): Boolean {
return if (event.action == KeyEvent.ACTION_DOWN && key == KeyEvent.KEYCODE_SPACE) {
textList.add(movingText)
movingText = ""
false } else false
}})
Output log for the above code:
edit
if(b == false) {
thoughtsViewModel.editThought(thoughtContent.text.toString(), thoughtItem.id)
val testList = thoughtContent.text.toString().split(" ")
textList.forEach {
(Log.i("testen", "it is $it"))
if(DictWord.dictWords.keys.contains(it)) {Log.i("testen", "TRIGGGEERRRED and its $it")}
}
testList.forEach {
(Log.i("testen", "it is $it"))
if(DictWord.dictWords.keys.contains(it)) {Log.i("testen", "test list TRIGGGEERRRED and its $it")}
}
newWord is not trimmed it seems. From your log, it has an extra space before it.
These two lines in the log correspond to this code respectively:
Log.i("testen", "it is: $it and equals 'black'? - ${it.equals("black")}")
Log.i("testen", "it is: $it and equals $newWord - ${it.equals(newWord)}")
You can see that you didn't add two spaces in the second line but still your black has an extra space before
You should either correct your list or do newWord.trim() which will remove all leading and trailing whitespaces
Otherwise you should always use String.equals(otherString: String) or s1 == s2 (they are the same in kotlin)
Your example is badly formatted and I believe missing some code, but as #snachmsm pointed out, contentEquals is a method on arrays in Kotlin. You should use equals() for Strings instead (though == is the preferred way in Kotlin)
Related
i have 1 edittext maxLength = 30, but i can only type 6 character emoji dog => 1 emoji dog = 6 regular character. So please help me type 30 emoji dog. Thanks everyone.
[enter image description here][1]
When someone types an emoji, you can call .length on that emoji, then increase your max character count by that amount. (You would have to remember your original character count and use that on your UI if you wanted to hide the magic).
i.e. when someone types a "dog" then you increase your max count from 30 to 35. (1 has been used and a dog usually counts for 6)
Ref:
https://twitter.com/riggaroo/status/1148278279713017858
https://developer.android.com/reference/java/text/BreakIterator
https://lemire.me/blog/2018/06/15/emojis-java-and-strings/
https://developer.android.com/reference/kotlin/androidx/emoji/text/EmojiCompat
editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
oldTextString = charSequence.toString()
}
override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {}
override fun afterTextChanged(editable: Editable) {
var newTextString = editable.toString()
if (!oldTextString.equals(newTextString)) {
if (Character.codePointCount(
newTextString,
0,
newTextString.length
) > maxCharactersAllowed
) {
newTextString = oldTextString
}
editText.setText(newTextString)
editText.setSelection(newTextString.length)
}
}
})
I have an edittext. I've added a text watcher to edittext. I listen text changes. İf the word user typing starts with #, I show user suggestions (like when you type # and twitter show you suggestions)
If text starts with a normal letter everything works fine.
For example:
hello #random_user how are you
#this also works because there is an empty space before '#'
This examples works.
However if text starts with special characters Text Watcher shows incorrect values
For example:
#hello_user
#someHashtag
text watcher return false value. I'm using onTextChanged method to track text
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//Text in edittext is '#user' but I get:
//start = 0, before = 0 and count = 1;
//edittext.getSelectionStart() also returns 1 but cursor is at the end of the line.
//edittext.getText().toString().length() also returns 1 but #user is 5 length.
}
How can I solve this?
Edit: edittext.postdesc.getText().toString() only returns first char. For example if my text is '#user', getText method only returns #
You can try this workaround:
class TextWatcherExtended(
private val onTextChanged: (text: CharSequence?, start: Int, before: Int, count: Int) -> Unit
) : TextWatcher {
private var before = 0
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(text: CharSequence?, start: Int, count: Int, after: Int) {
this.before = text?.length ?: 0
}
override fun onTextChanged(text: CharSequence?, start: Int, before: Int, count: Int) {
onTextChanged.invoke(text, start, this.before, count)
}
}
I am filtering most characters and numbers out in this use case. When I type several 'filtered' characters, let's say 555, the source of each following filter event still has those 5's in it, even though they have been filtered out. This means that after typing 555, and having nothing appear in the EditText, I have to backspace 3 times before I actually start backspacing what is in the EditText. Not only that, but my 'invalid input' toast fires on every backspace, because my source still has the 5's in it.
So, if I type abc123abc, my field shows abcabc, but logging my source shows abc123abc and I throw invalid toasts all over the place.
The superclass for the filter has nothing except a protected method to show the toast, and is used on the filters that work, as well.
InputFilter
class TextInputFilter constructor(
private val letters: Boolean,
private val numbers: Boolean,
private val whitespace: Boolean,
private val extraCharacters: Array<Char>,
context: Context?
) : ToastInputFilter(context) {
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
var valid = true
val builder = StringBuilder()
source.forEach { c ->
if (c.isValid()) {
builder.append(c)
} else {
valid = false
}
}
return if (valid) {
null
} else {
showInputToast(R.string.textInputInvalid)
if (source is Spanned) {
val spannable = SpannableString(builder)
TextUtils.copySpansFrom(source, start, builder.length, null, spannable, 0)
spannable
} else {
builder
}
}
}
private fun Char.isValid(): Boolean {
return when {
isLetter() -> letters
isDigit() -> numbers
isWhitespace() -> whitespace
else -> this in extraCharacters
}
}
}
Instantiation with args
titleEditText.filters = arrayOf(
TextInputFilter(letters = true, numbers = false, whitespace = true, extraCharacters = chars, context = context)
)
The extra chars that I'm allowing
chars = safeGetString(R.string.alphaExtraChars).toCharArray().toTypedArray()
<string name="alphaExtraChars">\'.-</string>
I've tried everything I can think of, and I have other filters that work fine on number input, because the source does not come in as Spannable, and only deals with the new piece of input, not the entire field.
Edit after using start|end arguments, this happens:
A -> Log: A | Display: A
b -> Log: Ab | Display: Ab
c -> Log: Abc | Display: Abc
1 -> Log: Abc1 | Display: Abc + TOAST
2 -> Log: Abc12 | Display: Abc + TOAST
3 -> Log: Abc123 | Display: Abc + TOAST
Backspace -> Log: Ab | Display: Ab
Good.
But, when I keep typing valid characters after invalid characters:
A -> Log: A | Display: A
1 -> Log: A1 | Display: A + TOAST
a -> Log: A1a | Display: Aa + TOAST
1 -> Log: A1a1 | Display: Aa + TOAST
a -> Log: A1a1a | Display: Aaa + TOAST
Backspace -> Log: A1a1 | Display: Aa + TOAST
Backspace -> Log: A | Display: A
I suggest this to concisely take the source delimiters into account:
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
val builder = StringBuilder()
for (c in source.subSequence(start, end) {
if (c.isValid()) builder.append(c)
}
return if (builder.length == end - start) {
null
} else {
showInputToast(R.string.textInputInvalid)
//...
}
}
You might consider simplifying the whole thing to reject any incoming block of text if it contains any invalid characters. Presumably, you will get either one new character at a time, or the user is pasting a block of text. Do you really want to filter pieces of a block of text that contains invalid characters? In many cases, this would be unexpected behavior.
So if it's acceptable behavior to do this, your filter simplifies down to:
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int): CharSequence? {
for (i in start until end) {
if (!source.charAt(i).isValid()) {
showInputToast(R.string.textInputInvalid)
return ""
}
}
return null
}
I'm trying to make a number look like this
932-874838/9
I did this with my EditText to append the - and / after some spaces
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(text: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onValueChange(s.toString())
}
})
}
private fun onValueChange(value: String) {
mNumberTxtView.text = value
if (value.length == 3) {
mNumberTxtView.append("-")
}
if (value.length == 10) {
mNumberTxtView.append("/")
}
}
When I'm typing like
932
it automatically appends the - , and that works, but after it appends the - and if I type another number it replaces the - with that number instead of continuing, so it becomes 932- at first but when trying to put another number,
9328
it gets replaced like that removing the appended -
I think the problem is inside the onValueChange() method
onValueChange should be like this:
var test: StringBuilder = StringBuilder()
var lastValue: String = ""
fun onValueChange(value: String) {
if(lastValue.length > value.length) {
test.deleteCharAt(test.lastIndex)
if(test.length == 3 || test.length == 10) {
test.deleteCharAt(test.lastIndex)
}
} else {
test.append(value.last())
if (test.length == 3) {
test.append("-")
} else if (test.length == 10) {
test.append("/")
}
}
lastValue = value
textView.text = test
}
Try this, instead.
private fun onValueChange(value: String) {
if (value.length == 3) {
mNumberTxtView.text = "${value}_"
} else if (value.length == 10) {
mNumberTxtView.text = "${value}/"
}
}
Let me know if this works.
(The curly brackets around "value" in the strings may not be necessary. I'm still getting used to Kotlin's way of handling string concatenation.)
Edited to remove redundant and potentially loop-causing part.
You should not change text in beforeTextChanged and afterTextChanged to prevent re-call of those methods by TextWatcher. Make changes in afterTextChanged.
But be careful not to get yourself into an infinite loop, because any changes you make will cause this method to be called again recursively.
So set invoke of onValueChanged into afterTextChanged method
with removal of mNumberTxtView.text = value
So I'm using a text watcher to show the user suggestions for tags.
Currently I am using a dummy list of tags. When the user starts typing, the code should create a another list of tags that is just the objects of the first list filtered based on whether they contain the character sequence the user is currently typing.
It works great for the first character, but as the user keeps typing the list doesn't change anymore.
This is my code:
val tags = listOf(
"John Smith",
"Kate Eckhart",
"Emily Sun",
"Frodo Baggins",
"Yanay Zabary",
"Sze Lok Ho",
"Jesse Albright",
"Shayna something",
"Makena Lawrence"
)
questionTagsInput.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val userInput = s.toString()
if (userInput == "") {
tagSuggestionRecycler.visibility = View.GONE
tagsFiltredAdapter.clear()
} else {
val relevantTags: List<String> = tags.filter { it.contains(userInput) }
for (t in relevantTags) {
tagSuggestionRecycler.visibility = View.VISIBLE
tagsFiltredAdapter.add(SingleTagSuggestion(t))
}
}
}
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
})
You Need to clear the tagsFiltredAdapter in each call of onTextChanged.
Currently, when typing the first character, your filtered list contains the right results, and when typing more characters, the list's size should decrease to match the new characters. Instead, you just adding items to the list.