Display tag blocks for caldav and google tasks

pull/685/merge
Alex Baker 8 years ago
parent fd2437cff3
commit d03698cd2e

@ -79,6 +79,8 @@ public class TaskListFragment extends InjectingFragment
implements SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener { implements SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener {
public static final String TAGS_METADATA_JOIN = "for_tags"; // $NON-NLS-1$ public static final String TAGS_METADATA_JOIN = "for_tags"; // $NON-NLS-1$
public static final String GTASK_METADATA_JOIN = "for_gtask"; // $NON-NLS-1$
public static final String CALDAV_METADATA_JOIN = "for_caldav"; // $NON-NLS-1$
public static final String FILE_METADATA_JOIN = "for_actions"; // $NON-NLS-1$ public static final String FILE_METADATA_JOIN = "for_actions"; // $NON-NLS-1$
private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234; private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
private static final String EXTRA_FILTER = "extra_filter"; private static final String EXTRA_FILTER = "extra_filter";

@ -35,6 +35,13 @@ public class TaskAdapter {
+ ".tag_uid, '')" + ".tag_uid, '')"
+ ", ',')") + ", ',')")
.as("tags"); .as("tags");
private static final StringProperty GTASK =
new StringProperty(null, "nullif(" + TaskListFragment.GTASK_METADATA_JOIN + ".list_id, '')")
.as("googletask");
private static final StringProperty CALDAV =
new StringProperty(null, "nullif(" + TaskListFragment.CALDAV_METADATA_JOIN + ".calendar, '')")
.as("caldav");
private static final LongProperty FILE_ID_PROPERTY = private static final LongProperty FILE_ID_PROPERTY =
TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId");
public static final Property<?>[] PROPERTIES = public static final Property<?>[] PROPERTIES =
@ -42,6 +49,8 @@ public class TaskAdapter {
Task.PROPERTIES, Task.PROPERTIES,
new Property<?>[] { new Property<?>[] {
TAGS, // Concatenated list of tags TAGS, // Concatenated list of tags
GTASK,
CALDAV,
FILE_ID_PROPERTY // File id FILE_ID_PROPERTY // File id
}, },
Property.class); Property.class);

@ -55,7 +55,7 @@ public class CaldavFilter extends Filter {
Criterion.and( Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(), TaskDao.TaskCriteria.activeAndVisible(),
Field.field("caldav_tasks.deleted").eq(0), Field.field("caldav_tasks.deleted").eq(0),
Field.field("calendar").eq(caldavCalendar.getUuid()))); Field.field("caldav_tasks.calendar").eq(caldavCalendar.getUuid())));
} }
private static Map<String, Object> getValuesForNewTask(CaldavCalendar caldavCalendar) { private static Map<String, Object> getValuesForNewTask(CaldavCalendar caldavCalendar) {

@ -64,7 +64,7 @@ public class GtasksFilter extends Filter {
Criterion.and( Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(), TaskDao.TaskCriteria.activeAndVisible(),
Field.field("google_tasks.deleted").eq(0), Field.field("google_tasks.deleted").eq(0),
Field.field("list_id").eq(list.getRemoteId()))); Field.field("google_tasks.list_id").eq(list.getRemoteId())));
} }
private static Map<String, Object> getValuesForNewTasks(GoogleTaskList list) { private static Map<String, Object> getValuesForNewTasks(GoogleTaskList list) {

@ -153,6 +153,7 @@ public class Task implements Parcelable {
/** Name of Task */ /** Name of Task */
@ColumnInfo(name = "title") @ColumnInfo(name = "title")
public String title = ""; public String title = "";
@ColumnInfo(name = "importance") @ColumnInfo(name = "importance")
public Integer priority = Priority.NONE; public Integer priority = Priority.NONE;
/** Unixtime Task is due, 0 if not set */ /** Unixtime Task is due, 0 if not set */
@ -220,6 +221,8 @@ public class Task implements Parcelable {
@Ignore private transient int indent; @Ignore private transient int indent;
@Ignore private transient String tags; @Ignore private transient String tags;
@Ignore private transient String googleTaskList;
@Ignore private transient String caldav;
@Ignore private transient boolean hasFiles; @Ignore private transient boolean hasFiles;
@Ignore private transient HashMap<String, Object> transitoryData = null; @Ignore private transient HashMap<String, Object> transitoryData = null;
@ -250,6 +253,8 @@ public class Task implements Parcelable {
final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId"); final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId");
final int _cursorIndexOfIndent = _cursor.getColumnIndex("indent"); final int _cursorIndexOfIndent = _cursor.getColumnIndex("indent");
final int _cursorIndexOfTags = _cursor.getColumnIndex("tags"); final int _cursorIndexOfTags = _cursor.getColumnIndex("tags");
final int _cursorIndexOfGoogleTasks = _cursor.getColumnIndex("googletask");
final int _cursorIndexOfCaldav = _cursor.getColumnIndex("caldav");
final int _cursorIndexOfFileId = _cursor.getColumnIndex("fileId"); final int _cursorIndexOfFileId = _cursor.getColumnIndex("fileId");
if (_cursor.isNull(_cursorIndexOfId)) { if (_cursor.isNull(_cursorIndexOfId)) {
id = null; id = null;
@ -342,6 +347,12 @@ public class Task implements Parcelable {
if (_cursorIndexOfTags >= 0) { if (_cursorIndexOfTags >= 0) {
tags = _cursor.getString(_cursorIndexOfTags); tags = _cursor.getString(_cursorIndexOfTags);
} }
if (_cursorIndexOfGoogleTasks >= 0) {
googleTaskList = _cursor.getString(_cursorIndexOfGoogleTasks);
}
if (_cursorIndexOfCaldav >= 0) {
caldav = _cursor.getString(_cursorIndexOfCaldav);
}
if (_cursorIndexOfFileId >= 0) { if (_cursorIndexOfFileId >= 0) {
hasFiles = _cursor.getInt(_cursorIndexOfFileId) > 0; hasFiles = _cursor.getInt(_cursorIndexOfFileId) > 0;
} }
@ -1061,10 +1072,6 @@ public class Task implements Parcelable {
return tags; return tags;
} }
public boolean hasFiles() {
return hasFiles;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -1076,6 +1083,9 @@ public class Task implements Parcelable {
Task task = (Task) o; Task task = (Task) o;
if (indent != task.indent) {
return false;
}
if (hasFiles != task.hasFiles) { if (hasFiles != task.hasFiles) {
return false; return false;
} }
@ -1152,7 +1162,15 @@ public class Task implements Parcelable {
if (remoteId != null ? !remoteId.equals(task.remoteId) : task.remoteId != null) { if (remoteId != null ? !remoteId.equals(task.remoteId) : task.remoteId != null) {
return false; return false;
} }
return tags != null ? tags.equals(task.tags) : task.tags == null; if (tags != null ? !tags.equals(task.tags) : task.tags != null) {
return false;
}
if (googleTaskList != null
? !googleTaskList.equals(task.googleTaskList)
: task.googleTaskList != null) {
return false;
}
return caldav != null ? caldav.equals(task.caldav) : task.caldav == null;
} }
@Override @Override
@ -1180,7 +1198,21 @@ public class Task implements Parcelable {
result = 31 * result + (remoteId != null ? remoteId.hashCode() : 0); result = 31 * result + (remoteId != null ? remoteId.hashCode() : 0);
result = 31 * result + indent; result = 31 * result + indent;
result = 31 * result + (tags != null ? tags.hashCode() : 0); result = 31 * result + (tags != null ? tags.hashCode() : 0);
result = 31 * result + (googleTaskList != null ? googleTaskList.hashCode() : 0);
result = 31 * result + (caldav != null ? caldav.hashCode() : 0);
result = 31 * result + (hasFiles ? 1 : 0); result = 31 * result + (hasFiles ? 1 : 0);
return result; return result;
} }
public String getGoogleTaskList() {
return googleTaskList;
}
public String getCaldav() {
return caldav;
}
public boolean hasFiles() {
return hasFiles;
}
} }

@ -12,13 +12,20 @@ import android.text.style.ForegroundColorSpan;
import android.util.TypedValue; import android.util.TypedValue;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TagService;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.R; import org.tasks.R;
import org.tasks.data.CaldavAccount;
import org.tasks.data.CaldavCalendar;
import org.tasks.data.CaldavDao;
import org.tasks.data.GoogleTaskList;
import org.tasks.data.GoogleTaskListDao;
import org.tasks.data.TagData; import org.tasks.data.TagData;
import org.tasks.injection.ForApplication; import org.tasks.injection.ForApplication;
import org.tasks.themes.ThemeCache; import org.tasks.themes.ThemeCache;
@ -28,25 +35,30 @@ public class TagFormatter {
private static final char SPACE = '\u0020'; private static final char SPACE = '\u0020';
private static final char HAIR_SPACE = '\u200a'; private static final char HAIR_SPACE = '\u200a';
private static final int MAX_TAGS = 4;
private final Map<String, TagData> tagMap = new HashMap<>(); private final Map<String, ColoredString> tagMap = new HashMap<>();
private final Map<String, ColoredString> googleTaskLists = new HashMap<>();
private final Map<String, ColoredString> caldavCalendars = new HashMap<>();
private final TagService tagService; private final TagService tagService;
private final ThemeCache themeCache; private final ThemeCache themeCache;
private final GoogleTaskListDao googleTaskListDao;
private final CaldavDao caldavDao;
private final float tagCharacters; private final float tagCharacters;
private final Function<String, TagData> uuidToTag = this::getTag; private final Function<String, ColoredString> uuidToTag = this::getTag;
private final Ordering<TagData> orderByName = private final Ordering<ColoredString> orderByName =
new Ordering<TagData>() { new Ordering<ColoredString>() {
@Override @Override
public int compare(TagData left, TagData right) { public int compare(ColoredString left, ColoredString right) {
return left.getName().compareTo(right.getName()); return left.name.compareTo(right.name);
} }
}; };
private final Ordering<TagData> orderByLength = private final Ordering<ColoredString> orderByLength =
new Ordering<TagData>() { new Ordering<ColoredString>() {
@Override @Override
public int compare(TagData left, TagData right) { public int compare(ColoredString left, ColoredString right) {
int leftLength = left.getName().length(); int leftLength = left.name.length();
int rightLength = right.getName().length(); int rightLength = right.name.length();
if (leftLength < rightLength) { if (leftLength < rightLength) {
return -1; return -1;
} else if (rightLength < leftLength) { } else if (rightLength < leftLength) {
@ -59,31 +71,71 @@ public class TagFormatter {
@Inject @Inject
public TagFormatter( public TagFormatter(
@ForApplication Context context, TagService tagService, ThemeCache themeCache) { @ForApplication Context context,
TagService tagService,
ThemeCache themeCache,
GoogleTaskListDao googleTaskListDao,
CaldavDao caldavDao) {
this.tagService = tagService; this.tagService = tagService;
this.themeCache = themeCache; this.themeCache = themeCache;
this.googleTaskListDao = googleTaskListDao;
this.caldavDao = caldavDao;
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
context.getResources().getValue(R.dimen.tag_characters, typedValue, true); context.getResources().getValue(R.dimen.tag_characters, typedValue, true);
tagCharacters = typedValue.getFloat(); tagCharacters = typedValue.getFloat();
for (TagData tagData : tagService.getTagList()) { for (TagData tagData : tagService.getTagList()) {
tagMap.put(tagData.getRemoteId(), tagData); tagMap.put(tagData.getRemoteId(), new ColoredString(tagData));
} }
for (CaldavCalendar calendar : caldavDao.getCalendars()) {
caldavCalendars.put(calendar.getUuid(), new ColoredString(calendar));
}
for (GoogleTaskList list : googleTaskListDao.getAllLists()) {
googleTaskLists.put(list.getRemoteId(), new ColoredString(list));
}
}
private class ColoredString {
final String name;
final int color;
ColoredString(TagData tagData) {
name = tagData.getName();
color = tagData.getColor();
}
ColoredString(GoogleTaskList googleTaskList) {
name = googleTaskList.getTitle();
color = googleTaskList.getColor();
} }
CharSequence getTagString(List<String> tagUuids) { ColoredString(CaldavCalendar caldavCalendar) {
Iterable<TagData> t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); name = caldavCalendar.getName();
List<TagData> firstFourByName = orderByName.leastOf(t, 4); color = caldavCalendar.getColor();
int numTags = firstFourByName.size(); }
}
CharSequence getTagString(String caldav, String googleTask, List<String> tagUuids) {
List<ColoredString> strings = new ArrayList<>();
if (!Strings.isNullOrEmpty(googleTask)) {
strings.add(getGoogleTaskList(googleTask));
} else if (!Strings.isNullOrEmpty(caldav)) {
strings.add(getCaldavCalendar(caldav));
}
Iterable<ColoredString> tags = filter(transform(tagUuids, uuidToTag), Predicates.notNull());
strings.addAll(0, orderByName.leastOf(tags, MAX_TAGS - strings.size()));
int numTags = strings.size();
if (numTags == 0) { if (numTags == 0) {
return null; return null;
} }
List<TagData> firstFourByNameLength = orderByLength.sortedCopy(firstFourByName); List<ColoredString> firstFourByNameLength = orderByLength.sortedCopy(strings);
float maxLength = tagCharacters / numTags; float maxLength = tagCharacters / numTags;
for (int i = 0; i < numTags - 1; i++) { for (int i = 0; i < numTags - 1; i++) {
TagData tagData = firstFourByNameLength.get(i); ColoredString tagData = firstFourByNameLength.get(i);
String name = tagData.getName(); String name = tagData.name;
if (name.length() >= maxLength) { if (name.length() >= maxLength) {
break; break;
} }
@ -92,7 +144,7 @@ public class TagFormatter {
float additional = excess / beneficiaries; float additional = excess / beneficiaries;
maxLength += additional; maxLength += additional;
} }
List<SpannableString> tagStrings = transform(firstFourByName, tagToString(maxLength)); List<SpannableString> tagStrings = transform(strings, tagToString(maxLength));
SpannableStringBuilder builder = new SpannableStringBuilder(); SpannableStringBuilder builder = new SpannableStringBuilder();
for (SpannableString tagString : tagStrings) { for (SpannableString tagString : tagStrings) {
if (builder.length() > 0) { if (builder.length() > 0) {
@ -103,12 +155,12 @@ public class TagFormatter {
return builder; return builder;
} }
private Function<TagData, SpannableString> tagToString(final float maxLength) { private Function<ColoredString, SpannableString> tagToString(final float maxLength) {
return tagData -> { return tagData -> {
String tagName = tagData.getName(); String tagName = tagData.name;
tagName = tagName.substring(0, Math.min(tagName.length(), (int) maxLength)); tagName = tagName.substring(0, Math.min(tagName.length(), (int) maxLength));
SpannableString string = new SpannableString(SPACE + tagName + SPACE); SpannableString string = new SpannableString(SPACE + tagName + SPACE);
int themeIndex = tagData.getColor(); int themeIndex = tagData.color;
ThemeColor color = ThemeColor color =
themeIndex >= 0 ? themeCache.getThemeColor(themeIndex) : themeCache.getUntaggedColor(); themeIndex >= 0 ? themeCache.getThemeColor(themeIndex) : themeCache.getUntaggedColor();
string.setSpan( string.setSpan(
@ -125,10 +177,28 @@ public class TagFormatter {
}; };
} }
private TagData getTag(String uuid) { private ColoredString getGoogleTaskList(String remoteId) {
TagData tagData = tagMap.get(uuid); ColoredString googleTaskList = googleTaskLists.get(remoteId);
if (googleTaskList == null) {
googleTaskList = new ColoredString(googleTaskListDao.getByRemoteId(remoteId));
googleTaskLists.put(remoteId, googleTaskList);
}
return googleTaskList;
}
private ColoredString getCaldavCalendar(String uuid) {
ColoredString calendar = caldavCalendars.get(uuid);
if (calendar == null) {
calendar = new ColoredString(caldavDao.getCalendar(uuid));
caldavCalendars.put(uuid, calendar);
}
return calendar;
}
private ColoredString getTag(String uuid) {
ColoredString tagData = tagMap.get(uuid);
if (tagData == null) { if (tagData == null) {
tagData = tagService.getTagByUuid(uuid); tagData = new ColoredString(tagService.getTagByUuid(uuid));
tagMap.put(uuid, tagData); tagMap.put(uuid, tagData);
} }
return tagData; return tagData;

@ -281,9 +281,8 @@ class ViewHolder extends RecyclerView.ViewHolder {
tagBlock.setVisibility(View.GONE); tagBlock.setVisibility(View.GONE);
} else { } else {
String tags = task.getTagsString(); String tags = task.getTagsString();
List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.newArrayList(); List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.newArrayList();
CharSequence tagString = tagFormatter.getTagString(tagUuids); CharSequence tagString = tagFormatter.getTagString(task.getCaldav(), task.getGoogleTaskList(), tagUuids);
if (TextUtils.isEmpty(tagString)) { if (TextUtils.isEmpty(tagString)) {
tagBlock.setVisibility(View.GONE); tagBlock.setVisibility(View.GONE);
} else { } else {

@ -1,6 +1,8 @@
package org.tasks.ui; package org.tasks.ui;
import static com.todoroo.astrid.activity.TaskListFragment.CALDAV_METADATA_JOIN;
import static com.todoroo.astrid.activity.TaskListFragment.FILE_METADATA_JOIN; import static com.todoroo.astrid.activity.TaskListFragment.FILE_METADATA_JOIN;
import static com.todoroo.astrid.activity.TaskListFragment.GTASK_METADATA_JOIN;
import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN; import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
@ -12,12 +14,16 @@ import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join; import com.todoroo.andlib.sql.Join;
import com.todoroo.astrid.api.CaldavFilter;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter;
import com.todoroo.astrid.api.TagFilter; import com.todoroo.astrid.api.TagFilter;
import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import javax.inject.Inject; import javax.inject.Inject;
import org.tasks.data.CaldavTask;
import org.tasks.data.GoogleTask;
import org.tasks.data.LimitOffsetDataSource; import org.tasks.data.LimitOffsetDataSource;
import org.tasks.data.Tag; import org.tasks.data.Tag;
import org.tasks.data.TaskAttachment; import org.tasks.data.TaskAttachment;
@ -62,11 +68,23 @@ public class TaskListViewModel extends ViewModel {
private LimitOffsetDataSource toDataSource(Filter filter, Property<?>[] properties) { private LimitOffsetDataSource toDataSource(Filter filter, Property<?>[] properties) {
Criterion tagsJoinCriterion = Criterion tagsJoinCriterion =
Criterion.and(Task.ID.eq(Field.field(TAGS_METADATA_JOIN + ".task"))); Criterion.and(Task.ID.eq(Field.field(TAGS_METADATA_JOIN + ".task")));
Criterion gtaskJoinCriterion =
Criterion.and(Task.ID.eq(Field.field(GTASK_METADATA_JOIN + ".task")));
Criterion caldavJoinCriterion =
Criterion.and(Task.ID.eq(Field.field(CALDAV_METADATA_JOIN + ".task")));
if (filter instanceof TagFilter) { if (filter instanceof TagFilter) {
String uuid = ((TagFilter) filter).getUuid(); String uuid = ((TagFilter) filter).getUuid();
tagsJoinCriterion = tagsJoinCriterion =
Criterion.and(tagsJoinCriterion, Field.field(TAGS_METADATA_JOIN + ".tag_uid").neq(uuid)); Criterion.and(tagsJoinCriterion, Field.field(TAGS_METADATA_JOIN + ".tag_uid").neq(uuid));
} else if (filter instanceof GtasksFilter) {
String listId = ((GtasksFilter) filter).getRemoteId();
gtaskJoinCriterion =
Criterion.and(gtaskJoinCriterion, Field.field(GTASK_METADATA_JOIN + ".list_id").neq(listId));
} else if (filter instanceof CaldavFilter) {
String uuid = ((CaldavFilter) filter).getUuid();
caldavJoinCriterion =
Criterion.and(
caldavJoinCriterion, Field.field(CALDAV_METADATA_JOIN + ".calendar").neq(uuid));
} }
// TODO: For now, we'll modify the query to join and include the things like tag data here. // TODO: For now, we'll modify the query to join and include the things like tag data here.
@ -77,6 +95,8 @@ public class TaskListViewModel extends ViewModel {
+ Join.left( + Join.left(
TaskAttachment.TABLE.as(FILE_METADATA_JOIN), TaskAttachment.TABLE.as(FILE_METADATA_JOIN),
Task.UUID.eq(Field.field(FILE_METADATA_JOIN + ".task_id"))) Task.UUID.eq(Field.field(FILE_METADATA_JOIN + ".task_id")))
+ Join.left(GoogleTask.TABLE.as(GTASK_METADATA_JOIN), gtaskJoinCriterion).toString()
+ Join.left(CaldavTask.TABLE.as(CALDAV_METADATA_JOIN), caldavJoinCriterion).toString()
+ filter.getSqlQuery(); + filter.getSqlQuery();
String query = String query =

Loading…
Cancel
Save