Skip to content

Commit

Permalink
Merge remote-tracking branch 'st1hy/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Rafael Dominiquini committed Jun 27, 2016
2 parents 64f64f6 + f136a7e commit 80d2aef
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 39 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.android.tools.build:gradle:2.1.2'
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public boolean isSelectable() {
private TokenSpanWatcher spanWatcher;
private TokenTextWatcher textWatcher;
private ArrayList<T> objects;
private List<TokenCompleteTextView<T>.TokenImageSpan> hiddenSpans;
private List<TokenImageSpan<T>> hiddenSpans;
private TokenDeleteStyle deletionStyle = TokenDeleteStyle._Parent;
private TokenClickStyle tokenClickStyle = TokenClickStyle.None;
private CharSequence prefix = "";
Expand Down Expand Up @@ -138,7 +138,7 @@ private void init() {
if (initialized) return;

// Initialise variables
setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
setTokenizer(new CommaTokenizer());
objects = new ArrayList<>();
Editable text = getText();
assert null != text;
Expand Down Expand Up @@ -280,6 +280,7 @@ public boolean isTokenRemovable(T token) {
*
* @param p String with the hint
*/
@SuppressWarnings("unused")
public void setPrefix(CharSequence p) {
//Have to clear and set the actual text before saving the prefix to avoid the prefix filter
prefix = "";
Expand Down Expand Up @@ -435,7 +436,7 @@ public CharSequence getTextForAccessibility() {
}

//Replace token spans
TokenImageSpan[] tokens = text.getSpans(i, i, TokenImageSpan.class);
TokenImageSpan<T>[] tokens = getSpans(text, i, i);
if (tokens.length > 0) {
TokenImageSpan token = tokens[0];
description = description.append(tokenizer.terminateToken(token.getToken().toString()));
Expand Down Expand Up @@ -620,7 +621,7 @@ private boolean deleteSelectedObject(boolean handled) {
Editable text = getText();
if (text == null) return handled;

TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, 0, text.length());
for (TokenImageSpan span : spans) {
if (span.view.isSelected()) {
removeSpan(span);
Expand Down Expand Up @@ -656,7 +657,7 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
int offset = getOffsetForPosition(event.getX(), event.getY());

if (offset != -1) {
TokenImageSpan[] links = text.getSpans(offset, offset, TokenImageSpan.class);
TokenImageSpan<T>[] links = getSpans(text, offset, offset);

if (links.length > 0) {
links[0].onClick();
Expand Down Expand Up @@ -699,7 +700,7 @@ protected void onSelectionChanged(int selStart, int selEnd) {
Editable text = getText();
if (text != null) {
//Make sure if we are in a span, we select the spot 1 space after the span end
TokenImageSpan[] spans = text.getSpans(selStart, selEnd, TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, selStart, selEnd);
for (TokenImageSpan span : spans) {
int spanEnd = text.getSpanEnd(span);
if (selStart <= spanEnd && text.getSpanStart(span) < selStart) {
Expand Down Expand Up @@ -737,7 +738,7 @@ public void performCollapse(boolean hasFocus) {
if (text != null && lastLayout != null) {
// Display +x thingy if appropriate
int lastPosition = lastLayout.getLineVisibleEnd(0);
TokenImageSpan[] tokens = text.getSpans(0, lastPosition, TokenImageSpan.class);
TokenImageSpan<T>[] tokens = getSpans(text, 0, lastPosition);
int count = objects.size() - tokens.length;

// Make sure we don't add more than 1 CountSpan
Expand Down Expand Up @@ -771,8 +772,7 @@ public void performCollapse(boolean hasFocus) {
// Remove all spans behind the count span and hold them in the hiddenSpans List
// The generic type information is not captured in TokenImageSpan.class so we have
// to perform a cast for the returned spans to coerce them to the proper generic type.
hiddenSpans = new ArrayList<>(Arrays.asList(
(TokenImageSpan[]) text.getSpans(lastPosition + cs.text.length(), text.length(), TokenImageSpan.class)));
hiddenSpans = new ArrayList<>(Arrays.asList(getSpans(text, lastPosition + cs.text.length(), text.length())));
for (TokenImageSpan span : hiddenSpans) {
removeSpan(span);
}
Expand All @@ -788,7 +788,7 @@ public void performCollapse(boolean hasFocus) {
}

// Restore the spans we have hidden
for (TokenImageSpan span : hiddenSpans) {
for (TokenImageSpan<T> span : hiddenSpans) {
insertSpan(span);
}
hiddenSpans.clear();
Expand Down Expand Up @@ -817,6 +817,11 @@ public void run() {
focusChanging = false;
}

@SuppressWarnings("unchecked")
private TokenImageSpan<T>[] getSpans(Editable text, int start, int length) {
return text.getSpans(start, length, TokenImageSpan.class);
}

@Override
public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
super.onFocusChanged(hasFocus, direction, previous);
Expand Down Expand Up @@ -856,12 +861,12 @@ private SpannableStringBuilder buildSpannableForText(CharSequence text) {
return new SpannableStringBuilder(String.valueOf(sentinel) + tokenizer.terminateToken(text));
}

protected TokenImageSpan buildSpanForObject(T obj) {
protected TokenImageSpan<T> buildSpanForObject(T obj) {
if (obj == null) {
return null;
}
View tokenView = getViewForObject(obj);
return new TokenImageSpan(tokenView, obj, (int) maxTextWidth());
return new TokenImageSpan<>(tokenView, obj, (int) maxTextWidth(), this);
}

@Override
Expand All @@ -872,7 +877,7 @@ protected void replaceText(CharSequence text) {
if (selectedObject == null || selectedObject.toString() == null || selectedObject.toString().equals("")) return;

SpannableStringBuilder ssb = buildSpannableForText(text);
TokenImageSpan tokenSpan = buildSpanForObject(selectedObject);
TokenImageSpan<T> tokenSpan = buildSpanForObject(selectedObject);

Editable editable = getText();
int cursorPosition = getSelectionEnd();
Expand Down Expand Up @@ -944,6 +949,7 @@ public void addObject(T object) {
*
* @param object object to remove, may be null or not in the view
*/
@SuppressWarnings("unused")
public void removeObject(final T object) {
post(new Runnable() {
@Override
Expand All @@ -969,7 +975,7 @@ public void run() {
updateCountSpan();

// If the object is currently visible, remove it
TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, 0, text.length());
for (TokenImageSpan span : spans) {
if (span.getToken().equals(object)) {
removeSpan(span);
Expand Down Expand Up @@ -1030,7 +1036,7 @@ private void removeSpan(TokenImageSpan span) {
*/
private void insertSpan(T object, CharSequence sourceText) {
SpannableStringBuilder ssb = buildSpannableForText(sourceText);
TokenImageSpan tokenSpan = buildSpanForObject(object);
TokenImageSpan<T> tokenSpan = buildSpanForObject(object);

Editable editable = getText();
if (editable == null) return;
Expand Down Expand Up @@ -1082,7 +1088,7 @@ private void insertSpan(T object) {
insertSpan(object, spanString);
}

private void insertSpan(TokenImageSpan span) {
private void insertSpan(TokenImageSpan<T> span) {
insertSpan(span.getToken());
}

Expand All @@ -1102,7 +1108,7 @@ public void run() {
if (text == null) return;

// Get all spans in the EditText and remove them
TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, 0, text.length());
for (TokenImageSpan span : spans) {
removeSpan(span);

Expand Down Expand Up @@ -1172,55 +1178,57 @@ private void clearSelections() {
Editable text = getText();
if (text == null) return;

TokenImageSpan[] tokens = text.getSpans(0, text.length(), TokenImageSpan.class);
TokenImageSpan<T>[] tokens = getSpans(text, 0, text.length());
for (TokenImageSpan token : tokens) {
token.view.setSelected(false);
}
invalidate();
}

protected class TokenImageSpan extends ViewSpan implements NoCopySpan {
protected static class TokenImageSpan<T> extends ViewSpan implements NoCopySpan {
private T token;
final TokenCompleteTextView<T> parent;

public TokenImageSpan(View d, T token, int maxWidth) {
public TokenImageSpan(View d, T token, int maxWidth, TokenCompleteTextView<T> parent) {
super(d, maxWidth);
this.token = token;
this.parent = parent;
}

public T getToken() {
return this.token;
}

public void onClick() {
Editable text = getText();
Editable text = parent.getText();
if (text == null) return;

switch (tokenClickStyle) {
switch (parent.tokenClickStyle) {
case Select:
case SelectDeselect:

if (!view.isSelected()) {
clearSelections();
parent.clearSelections();
view.setSelected(true);
break;
}

if (tokenClickStyle == TokenClickStyle.SelectDeselect || !isTokenRemovable(token)) {
if (parent.tokenClickStyle == TokenClickStyle.SelectDeselect || !parent.isTokenRemovable(token)) {
view.setSelected(false);
invalidate();
parent.invalidate();
break;
}
//If the view is already selected, we want to delete it
case Delete:
if (isTokenRemovable(token)) {
removeSpan(this);
if (parent.isTokenRemovable(token)) {
parent.removeSpan(this);
}
break;
case None:
default:
if (getSelectionStart() != text.getSpanEnd(this) + 1) {
if (parent.getSelectionStart() != text.getSpanEnd(this) + 1) {
//Make sure the selection is not in the middle of the span
setSelection(text.getSpanEnd(this) + 1);
parent.setSelection(text.getSpanEnd(this) + 1);
}
}
}
Expand All @@ -1237,8 +1245,8 @@ private class TokenSpanWatcher implements SpanWatcher {
@SuppressWarnings("unchecked cast")
@Override
public void onSpanAdded(Spannable text, Object what, int start, int end) {
if (what instanceof TokenCompleteTextView<?>.TokenImageSpan && !savingState && !focusChanging) {
TokenImageSpan token = (TokenImageSpan) what;
if (what instanceof TokenImageSpan && !savingState && !focusChanging) {
TokenImageSpan<T> token = (TokenImageSpan) what;
objects.add(token.getToken());

if (listener != null)
Expand All @@ -1249,8 +1257,8 @@ public void onSpanAdded(Spannable text, Object what, int start, int end) {
@SuppressWarnings("unchecked cast")
@Override
public void onSpanRemoved(Spannable text, Object what, int start, int end) {
if (what instanceof TokenCompleteTextView<?>.TokenImageSpan && !savingState && !focusChanging) {
TokenImageSpan token = (TokenImageSpan) what;
if (what instanceof TokenImageSpan && !savingState && !focusChanging) {
TokenImageSpan<T> token = (TokenImageSpan) what;
if (objects.contains(token.getToken())) {
objects.remove(token.getToken());
}
Expand Down Expand Up @@ -1288,7 +1296,7 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
start -= 1;
}

TokenImageSpan[] spans = text.getSpans(start, end, TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, start, end);

//NOTE: I'm not completely sure this won't cause problems if we get stuck in a text changed loop
//but it appears to work fine. Spans will stop getting removed if this breaks.
Expand Down Expand Up @@ -1481,8 +1489,8 @@ public String toString() {
}

@SuppressWarnings("hiding")
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public static final Creator<SavedState> CREATOR
= new Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
Expand All @@ -1509,11 +1517,11 @@ public boolean canDeleteSelection(int beforeLength) {
int startSelection = beforeLength == 1 ? getSelectionStart() : endSelection - beforeLength;

Editable text = getText();
TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
TokenImageSpan<T>[] spans = getSpans(text, 0, text.length());

// Iterate over all tokens and allow the deletion
// if there are no tokens not removable in the selection
for (TokenImageSpan span : spans) {
for (TokenImageSpan<T> span : spans) {
int startTokenSelection = text.getSpanStart(span);
int endTokenSelection = text.getSpanEnd(span);

Expand Down

0 comments on commit 80d2aef

Please sign in to comment.