splitwise / TokenAutoComplete

Gmail style MultiAutoCompleteTextView for Android
Apache License 2.0
1.3k stars 383 forks source link

If TokenClickStyle.Delete, backspacing a token does not remove object, but removes it from view #147

Closed shanempope closed 9 years ago

shanempope commented 9 years ago

If TokenClickStyle.Delete, backspacing a token does not remove token from Objects, but removes it from view.

mgod commented 9 years ago

If you remove a token, the object/span is not removed until the next view update cycle. Is it possible you are removing a token and immediately checking instead of waiting until after the view updates?

shanempope commented 9 years ago

Nope. I checked in the debugger after adding another token back to it. https://github.com/splitwise/TokenAutoComplete/blob/master/library/src/main/java/com/tokenautocomplete/TokenCompleteTextView.java#L483

I think this .isSelectable() is the problem but it uses .isSelected below to figure out which to delete so I'm not really sure.

    private boolean deleteSelectedObject(boolean handled) {
        if (tokenClickStyle != null && tokenClickStyle.isSelectable()) {
            Editable text = getText();
            if (text == null) return handled;

            TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
            for (TokenImageSpan span: spans) {
                if (span.view.isSelected()) {
                    removeSpan(span);
                    handled = true;
                    break;
                }
            }
        }
        return handled;
    }
shanempope commented 9 years ago

It doesn't work on my phone for .Select either though. I'm looking into it more. I'll let you know what I find. I'm trying other devices now.

mgod commented 9 years ago

Nothing is supposed to get removed in deleteSelectedObject unless you have an object selected. If you're just deleting text, the code uses a different path to remove the object. Can you reproduce this issue in the demo app?

mgod commented 9 years ago

Namely in https://github.com/splitwise/TokenAutoComplete/blob/master/library/src/main/java/com/tokenautocomplete/TokenCompleteTextView.java#L1137

shanempope commented 9 years ago

Thanks for your help. I will try to reproduce it in the demo app. The issue is I'm writing a binding for your library for Xamarin so it's harder to debug the actual java code. I'll let you know what I find. Everything else works great though. Just the backspace not removing objects. I'll figure it out. Thanks.

shanempope commented 9 years ago

In case you care I've posted the xamarin binding here: https://github.com/shanempope/TokenAutoCompleteXamarinBinding I didn't include the jar itself. I'll update this issue when I find the root cause of the backspace->delete not working. Thanks again, shane

mgod commented 9 years ago

Awesome! One other thing worth knowing - I had to do some work to get the textWatcher to stick around correctly, and it's possible the Tamarin UI bindings are interfering with the textWatcher in some way.

shanempope commented 9 years ago

Finally found the issue. The same thing happens (span watcher just goes away) when I set Text manually from the C# side (I'm sure it happens on android too if you use it this way). I was manually adding tokens (addObject) and removing user typed text by parsing the getText span and removing anything after the last Token. When I stopped setting Text it went away. Just have to figure out a better way to remove text when adding objects. Probably just going to write my own function that clears everything but the image token spans when I addObject

Thanks again for your help, shane

shanempope commented 9 years ago

Here's the only code I ended up needing to write on the java side if you're curious. Just replaces the completion text with empty string. Currently calling it before I call addObject because I'm using my own listview to fill the tokenizer. Take care, shane

    public void clearCompletionText() {
        Editable text = getText();
        if (text == null) return;

        int end = getSelectionEnd();
        if (end < 0 || tokenizer == null) {
            return;
        }

        int start = tokenizer.findTokenStart(text, end);
        if (start < prefix.length()) {
            start = prefix.length();
        }
        text.replace(start,end, "");
    }
mgod commented 9 years ago

I'm curious – why do you need to call setText? I've also just pushed an update that includes protected methods for addListeners and removeListeners that might make this a little simpler.

shanempope commented 9 years ago

So I have an iOS and android app, with a listbox of suggestions below the tokenizer that way both apps match visually. When suggestions are typed in, I update the listbox below and when the user selects one of them I AddToken() it. At that point I need to clear the text the user typed in and replace it with the token.

I hope that made since.

Edit: To clarify I don't call setText anymore. I use that above code to solve the same problem.

mgod commented 9 years ago

Thanks for the follow-up! That's how we originally did autocomplete on our iPhone app, but we never brought the same style to Android. I'll go ahead and mark this as closed.