From 7a8af4e46f394fb504b1074cb1e8b31d4b70f334 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Tue, 1 Nov 2016 16:39:38 -0500 Subject: [PATCH] Add TagFormatter --- .../gtasks/GtasksSubtaskListFragment.java | 8 +- .../OrderedMetadataListFragmentHelper.java | 22 ++- .../astrid/activity/TaskListFragment.java | 8 +- .../todoroo/astrid/adapter/TaskAdapter.java | 116 ++-------------- .../AstridOrderedListFragmentHelper.java | 18 ++- .../astrid/subtasks/SubtasksListFragment.java | 8 +- .../subtasks/SubtasksTagListFragment.java | 10 +- .../java/org/tasks/tasklist/TagFormatter.java | 125 ++++++++++++++++++ 8 files changed, 167 insertions(+), 148 deletions(-) create mode 100644 src/main/java/org/tasks/tasklist/TagFormatter.java diff --git a/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java b/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java index 5ebb05471..6c08b5fcc 100644 --- a/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java +++ b/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java @@ -20,7 +20,6 @@ import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.tags.TagService; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; @@ -28,8 +27,8 @@ import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.preferences.Preferences; import org.tasks.tasklist.GtasksListFragment; +import org.tasks.tasklist.TagFormatter; import org.tasks.themes.Theme; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import java.util.ArrayList; @@ -53,10 +52,9 @@ public class GtasksSubtaskListFragment extends GtasksListFragment { @Inject Preferences preferences; @Inject DialogBuilder dialogBuilder; @Inject CheckBoxes checkBoxes; - @Inject TagService tagService; - @Inject ThemeCache themeCache; @Inject @ForApplication Context context; @Inject Theme theme; + @Inject TagFormatter tagFormatter; protected OrderedMetadataListFragmentHelper helper; private int lastVisibleIndex = -1; @@ -88,7 +86,7 @@ public class GtasksSubtaskListFragment extends GtasksListFragment { super.onAttach(activity); helper = new OrderedMetadataListFragmentHelper(preferences, taskAttachmentDao, taskDao, - metadataDao, this, gtasksTaskListUpdater, dialogBuilder, checkBoxes, tagService, themeCache); + metadataDao, this, gtasksTaskListUpdater, dialogBuilder, checkBoxes, tagFormatter); } @Override diff --git a/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java b/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java index a15ba3076..d28c75f09 100644 --- a/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java +++ b/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java @@ -24,7 +24,6 @@ import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.ui.DraggableListView; import com.todoroo.astrid.ui.DraggableListView.DropListener; import com.todoroo.astrid.ui.DraggableListView.GrabberClickListener; @@ -34,8 +33,8 @@ import org.tasks.R; import org.tasks.dialogs.DialogBuilder; import org.tasks.preferences.Preferences; import org.tasks.tasklist.ManualSortHelper; +import org.tasks.tasklist.TagFormatter; import org.tasks.tasklist.ViewHolder; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import java.util.ArrayList; @@ -52,8 +51,7 @@ class OrderedMetadataListFragmentHelper { private final GtasksTaskListUpdater updater; private final DialogBuilder dialogBuilder; private final CheckBoxes checkBoxes; - private final TagService tagService; - private final ThemeCache themeCache; + private final TagFormatter tagFormatter; private final TaskListFragment fragment; private final Preferences preferences; @@ -66,10 +64,9 @@ class OrderedMetadataListFragmentHelper { private GtasksList list; OrderedMetadataListFragmentHelper(Preferences preferences, TaskAttachmentDao taskAttachmentDao, - TaskDao taskDao, MetadataDao metadataDao, - TaskListFragment fragment, GtasksTaskListUpdater updater, - DialogBuilder dialogBuilder, CheckBoxes checkBoxes, TagService tagService, - ThemeCache themeCache) { + TaskDao taskDao, MetadataDao metadataDao, + TaskListFragment fragment, GtasksTaskListUpdater updater, + DialogBuilder dialogBuilder, CheckBoxes checkBoxes, TagFormatter tagFormatter) { this.preferences = preferences; this.taskAttachmentDao = taskAttachmentDao; this.taskDao = taskDao; @@ -78,8 +75,7 @@ class OrderedMetadataListFragmentHelper { this.updater = updater; this.dialogBuilder = dialogBuilder; this.checkBoxes = checkBoxes; - this.tagService = tagService; - this.themeCache = themeCache; + this.tagFormatter = tagFormatter; } // --- ui component setup @@ -180,7 +176,7 @@ class OrderedMetadataListFragmentHelper { AtomicReference sqlQueryTemplate) { taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor, - sqlQueryTemplate, dialogBuilder, checkBoxes, tagService, themeCache); + sqlQueryTemplate, dialogBuilder, checkBoxes, tagFormatter); taskAdapter.addOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); @@ -193,9 +189,9 @@ class OrderedMetadataListFragmentHelper { private DraggableTaskAdapter(Context context, Preferences preferences, TaskListFragment activity, Cursor c, AtomicReference query, DialogBuilder dialogBuilder, - CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) { + CheckBoxes checkBoxes, TagFormatter tagFormatter) { super(context, preferences, taskAttachmentDao, taskDao, activity, c, query, - dialogBuilder, checkBoxes, tagService, themeCache); + dialogBuilder, checkBoxes, tagFormatter); manualSortHelper = new ManualSortHelper(context); } diff --git a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java index 779ecf3a9..1f3556db6 100644 --- a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java +++ b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java @@ -49,7 +49,6 @@ import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.service.TaskDuplicator; import com.todoroo.astrid.subtasks.SubtasksListFragment; import com.todoroo.astrid.subtasks.SubtasksTagListFragment; -import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.timers.TimerPlugin; import com.todoroo.astrid.voice.VoiceInputAssistant; @@ -65,8 +64,8 @@ import org.tasks.injection.FragmentComponent; import org.tasks.injection.InjectingListFragment; import org.tasks.notifications.NotificationManager; import org.tasks.preferences.Preferences; +import org.tasks.tasklist.TagFormatter; import org.tasks.tasklist.ViewHolder; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import org.tasks.ui.MenuColorizer; @@ -123,11 +122,10 @@ public class TaskListFragment extends InjectingListFragment implements @Inject VoiceInputAssistant voiceInputAssistant; @Inject TaskCreator taskCreator; @Inject Broadcaster broadcaster; - @Inject TagService tagService; - @Inject ThemeCache themeCache; @Inject protected TaskListDataProvider taskListDataProvider; @Inject TimerPlugin timerPlugin; @Inject TaskDao taskDao; + @Inject TagFormatter tagFormatter; @BindView(R.id.swipe_layout) SwipeRefreshLayout swipeRefreshLayout; @BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyView; @@ -474,7 +472,7 @@ public class TaskListFragment extends InjectingListFragment implements protected TaskAdapter createTaskAdapter(TodorooCursor cursor) { return new TaskAdapter(context, preferences, taskAttachmentDao, taskDao, this, cursor, - taskListDataProvider.getSqlQueryTemplate(), dialogBuilder, checkBoxes, tagService, themeCache); + taskListDataProvider.getSqlQueryTemplate(), dialogBuilder, checkBoxes, tagFormatter); } public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$ diff --git a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java index 0d918d19a..14d46dd8a 100644 --- a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java @@ -12,14 +12,9 @@ import android.database.Cursor; import android.graphics.Paint; import android.support.v7.app.AlertDialog; import android.text.SpannableString; -import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; import android.text.method.LinkMovementMethod; -import android.text.style.BackgroundColorSpan; -import android.text.style.ForegroundColorSpan; import android.text.util.Linkify; -import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnTouchListener; @@ -29,10 +24,7 @@ import android.widget.Filterable; import android.widget.ImageView; import android.widget.TextView; -import com.google.common.base.Function; -import com.google.common.base.Predicates; import com.google.common.collect.Lists; -import com.google.common.collect.Ordering; import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.Property.IntegerProperty; import com.todoroo.andlib.data.Property.LongProperty; @@ -50,34 +42,27 @@ import com.todoroo.astrid.core.LinkActionExposer; import com.todoroo.astrid.dao.TaskAttachmentDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.RemoteModel; -import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.files.FilesAction; import com.todoroo.astrid.notes.NotesAction; -import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.tags.TaskToTagMetadata; import com.todoroo.astrid.ui.CheckableImageView; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; import org.tasks.preferences.Preferences; +import org.tasks.tasklist.TagFormatter; import org.tasks.tasklist.ViewHolder; -import org.tasks.themes.ThemeCache; -import org.tasks.themes.ThemeColor; import org.tasks.ui.CheckBoxes; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import timber.log.Timber; import static android.support.v4.content.ContextCompat.getColor; -import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Lists.transform; import static org.tasks.preferences.ResourceResolver.getData; /** @@ -92,8 +77,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable { void onCompletedTask(Task item, boolean newState); } - private static final char SPACE = '\u0020'; - private static final char HAIR_SPACE = '\u200a'; public static final StringProperty TAGS = new StringProperty(null, "group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TaskToTagMetadata.TAG_UUID.name + ", '')"+ ", ',')").as("tags"); public static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId"); public static final IntegerProperty HAS_NOTES_PROPERTY = new IntegerProperty(null, "length(" + Task.NOTES + ") > 0").as("hasNotes"); @@ -130,8 +113,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable { private final Context context; private final TaskListFragment fragment; private final DialogBuilder dialogBuilder; - private final TagService tagService; - private final ThemeCache themeCache; private final Resources resources; private OnCompletedTaskListener onCompletedTaskListener = null; private final LayoutInflater inflater; @@ -139,18 +120,15 @@ public class TaskAdapter extends CursorAdapter implements Filterable { private final AtomicReference query; - private final float tagCharacters; - - private final Map tagMap = new HashMap<>(); - private final int textColorSecondary; private final int textColorHint; private final int textColorOverdue; + private final TagFormatter tagFormatter; public TaskAdapter(Context context, Preferences preferences, TaskAttachmentDao taskAttachmentDao, TaskDao taskDao, TaskListFragment fragment, Cursor c, AtomicReference query, DialogBuilder dialogBuilder, - CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) { + CheckBoxes checkBoxes, TagFormatter tagFormatter) { super(context, c, false); this.checkBoxes = checkBoxes; this.preferences = preferences; @@ -160,23 +138,18 @@ public class TaskAdapter extends CursorAdapter implements Filterable { this.query = query; this.fragment = fragment; this.dialogBuilder = dialogBuilder; - this.tagService = tagService; - this.themeCache = themeCache; this.resources = fragment.getResources(); inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); - TypedValue typedValue = new TypedValue(); - context.getResources().getValue(R.dimen.tag_characters, typedValue, true); - tagCharacters = typedValue.getFloat(); - fontSize = preferences.getIntegerFromString(R.string.p_fontSize, 18); textColorSecondary = getData(context, android.R.attr.textColorSecondary); textColorHint = getData(context, android.R.attr.textColorTertiary); textColorOverdue = getColor(context, R.color.overdue); + this.tagFormatter = tagFormatter; - updateTagMap(); + tagFormatter.updateTagMap(); } @@ -393,15 +366,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable { @Override public void notifyDataSetChanged() { super.notifyDataSetChanged(); - updateTagMap(); + tagFormatter.updateTagMap(); } - private void updateTagMap() { - tagMap.clear(); - for (TagData tagData : tagService.getTagList()) { - tagMap.put(tagData.getUuid(), tagData); - } - } private final View.OnClickListener completeBoxListener = v -> { int[] location = new int[2]; @@ -469,43 +436,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable { checkBoxView.invalidate(); } - private final Function uuidToTag = tagMap::get; - - private final Ordering orderByName = new Ordering() { - @Override - public int compare(TagData left, TagData right) { - return left.getName().compareTo(right.getName()); - } - }; - - private final Ordering orderByLength = new Ordering() { - @Override - public int compare(TagData left, TagData right) { - int leftLength = left.getName().length(); - int rightLength = right.getName().length(); - if (leftLength < rightLength) { - return -1; - } else if (rightLength < leftLength) { - return 1; - } else { - return 0; - } - } - }; - - private Function tagToString(final float maxLength) { - return tagData -> { - String tagName = tagData.getName(); - tagName = tagName.substring(0, Math.min(tagName.length(), (int) maxLength)); - SpannableString string = new SpannableString(SPACE + tagName + SPACE); - int themeIndex = tagData.getColor(); - ThemeColor color = themeIndex >= 0 ? themeCache.getThemeColor(themeIndex) : themeCache.getUntaggedColor(); - string.setSpan(new BackgroundColorSpan(color.getPrimaryColor()), 0, string.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - string.setSpan(new ForegroundColorSpan(color.getActionBarTint()), 0, string.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - return string; - }; - } - private void setupDueDateAndTags(ViewHolder viewHolder, Task task) { // due date / completion date final TextView dueDateView = viewHolder.dueDate; @@ -532,36 +462,14 @@ public class TaskAdapter extends CursorAdapter implements Filterable { viewHolder.tagBlock.setVisibility(View.GONE); } else { String tags = viewHolder.tagsString; + List tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.newArrayList(); - Iterable t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); - List firstFourByName = orderByName.leastOf(t, 4); - int numTags = firstFourByName.size(); - if (numTags > 0) { - List firstFourByNameLength = orderByLength.sortedCopy(firstFourByName); - float maxLength = tagCharacters / numTags; - for (int i = 0; i < numTags - 1; i++) { - TagData tagData = firstFourByNameLength.get(i); - String name = tagData.getName(); - if (name.length() >= maxLength) { - break; - } - float excess = maxLength - name.length(); - int beneficiaries = numTags - i - 1; - float additional = excess / beneficiaries; - maxLength += additional; - } - List tagStrings = transform(firstFourByName, tagToString(maxLength)); - SpannableStringBuilder builder = new SpannableStringBuilder(); - for (SpannableString tagString : tagStrings) { - if (builder.length() > 0) { - builder.append(HAIR_SPACE); - } - builder.append(tagString); - } - viewHolder.tagBlock.setText(builder); - viewHolder.tagBlock.setVisibility(View.VISIBLE); - } else { + CharSequence tagString = tagFormatter.getTagString(tagUuids); + if (TextUtils.isEmpty(tagString)) { viewHolder.tagBlock.setVisibility(View.GONE); + } else { + viewHolder.tagBlock.setText(tagString); + viewHolder.tagBlock.setVisibility(View.VISIBLE); } } } diff --git a/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java b/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java index b3453b580..8bbb86566 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java +++ b/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java @@ -22,7 +22,6 @@ import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import com.todoroo.astrid.tags.TagService; import com.todoroo.astrid.ui.DraggableListView; import com.todoroo.astrid.ui.DraggableListView.DropListener; import com.todoroo.astrid.ui.DraggableListView.GrabberClickListener; @@ -32,8 +31,8 @@ import org.tasks.R; import org.tasks.dialogs.DialogBuilder; import org.tasks.preferences.Preferences; import org.tasks.tasklist.ManualSortHelper; +import org.tasks.tasklist.TagFormatter; import org.tasks.tasklist.ViewHolder; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import java.util.ArrayList; @@ -50,11 +49,10 @@ class AstridOrderedListFragmentHelper { private final SubtasksFilterUpdater updater; private final DialogBuilder dialogBuilder; private final CheckBoxes checkBoxes; - private final TagService tagService; private final TaskListFragment fragment; private final Preferences preferences; private final TaskAttachmentDao taskAttachmentDao; - private final ThemeCache themeCache; + private final TagFormatter tagFormatter; private final TaskDao taskDao; private DraggableTaskAdapter taskAdapter; @@ -64,15 +62,14 @@ class AstridOrderedListFragmentHelper { AstridOrderedListFragmentHelper(Preferences preferences, TaskAttachmentDao taskAttachmentDao, TaskListFragment fragment, SubtasksFilterUpdater updater, DialogBuilder dialogBuilder, CheckBoxes checkBoxes, - TagService tagService, ThemeCache themeCache, TaskDao taskDao) { + TagFormatter tagFormatter, TaskDao taskDao) { this.preferences = preferences; this.taskAttachmentDao = taskAttachmentDao; this.fragment = fragment; this.updater = updater; this.dialogBuilder = dialogBuilder; this.checkBoxes = checkBoxes; - this.tagService = tagService; - this.themeCache = themeCache; + this.tagFormatter = tagFormatter; this.taskDao = taskDao; } @@ -181,7 +178,7 @@ class AstridOrderedListFragmentHelper { AtomicReference sqlQueryTemplate) { taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor, - sqlQueryTemplate, dialogBuilder, checkBoxes, tagService, themeCache); + sqlQueryTemplate, dialogBuilder, checkBoxes, tagFormatter); taskAdapter.addOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); @@ -194,8 +191,9 @@ class AstridOrderedListFragmentHelper { private DraggableTaskAdapter(Context context, Preferences preferences, TaskListFragment activity, Cursor c, AtomicReference query, DialogBuilder dialogBuilder, - CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) { - super(context, preferences, taskAttachmentDao, taskDao, activity, c, query, dialogBuilder, checkBoxes, tagService, themeCache); + CheckBoxes checkBoxes, TagFormatter tagFormatter) { + super(context, preferences, taskAttachmentDao, taskDao, activity, c, query, + dialogBuilder, checkBoxes, tagFormatter); manualSortHelper = new ManualSortHelper(context); } diff --git a/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java b/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java index a083320b7..2307d5a34 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java +++ b/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java @@ -22,15 +22,14 @@ import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskListMetadataDao; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import com.todoroo.astrid.tags.TagService; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.preferences.Preferences; +import org.tasks.tasklist.TagFormatter; import org.tasks.themes.Theme; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import javax.inject.Inject; @@ -60,17 +59,16 @@ public class SubtasksListFragment extends TaskListFragment { @Inject DialogBuilder dialogBuilder; @Inject TaskListMetadataDao taskListMetadataDao; @Inject CheckBoxes checkBoxes; - @Inject TagService tagService; - @Inject ThemeCache themeCache; @Inject Theme theme; @Inject TaskDao taskDao; + @Inject TagFormatter tagFormatter; @Override public void onAttach(Activity activity) { super.onAttach(activity); helper = new AstridOrderedListFragmentHelper(preferences, taskAttachmentDao, - this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagService, themeCache, taskDao); + this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagFormatter, taskDao); } @Override diff --git a/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java b/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java index 5dba09a85..39374d543 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java +++ b/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java @@ -11,7 +11,6 @@ import android.os.Bundle; import android.view.View; import com.todoroo.andlib.data.TodorooCursor; -import org.tasks.tasklist.TagListFragment; import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.api.TagFilter; @@ -22,15 +21,15 @@ import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import com.todoroo.astrid.tags.TagService; import org.tasks.R; import org.tasks.dialogs.DialogBuilder; import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.preferences.Preferences; +import org.tasks.tasklist.TagFormatter; +import org.tasks.tasklist.TagListFragment; import org.tasks.themes.Theme; -import org.tasks.themes.ThemeCache; import org.tasks.ui.CheckBoxes; import javax.inject.Inject; @@ -51,10 +50,9 @@ public class SubtasksTagListFragment extends TagListFragment { @Inject DialogBuilder dialogBuilder; @Inject TaskListMetadataDao taskListMetadataDao; @Inject CheckBoxes checkBoxes; - @Inject TagService tagService; - @Inject ThemeCache themeCache; @Inject Theme theme; @Inject TaskDao taskDao; + @Inject TagFormatter tagFormatter; private AstridOrderedListFragmentHelper helper; @@ -65,7 +63,7 @@ public class SubtasksTagListFragment extends TagListFragment { super.onAttach(activity); helper = new AstridOrderedListFragmentHelper(preferences, taskAttachmentDao, - this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagService, themeCache, taskDao); + this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagFormatter, taskDao); } @Override diff --git a/src/main/java/org/tasks/tasklist/TagFormatter.java b/src/main/java/org/tasks/tasklist/TagFormatter.java new file mode 100644 index 000000000..7872eaef3 --- /dev/null +++ b/src/main/java/org/tasks/tasklist/TagFormatter.java @@ -0,0 +1,125 @@ +package org.tasks.tasklist; + +import android.content.Context; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.BackgroundColorSpan; +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.collect.Ordering; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.tags.TagService; + +import org.tasks.R; +import org.tasks.injection.ForApplication; +import org.tasks.themes.ThemeCache; +import org.tasks.themes.ThemeColor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + +import static com.google.common.collect.Iterables.filter; +import static com.google.common.collect.Lists.transform; + +public class TagFormatter { + + private static final char SPACE = '\u0020'; + private static final char HAIR_SPACE = '\u200a'; + + private final Map tagMap = new HashMap<>(); + private final TagService tagService; + private final ThemeCache themeCache; + private final float tagCharacters; + + @Inject + public TagFormatter(@ForApplication Context context, TagService tagService, ThemeCache themeCache) { + this.tagService = tagService; + this.themeCache = themeCache; + + TypedValue typedValue = new TypedValue(); + context.getResources().getValue(R.dimen.tag_characters, typedValue, true); + tagCharacters = typedValue.getFloat(); + } + + public void updateTagMap() { + tagMap.clear(); + for (TagData tagData : tagService.getTagList()) { + tagMap.put(tagData.getUuid(), tagData); + } + } + + public CharSequence getTagString(List tagUuids) { + Iterable t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); + List firstFourByName = orderByName.leastOf(t, 4); + int numTags = firstFourByName.size(); + if (numTags == 0) { + return null; + } + List firstFourByNameLength = orderByLength.sortedCopy(firstFourByName); + float maxLength = tagCharacters / numTags; + for (int i = 0; i < numTags - 1; i++) { + TagData tagData = firstFourByNameLength.get(i); + String name = tagData.getName(); + if (name.length() >= maxLength) { + break; + } + float excess = maxLength - name.length(); + int beneficiaries = numTags - i - 1; + float additional = excess / beneficiaries; + maxLength += additional; + } + List tagStrings = transform(firstFourByName, tagToString(maxLength)); + SpannableStringBuilder builder = new SpannableStringBuilder(); + for (SpannableString tagString : tagStrings) { + if (builder.length() > 0) { + builder.append(HAIR_SPACE); + } + builder.append(tagString); + } + return builder; + } + + private Function tagToString(final float maxLength) { + return tagData -> { + String tagName = tagData.getName(); + tagName = tagName.substring(0, Math.min(tagName.length(), (int) maxLength)); + SpannableString string = new SpannableString(SPACE + tagName + SPACE); + int themeIndex = tagData.getColor(); + ThemeColor color = themeIndex >= 0 ? themeCache.getThemeColor(themeIndex) : themeCache.getUntaggedColor(); + string.setSpan(new BackgroundColorSpan(color.getPrimaryColor()), 0, string.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + string.setSpan(new ForegroundColorSpan(color.getActionBarTint()), 0, string.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return string; + }; + } + + private final Function uuidToTag = tagMap::get; + + private final Ordering orderByName = new Ordering() { + @Override + public int compare(TagData left, TagData right) { + return left.getName().compareTo(right.getName()); + } + }; + + private final Ordering orderByLength = new Ordering() { + @Override + public int compare(TagData left, TagData right) { + int leftLength = left.getName().length(); + int rightLength = right.getName().length(); + if (leftLength < rightLength) { + return -1; + } else if (rightLength < leftLength) { + return 1; + } else { + return 0; + } + } + }; +}