From d03698cd2efa4b0f80d1ae42a7df43030e71a2ad Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sat, 21 Apr 2018 10:42:41 -0500 Subject: [PATCH] Display tag blocks for caldav and google tasks --- .../astrid/activity/TaskListFragment.java | 2 + .../todoroo/astrid/adapter/TaskAdapter.java | 9 ++ .../com/todoroo/astrid/api/CaldavFilter.java | 2 +- .../com/todoroo/astrid/api/GtasksFilter.java | 2 +- .../java/com/todoroo/astrid/data/Task.java | 42 +++++- .../java/org/tasks/tasklist/TagFormatter.java | 124 ++++++++++++++---- .../java/org/tasks/tasklist/ViewHolder.java | 3 +- .../java/org/tasks/ui/TaskListViewModel.java | 22 +++- 8 files changed, 169 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java index aea440a94..1e14bfca9 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java @@ -79,6 +79,8 @@ public class TaskListFragment extends InjectingFragment implements SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener { 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$ private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234; private static final String EXTRA_FILTER = "extra_filter"; diff --git a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java index cf4213ebe..a72db400e 100644 --- a/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/app/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java @@ -35,6 +35,13 @@ public class TaskAdapter { + ".tag_uid, '')" + ", ',')") .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 = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); public static final Property[] PROPERTIES = @@ -42,6 +49,8 @@ public class TaskAdapter { Task.PROPERTIES, new Property[] { TAGS, // Concatenated list of tags + GTASK, + CALDAV, FILE_ID_PROPERTY // File id }, Property.class); diff --git a/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java b/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java index b3ce32a89..c6a42ab62 100644 --- a/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/CaldavFilter.java @@ -55,7 +55,7 @@ public class CaldavFilter extends Filter { Criterion.and( TaskDao.TaskCriteria.activeAndVisible(), Field.field("caldav_tasks.deleted").eq(0), - Field.field("calendar").eq(caldavCalendar.getUuid()))); + Field.field("caldav_tasks.calendar").eq(caldavCalendar.getUuid()))); } private static Map getValuesForNewTask(CaldavCalendar caldavCalendar) { diff --git a/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java b/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java index 2b89d615e..33a1cbb76 100644 --- a/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java +++ b/app/src/main/java/com/todoroo/astrid/api/GtasksFilter.java @@ -64,7 +64,7 @@ public class GtasksFilter extends Filter { Criterion.and( TaskDao.TaskCriteria.activeAndVisible(), 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 getValuesForNewTasks(GoogleTaskList list) { diff --git a/app/src/main/java/com/todoroo/astrid/data/Task.java b/app/src/main/java/com/todoroo/astrid/data/Task.java index e93e3ccdb..9e2857687 100644 --- a/app/src/main/java/com/todoroo/astrid/data/Task.java +++ b/app/src/main/java/com/todoroo/astrid/data/Task.java @@ -153,6 +153,7 @@ public class Task implements Parcelable { /** Name of Task */ @ColumnInfo(name = "title") public String title = ""; + @ColumnInfo(name = "importance") public Integer priority = Priority.NONE; /** 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 String tags; + @Ignore private transient String googleTaskList; + @Ignore private transient String caldav; @Ignore private transient boolean hasFiles; @Ignore private transient HashMap transitoryData = null; @@ -250,6 +253,8 @@ public class Task implements Parcelable { final int _cursorIndexOfRemoteId = _cursor.getColumnIndexOrThrow("remoteId"); final int _cursorIndexOfIndent = _cursor.getColumnIndex("indent"); final int _cursorIndexOfTags = _cursor.getColumnIndex("tags"); + final int _cursorIndexOfGoogleTasks = _cursor.getColumnIndex("googletask"); + final int _cursorIndexOfCaldav = _cursor.getColumnIndex("caldav"); final int _cursorIndexOfFileId = _cursor.getColumnIndex("fileId"); if (_cursor.isNull(_cursorIndexOfId)) { id = null; @@ -342,6 +347,12 @@ public class Task implements Parcelable { if (_cursorIndexOfTags >= 0) { tags = _cursor.getString(_cursorIndexOfTags); } + if (_cursorIndexOfGoogleTasks >= 0) { + googleTaskList = _cursor.getString(_cursorIndexOfGoogleTasks); + } + if (_cursorIndexOfCaldav >= 0) { + caldav = _cursor.getString(_cursorIndexOfCaldav); + } if (_cursorIndexOfFileId >= 0) { hasFiles = _cursor.getInt(_cursorIndexOfFileId) > 0; } @@ -1061,10 +1072,6 @@ public class Task implements Parcelable { return tags; } - public boolean hasFiles() { - return hasFiles; - } - @Override public boolean equals(Object o) { if (this == o) { @@ -1076,6 +1083,9 @@ public class Task implements Parcelable { Task task = (Task) o; + if (indent != task.indent) { + return false; + } if (hasFiles != task.hasFiles) { return false; } @@ -1152,7 +1162,15 @@ public class Task implements Parcelable { if (remoteId != null ? !remoteId.equals(task.remoteId) : task.remoteId != null) { 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 @@ -1180,7 +1198,21 @@ public class Task implements Parcelable { result = 31 * result + (remoteId != null ? remoteId.hashCode() : 0); result = 31 * result + indent; 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); return result; } + + public String getGoogleTaskList() { + return googleTaskList; + } + + public String getCaldav() { + return caldav; + } + + public boolean hasFiles() { + return hasFiles; + } } diff --git a/app/src/main/java/org/tasks/tasklist/TagFormatter.java b/app/src/main/java/org/tasks/tasklist/TagFormatter.java index e199bb1c8..565d975e8 100644 --- a/app/src/main/java/org/tasks/tasklist/TagFormatter.java +++ b/app/src/main/java/org/tasks/tasklist/TagFormatter.java @@ -12,13 +12,20 @@ import android.text.style.ForegroundColorSpan; import android.util.TypedValue; import com.google.common.base.Function; import com.google.common.base.Predicates; +import com.google.common.base.Strings; import com.google.common.collect.Ordering; import com.todoroo.astrid.tags.TagService; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; 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.injection.ForApplication; import org.tasks.themes.ThemeCache; @@ -28,25 +35,30 @@ public class TagFormatter { private static final char SPACE = '\u0020'; private static final char HAIR_SPACE = '\u200a'; + private static final int MAX_TAGS = 4; - private final Map tagMap = new HashMap<>(); + private final Map tagMap = new HashMap<>(); + private final Map googleTaskLists = new HashMap<>(); + private final Map caldavCalendars = new HashMap<>(); private final TagService tagService; private final ThemeCache themeCache; + private final GoogleTaskListDao googleTaskListDao; + private final CaldavDao caldavDao; private final float tagCharacters; - private final Function uuidToTag = this::getTag; - private final Ordering orderByName = - new Ordering() { + private final Function uuidToTag = this::getTag; + private final Ordering orderByName = + new Ordering() { @Override - public int compare(TagData left, TagData right) { - return left.getName().compareTo(right.getName()); + public int compare(ColoredString left, ColoredString right) { + return left.name.compareTo(right.name); } }; - private final Ordering orderByLength = - new Ordering() { + private final Ordering orderByLength = + new Ordering() { @Override - public int compare(TagData left, TagData right) { - int leftLength = left.getName().length(); - int rightLength = right.getName().length(); + public int compare(ColoredString left, ColoredString right) { + int leftLength = left.name.length(); + int rightLength = right.name.length(); if (leftLength < rightLength) { return -1; } else if (rightLength < leftLength) { @@ -59,31 +71,71 @@ public class TagFormatter { @Inject public TagFormatter( - @ForApplication Context context, TagService tagService, ThemeCache themeCache) { + @ForApplication Context context, + TagService tagService, + ThemeCache themeCache, + GoogleTaskListDao googleTaskListDao, + CaldavDao caldavDao) { this.tagService = tagService; this.themeCache = themeCache; + this.googleTaskListDao = googleTaskListDao; + this.caldavDao = caldavDao; TypedValue typedValue = new TypedValue(); context.getResources().getValue(R.dimen.tag_characters, typedValue, true); tagCharacters = typedValue.getFloat(); 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)); } } - CharSequence getTagString(List tagUuids) { - Iterable t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); - List firstFourByName = orderByName.leastOf(t, 4); - int numTags = firstFourByName.size(); + 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(); + } + + ColoredString(CaldavCalendar caldavCalendar) { + name = caldavCalendar.getName(); + color = caldavCalendar.getColor(); + } + } + + CharSequence getTagString(String caldav, String googleTask, List tagUuids) { + List strings = new ArrayList<>(); + if (!Strings.isNullOrEmpty(googleTask)) { + strings.add(getGoogleTaskList(googleTask)); + } else if (!Strings.isNullOrEmpty(caldav)) { + strings.add(getCaldavCalendar(caldav)); + } + + Iterable tags = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); + strings.addAll(0, orderByName.leastOf(tags, MAX_TAGS - strings.size())); + int numTags = strings.size(); if (numTags == 0) { return null; } - List firstFourByNameLength = orderByLength.sortedCopy(firstFourByName); + List firstFourByNameLength = orderByLength.sortedCopy(strings); float maxLength = tagCharacters / numTags; for (int i = 0; i < numTags - 1; i++) { - TagData tagData = firstFourByNameLength.get(i); - String name = tagData.getName(); + ColoredString tagData = firstFourByNameLength.get(i); + String name = tagData.name; if (name.length() >= maxLength) { break; } @@ -92,7 +144,7 @@ public class TagFormatter { float additional = excess / beneficiaries; maxLength += additional; } - List tagStrings = transform(firstFourByName, tagToString(maxLength)); + List tagStrings = transform(strings, tagToString(maxLength)); SpannableStringBuilder builder = new SpannableStringBuilder(); for (SpannableString tagString : tagStrings) { if (builder.length() > 0) { @@ -103,12 +155,12 @@ public class TagFormatter { return builder; } - private Function tagToString(final float maxLength) { + private Function tagToString(final float maxLength) { return tagData -> { - String tagName = tagData.getName(); + String tagName = tagData.name; tagName = tagName.substring(0, Math.min(tagName.length(), (int) maxLength)); SpannableString string = new SpannableString(SPACE + tagName + SPACE); - int themeIndex = tagData.getColor(); + int themeIndex = tagData.color; ThemeColor color = themeIndex >= 0 ? themeCache.getThemeColor(themeIndex) : themeCache.getUntaggedColor(); string.setSpan( @@ -125,10 +177,28 @@ public class TagFormatter { }; } - private TagData getTag(String uuid) { - TagData tagData = tagMap.get(uuid); + private ColoredString getGoogleTaskList(String remoteId) { + 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) { - tagData = tagService.getTagByUuid(uuid); + tagData = new ColoredString(tagService.getTagByUuid(uuid)); tagMap.put(uuid, tagData); } return tagData; diff --git a/app/src/main/java/org/tasks/tasklist/ViewHolder.java b/app/src/main/java/org/tasks/tasklist/ViewHolder.java index 278d484b2..7c1cf151e 100644 --- a/app/src/main/java/org/tasks/tasklist/ViewHolder.java +++ b/app/src/main/java/org/tasks/tasklist/ViewHolder.java @@ -281,9 +281,8 @@ class ViewHolder extends RecyclerView.ViewHolder { tagBlock.setVisibility(View.GONE); } else { String tags = task.getTagsString(); - List 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)) { tagBlock.setVisibility(View.GONE); } else { diff --git a/app/src/main/java/org/tasks/ui/TaskListViewModel.java b/app/src/main/java/org/tasks/ui/TaskListViewModel.java index 811469e1f..410bc141d 100644 --- a/app/src/main/java/org/tasks/ui/TaskListViewModel.java +++ b/app/src/main/java/org/tasks/ui/TaskListViewModel.java @@ -1,6 +1,8 @@ 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.GTASK_METADATA_JOIN; import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN; 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.Field; import com.todoroo.andlib.sql.Join; +import com.todoroo.astrid.api.CaldavFilter; import com.todoroo.astrid.api.Filter; +import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.api.TagFilter; import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Task; import javax.inject.Inject; +import org.tasks.data.CaldavTask; +import org.tasks.data.GoogleTask; import org.tasks.data.LimitOffsetDataSource; import org.tasks.data.Tag; import org.tasks.data.TaskAttachment; @@ -62,11 +68,23 @@ public class TaskListViewModel extends ViewModel { private LimitOffsetDataSource toDataSource(Filter filter, Property[] properties) { Criterion tagsJoinCriterion = 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) { String uuid = ((TagFilter) filter).getUuid(); tagsJoinCriterion = 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. @@ -77,6 +95,8 @@ public class TaskListViewModel extends ViewModel { + Join.left( TaskAttachment.TABLE.as(FILE_METADATA_JOIN), 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(); String query =