Add tag colors

pull/413/head
Alex Baker 8 years ago
parent 8c4df05bda
commit 386a096421

@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Intent;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.widget.WidgetConfigActivity;
import javax.inject.Inject;
@ -21,7 +20,7 @@ public class PurchaseHelper {
return false;
}
public void handleActivityResult(WidgetConfigActivity widgetConfigActivity, int requestCode, int resultCode, Intent data) {
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) {
}
}

@ -4,11 +4,15 @@ import android.content.Context;
import com.todoroo.astrid.dao.Database;
import org.tasks.analytics.Tracker;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
import static org.mockito.Mockito.mock;
@Module
public class TestModule {
private Context context;
@ -20,7 +24,7 @@ public class TestModule {
@Singleton
@Provides
public Database getDatabase() {
return new Database(context) {
return new Database(context, mock(Tracker.class)) {
@Override
public String getName() {
return "databasetest";

@ -5,7 +5,6 @@ import android.content.Intent;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.preferences.Preferences;
import org.tasks.widget.WidgetConfigActivity;
import javax.inject.Inject;
@ -25,7 +24,7 @@ public class PurchaseHelper {
return true;
}
public void handleActivityResult(WidgetConfigActivity widgetConfigActivity, int requestCode, int resultCode, Intent data) {
public void handleActivityResult(PurchaseHelperCallback callback, int requestCode, int resultCode, Intent data) {
}
}

@ -21,6 +21,7 @@ import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.subtasks.OrderedListFragmentHelperInterface;
import com.todoroo.astrid.subtasks.SubtasksListFragment;
import com.todoroo.astrid.sync.SyncResultCallback;
import com.todoroo.astrid.tags.TagService;
import org.tasks.Broadcaster;
import org.tasks.R;
@ -28,6 +29,7 @@ import org.tasks.dialogs.DialogBuilder;
import org.tasks.preferences.Preferences;
import org.tasks.sync.IndeterminateProgressBarSyncResultCallback;
import org.tasks.sync.SyncThrottle;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import javax.inject.Inject;
@ -54,12 +56,15 @@ public class GtasksListFragment extends SubtasksListFragment {
@Inject DialogBuilder dialogBuilder;
@Inject Broadcaster broadcaster;
@Inject CheckBoxes checkBoxes;
@Inject TagService tagService;
@Inject ThemeCache themeCache;
private GtasksList list;
@Override
protected OrderedListFragmentHelperInterface createFragmentHelper() {
return new OrderedMetadataListFragmentHelper<>(preferences, taskAttachmentDao, taskService, metadataDao, this, gtasksTaskListUpdater, dialogBuilder, checkBoxes);
return new OrderedMetadataListFragmentHelper<>(preferences, taskAttachmentDao, taskService,
metadataDao, this, gtasksTaskListUpdater, dialogBuilder, checkBoxes, tagService, themeCache);
}
@Override

@ -30,11 +30,13 @@ import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.subtasks.OrderedListFragmentHelperInterface;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.ui.DraggableListView;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import java.util.ArrayList;
@ -52,6 +54,8 @@ public class OrderedMetadataListFragmentHelper<LIST> implements OrderedListFragm
private final OrderedMetadataListUpdater<LIST> updater;
private DialogBuilder dialogBuilder;
private CheckBoxes checkBoxes;
private final TagService tagService;
private ThemeCache themeCache;
private final TaskListFragment fragment;
private final Preferences preferences;
@ -66,7 +70,8 @@ public class OrderedMetadataListFragmentHelper<LIST> implements OrderedListFragm
public OrderedMetadataListFragmentHelper(Preferences preferences, TaskAttachmentDao taskAttachmentDao,
TaskService taskService, MetadataDao metadataDao,
TaskListFragment fragment, OrderedMetadataListUpdater<LIST> updater,
DialogBuilder dialogBuilder, CheckBoxes checkBoxes) {
DialogBuilder dialogBuilder, CheckBoxes checkBoxes, TagService tagService,
ThemeCache themeCache) {
this.preferences = preferences;
this.taskAttachmentDao = taskAttachmentDao;
this.taskService = taskService;
@ -75,6 +80,8 @@ public class OrderedMetadataListFragmentHelper<LIST> implements OrderedListFragm
this.updater = updater;
this.dialogBuilder = dialogBuilder;
this.checkBoxes = checkBoxes;
this.tagService = tagService;
this.themeCache = themeCache;
}
// --- ui component setup
@ -189,7 +196,8 @@ public class OrderedMetadataListFragmentHelper<LIST> implements OrderedListFragm
public TaskAdapter createTaskAdapter(Context context, TodorooCursor<Task> cursor,
AtomicReference<String> sqlQueryTemplate) {
taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor, sqlQueryTemplate, dialogBuilder, checkBoxes);
taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor,
sqlQueryTemplate, dialogBuilder, checkBoxes, tagService, themeCache);
taskAdapter.addOnCompletedTaskListener(new OnCompletedTaskListener() {
@Override
@ -204,8 +212,10 @@ public class OrderedMetadataListFragmentHelper<LIST> implements OrderedListFragm
private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(Context context, Preferences preferences, TaskListFragment activity,
Cursor c, AtomicReference<String> query, DialogBuilder dialogBuilder, CheckBoxes checkBoxes) {
super(context, preferences, taskAttachmentDao, taskService, activity, c, query, null, dialogBuilder, checkBoxes);
Cursor c, AtomicReference<String> query, DialogBuilder dialogBuilder,
CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) {
super(context, preferences, taskAttachmentDao, taskService, activity, c, query, null,
dialogBuilder, checkBoxes, tagService, themeCache);
}
@Override

@ -330,8 +330,7 @@
<!-- actfm -->
<activity
android:name="com.todoroo.astrid.actfm.TagSettingsActivity"
android:windowSoftInputMode="stateHidden" />
android:name="com.todoroo.astrid.actfm.TagSettingsActivity" />
<activity
android:name="com.todoroo.astrid.actfm.FilterSettingsActivity"

@ -122,7 +122,11 @@ public class DatabaseDao<TYPE extends AbstractModel> {
*/
public TodorooCursor<TYPE> query(Query query) {
query.from(table);
Cursor cursor = database.rawQuery(query.toString());
String queryString = query.toString();
if (BuildConfig.DEBUG) {
Timber.d(queryString);
}
Cursor cursor = database.rawQuery(queryString);
return new TodorooCursor<>(cursor, query.getFields());
}

@ -5,6 +5,7 @@
*/
package com.todoroo.astrid.actfm;
import android.app.FragmentManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -13,8 +14,6 @@ import android.os.Bundle;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@ -23,7 +22,6 @@ import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.google.common.base.Strings;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.MetadataDao;
@ -36,20 +34,31 @@ import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
import org.tasks.R;
import org.tasks.billing.PurchaseHelper;
import org.tasks.billing.PurchaseHelperCallback;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.dialogs.ThemePickerDialog;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ThemedInjectingAppCompatActivity;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.MenuColorizer;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import timber.log.Timber;
import static android.text.TextUtils.isEmpty;
import static org.tasks.dialogs.ThemePickerDialog.newThemePickerDialog;
public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
public class TagSettingsActivity extends ThemedInjectingAppCompatActivity implements ThemePickerDialog.ThemePickerCallback, PurchaseHelperCallback {
private static final String FRAG_TAG_COLOR_PICKER = "frag_tag_color_picker";
private static final int REQUEST_PURCHASE = 10109;
public static final String TOKEN_NEW_FILTER = "newFilter"; //$NON-NLS-1$
public static final String TOKEN_AUTOPOPULATE_NAME = "autopopulateName"; //$NON-NLS-1$
@ -58,15 +67,20 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
private boolean isNewTag;
private TagData tagData;
private int selectedTheme;
@Inject TagService tagService;
@Inject TagDataDao tagDataDao;
@Inject MetadataDao metadataDao;
@Inject DialogBuilder dialogBuilder;
@Inject Preferences preferences;
@Inject ThemeCache themeCache;
@Inject PurchaseHelper purchaseHelper;
@BindView(R.id.tag_name) EditText tagName;
@BindView(R.id.toolbar) Toolbar toolbar;
@BindView(R.id.theme) TextView themeName;
@BindView(R.id.clear) View clear;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -110,9 +124,31 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
if (!isEmpty(autopopulateName)) {
tagName.setText(autopopulateName);
getIntent().removeExtra(TOKEN_AUTOPOPULATE_NAME);
} else if (isNewTag) {
tagName.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(tagName, InputMethodManager.SHOW_IMPLICIT);
}
selectedTheme = tagData.getColor();
updateTheme();
}
@OnClick(R.id.theme_row)
protected void showThemePicker() {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.findFragmentByTag(FRAG_TAG_COLOR_PICKER) == null) {
newThemePickerDialog(ThemePickerDialog.ColorPalette.COLORS)
.show(fragmentManager, FRAG_TAG_COLOR_PICKER);
}
}
@OnClick(R.id.clear)
void clearColor() {
selectedTheme = -1;
updateTheme();
}
@Override
public void inject(ActivityComponent component) {
component.inject(this);
@ -128,7 +164,6 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
}
private void save() {
String oldName = tagData.getName();
String newName = getNewName();
if (isEmpty(newName)) {
@ -143,10 +178,12 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
if (isNewTag) {
tagData.setName(newName);
tagData.setColor(selectedTheme);
tagDataDao.persist(tagData);
setResult(RESULT_OK, new Intent().putExtra(TOKEN_NEW_FILTER, TagFilterExposer.filterFromTag(tagData)));
} else if (!oldName.equals(newName)) {
} else if (hasChanges()) {
tagData.setName(newName);
tagData.setColor(selectedTheme);
tagService.rename(tagData.getUuid(), newName);
tagDataDao.persist(tagData);
Metadata m = new Metadata();
@ -160,6 +197,13 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
finish();
}
private boolean hasChanges() {
if (isNewTag) {
return selectedTheme >= 0 || !isEmpty(getNewName());
}
return !(selectedTheme == tagData.getColor() && getNewName().equals(tagData.getName()));
}
@Override
public void finish() {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
@ -196,6 +240,15 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_PURCHASE) {
purchaseHelper.handleActivityResult(this, requestCode, resultCode, data);
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void deleteTag() {
dialogBuilder.newMessageDialog(R.string.delete_tag_confirmation, tagData.getName())
.setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() {
@ -215,9 +268,7 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
}
private void discard() {
String tagName = getNewName();
if ((isNewTag && isEmpty(tagName)) ||
(!isNewTag && tagData.getName().equals(tagName))) {
if (!hasChanges()) {
finish();
} else {
dialogBuilder.newMessageDialog(R.string.discard_changes)
@ -231,4 +282,39 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity {
.show();
}
}
@Override
public void themePicked(ThemePickerDialog.ColorPalette palette, int index) {
selectedTheme = index;
updateTheme();
}
private void updateTheme() {
if (selectedTheme < 0) {
themeName.setText(R.string.none);
clear.setVisibility(View.GONE);
} else {
themeName.setText(themeCache.getThemeColor(selectedTheme).getName());
clear.setVisibility(View.VISIBLE);
}
}
@Override
public void initiateThemePurchase() {
purchaseHelper.purchase(dialogBuilder, this, getString(R.string.sku_themes), getString(R.string.p_purchased_themes), REQUEST_PURCHASE, this);
}
@Override
public void purchaseCompleted(boolean success, final String sku) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (getString(R.string.sku_themes).equals(sku)) {
showThemePicker();
} else {
Timber.d("Unhandled sku: %s", sku);
}
}
});
}
}

@ -66,6 +66,7 @@ import com.todoroo.astrid.service.TaskDuplicator;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.subtasks.SubtasksListFragment;
import com.todoroo.astrid.subtasks.SubtasksTagListFragment;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
import com.todoroo.astrid.timers.TimerPlugin;
import com.todoroo.astrid.voice.VoiceInputAssistant;
@ -79,6 +80,7 @@ import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingListFragment;
import org.tasks.notifications.NotificationManager;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import org.tasks.ui.MenuColorizer;
@ -146,6 +148,8 @@ public class TaskListFragment extends InjectingListFragment implements
@Inject VoiceInputAssistant voiceInputAssistant;
@Inject TaskCreator taskCreator;
@Inject Broadcaster broadcaster;
@Inject TagService tagService;
@Inject ThemeCache themeCache;
@BindView(R.id.swipe_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyView;
@ -560,7 +564,7 @@ public class TaskListFragment extends InjectingListFragment implements
@Override
public void onCompletedTask(Task item, boolean newState) {
}
}, dialogBuilder, checkBoxes);
}, dialogBuilder, checkBoxes, tagService, themeCache);
}
public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$

@ -24,6 +24,7 @@ import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.TagFilter;
import com.todoroo.astrid.core.CustomFilterActivity;
import org.tasks.R;
@ -34,6 +35,8 @@ import org.tasks.filters.NavigationDrawerSeparator;
import org.tasks.filters.NavigationDrawerSubheader;
import org.tasks.preferences.BasicPreferences;
import org.tasks.preferences.HelpAndFeedbackActivity;
import org.tasks.themes.Theme;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.NavigationDrawerFragment;
import java.util.List;
@ -57,16 +60,20 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
/** layout inflater */
private final LayoutInflater inflater;
private final Theme theme;
private final ThemeCache themeCache;
public FilterAdapter(FilterProvider filterProvider, FilterCounter filterCounter, Activity activity,
LayoutInflater inflater, ListView listView, boolean navigationDrawer) {
ListView listView, boolean navigationDrawer, Theme theme, ThemeCache themeCache) {
super(activity, 0);
this.filterProvider = filterProvider;
this.filterCounter = filterCounter;
this.activity = activity;
this.listView = listView;
this.navigationDrawer = navigationDrawer;
this.inflater = inflater;
this.inflater = theme.getLayoutInflater(activity);
this.theme = theme;
this.themeCache = themeCache;
}
@Override
@ -319,9 +326,10 @@ public class FilterAdapter extends ArrayAdapter<FilterListItem> {
}
viewHolder.view.setBackgroundResource(0);
int icon = filter.icon;
viewHolder.icon.setImageResource(icon);
viewHolder.icon.setVisibility(icon == 0 ? View.INVISIBLE : View.VISIBLE);
viewHolder.icon.setImageResource(filter.icon);
viewHolder.icon.setColorFilter(filter.tint >= 0
? themeCache.getThemeColor(filter.tint).getPrimaryColor()
: theme.getThemeBase().getTextColor());
String title = filter.listingTitle;
if(!title.equals(viewHolder.name.getText())) {

@ -11,8 +11,13 @@ import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Paint;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@ -24,6 +29,10 @@ 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;
@ -36,23 +45,33 @@ import com.todoroo.astrid.api.TaskAction;
import com.todoroo.astrid.core.LinkActionExposer;
import com.todoroo.astrid.dao.TaskAttachmentDao;
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.service.TaskService;
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.themes.ThemeCache;
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 com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
/**
* Adapter for displaying a user's tasks as a list
*
@ -65,7 +84,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
void onCompletedTask(Task item, boolean newState);
}
private static final StringProperty TAGS = new StringProperty(null, "group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TaskToTagMetadata.TAG_NAME.name + ", '')"+ ", ' | ')").as("tags");
private static final char SPACE = '\u0020';
private static final char HAIR_SPACE = '\u200a';
private static final StringProperty TAGS = new StringProperty(null, "group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + "." + TaskToTagMetadata.TAG_UUID.name + ", '')"+ ", ',')").as("tags");
private static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId");
private static final IntegerProperty HAS_NOTES_PROPERTY = new IntegerProperty(null, "length(" + Task.NOTES + ") > 0").as("hasNotes");
@ -101,6 +122,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
protected final Context context;
protected final TaskListFragment fragment;
private DialogBuilder dialogBuilder;
private final TagService tagService;
private ThemeCache themeCache;
protected final Resources resources;
protected OnCompletedTaskListener onCompletedTaskListener = null;
protected final LayoutInflater inflater;
@ -109,14 +132,16 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
private final AtomicReference<String> query;
// measure utilities
protected final Paint paint;
protected final DisplayMetrics displayMetrics;
protected final int minRowHeight;
private final float tagCharacters;
private final Map<String, TagData> tagMap = new HashMap<>();
public TaskAdapter(Context context, Preferences preferences, TaskAttachmentDao taskAttachmentDao, TaskService taskService, TaskListFragment fragment,
Cursor c, AtomicReference<String> query, OnCompletedTaskListener onCompletedTaskListener,
DialogBuilder dialogBuilder, CheckBoxes checkBoxes) {
Cursor c, AtomicReference<String> query, OnCompletedTaskListener onCompletedTaskListener,
DialogBuilder dialogBuilder, CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) {
super(context, c, false);
this.checkBoxes = checkBoxes;
this.preferences = preferences;
@ -126,16 +151,22 @@ 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();
this.onCompletedTaskListener = onCompletedTaskListener;
inflater = (LayoutInflater) fragment.getActivity().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);
paint = new Paint();
displayMetrics = new DisplayMetrics();
fragment.getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
updateTagMap();
this.minRowHeight = computeMinRowHeight();
}
@ -182,8 +213,8 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
viewHolder.rowBody = (ViewGroup)view.findViewById(R.id.rowBody);
viewHolder.nameView = (TextView)view.findViewById(R.id.title);
viewHolder.completeBox = (CheckableImageView)view.findViewById(R.id.completeBox);
viewHolder.dueDate = (TextView)view.findViewById(R.id.dueDate);
viewHolder.tagsView = (TextView)view.findViewById(R.id.tagsDisplay);
viewHolder.dueDate = (TextView)view.findViewById(R.id.due_date);
viewHolder.tagBlock = (TextView) view.findViewById(R.id.tag_block);
viewHolder.taskActionContainer = view.findViewById(R.id.taskActionContainer);
viewHolder.taskActionIcon = (ImageView)view.findViewById(R.id.taskActionIcon);
@ -249,7 +280,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public TextView nameView;
public CheckableImageView completeBox;
public TextView dueDate;
public TextView tagsView;
public TextView tagBlock;
public View taskActionContainer;
public ImageView taskActionIcon;
public String tagsString; // From join query, not part of the task model
@ -290,11 +321,11 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
if (taskAction != null) {
TaskAction action = getTaskAction(task, viewHolder.hasFiles, viewHolder.hasNotes);
if (action != null) {
taskAction.setVisibility(View.VISIBLE);
viewHolder.taskActionContainer.setVisibility(View.VISIBLE);
taskAction.setImageDrawable(action.icon);
taskAction.setTag(action);
} else {
taskAction.setVisibility(View.GONE);
viewHolder.taskActionContainer.setVisibility(View.GONE);
taskAction.setTag(null);
}
}
@ -392,6 +423,14 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
fontSize = preferences.getIntegerFromString(R.string.p_fontSize, 18);
updateTagMap();
}
private void updateTagMap() {
tagMap.clear();
for (TagData tagData : tagService.getTagList()) {
tagMap.put(tagData.getUuid(), tagData);
}
}
protected final View.OnClickListener completeBoxListener = new View.OnClickListener() {
@ -447,11 +486,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
viewHolder.dueDate.setTextSize(detailTextSize);
viewHolder.dueDate.setTypeface(null, 0);
}
if (viewHolder.tagsView != null) {
viewHolder.tagsView.setTextSize(detailTextSize);
viewHolder.tagsView.setTypeface(null, 0);
}
paint.setTextSize(detailTextSize);
setupCompleteBox(viewHolder);
@ -474,6 +508,50 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
checkBoxView.invalidate();
}
private final Function<String, TagData> uuidToTag = new Function<String, TagData>() {
@Override
public TagData apply(String input) {
return tagMap.get(input);
}
};
private final Ordering<TagData> orderByName = new Ordering<TagData>() {
@Override
public int compare(TagData left, TagData right) {
return left.getName().compareTo(right.getName());
}
};
private final Ordering<TagData> orderByLength = new Ordering<TagData>() {
@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<TagData, SpannableString> tagToString(final float maxLength) {
return new Function<TagData, SpannableString>() {
@Override
public SpannableString apply(TagData 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() >= 0 ? tagData.getColor() : 19;
int backgroundColor = themeCache.getThemeColor(themeIndex).getPrimaryColor();
string.setSpan(new BackgroundColorSpan(backgroundColor), 0, string.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
return string;
}
};
}
// Returns due date text width
private void setupDueDateAndTags(ViewHolder viewHolder, Task task) {
// due date / completion date
@ -499,17 +577,40 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
dueDateView.setVisibility(View.GONE);
}
if (viewHolder.tagsView != null) {
if (task.isCompleted()) {
viewHolder.tagBlock.setVisibility(View.GONE);
} else {
String tags = viewHolder.tagsString;
if (tags != null && task.hasDueDate()) {
tags = " | " + tags; //$NON-NLS-1$
}
if (!task.isCompleted()) {
viewHolder.tagsView.setText(tags);
viewHolder.tagsView.setVisibility(TextUtils.isEmpty(tags) ? View.GONE : View.VISIBLE);
List<String> tagUuids = tags != null ? newArrayList(tags.split(",")) : Lists.<String>newArrayList();
Iterable<TagData> t = filter(transform(tagUuids, uuidToTag), Predicates.notNull());
List<TagData> firstFourByName = orderByName.leastOf(t, 4);
int numTags = firstFourByName.size();
if (numTags > 0) {
List<TagData> 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<SpannableString> 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 {
viewHolder.tagsView.setText(""); //$NON-NLS-1$
viewHolder.tagsView.setVisibility(View.GONE);
viewHolder.tagBlock.setVisibility(View.GONE);
}
}
}

@ -31,6 +31,7 @@ abstract public class FilterListItem implements Parcelable {
public String listingTitle = null;
public int icon = 0;
public int tint = -1;
@Override
public int describeContents() {
@ -46,6 +47,7 @@ abstract public class FilterListItem implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(listingTitle);
dest.writeInt(icon);
dest.writeInt(tint);
dest.writeStringArray(new String[0]); // old context menu labels
dest.writeTypedArray(new Intent[0], 0); // old context menu intents
}
@ -56,6 +58,7 @@ abstract public class FilterListItem implements Parcelable {
public void readFromParcel(Parcel source) {
listingTitle = source.readString();
icon = source.readInt();
tint = source.readInt();
source.createStringArray(); // old context menu labels
source.createTypedArray(Intent.CREATOR); // old context menu intents
}

@ -29,6 +29,7 @@ public class TagFilter extends Filter {
public TagFilter(TagData tagData) {
super(tagData.getName(), queryTemplate(tagData.getUuid()), getValuesForNewTask(tagData));
uuid = tagData.getUuid();
tint = tagData.getColor();
icon = TAG;
}

@ -27,6 +27,7 @@ import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.UserActivity;
import org.tasks.analytics.Tracker;
import org.tasks.injection.ForApplication;
import java.util.ArrayList;
@ -45,7 +46,7 @@ import timber.log.Timber;
@Singleton
public class Database {
private static final int VERSION = 35;
private static final int VERSION = 36;
private static final String NAME = "database";
private static final Table[] TABLES = new Table[] {
Task.TABLE,
@ -59,12 +60,14 @@ public class Database {
private final ArrayList<DatabaseUpdateListener> listeners = new ArrayList<>();
private final SQLiteOpenHelper helper;
private final Tracker tracker;
private SQLiteDatabase database;
// --- listeners
@Inject
public Database(@ForApplication Context context) {
public Database(@ForApplication Context context, Tracker tracker) {
this.tracker = tracker;
helper = new DatabaseHelper(context, getName(), VERSION);
}
@ -113,6 +116,14 @@ public class Database {
private boolean onUpgrade(int oldVersion, int newVersion) {
SqlConstructorVisitor visitor = new SqlConstructorVisitor();
switch(oldVersion) {
case 35:
try {
tryExecSQL(addColumnSql(TagData.TABLE, TagData.COLOR, visitor, "-1"));
} catch (SQLiteException e) {
tracker.reportException(e);
}
return true;
}
return false;

@ -9,6 +9,7 @@ package com.todoroo.astrid.data;
import android.content.ContentValues;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.data.Table;
@ -40,6 +41,9 @@ public final class TagData extends RemoteModel {
public static final StringProperty NAME = new StringProperty(
TABLE, "name");
public static final IntegerProperty COLOR = new IntegerProperty(
TABLE, "color");
/** Unixtime Project was deleted. 0 means not deleted */
@Deprecated
public static final LongProperty DELETION_DATE = new LongProperty(
@ -68,6 +72,7 @@ public final class TagData extends RemoteModel {
defaultValues.put(DELETION_DATE.name, 0);
defaultValues.put(LAST_AUTOSYNC.name, 0);
defaultValues.put(TAG_ORDERING.name, "[]");
defaultValues.put(COLOR.name, -1);
}
@Override
@ -110,6 +115,14 @@ public final class TagData extends RemoteModel {
setValue(LAST_AUTOSYNC, lastAutosync);
}
public void setColor(int color) {
setValue(COLOR, color);
}
public int getColor() {
return getValue(COLOR);
}
// TODO: remove?
public String getUUID() {
return getValue(UUID);

@ -26,11 +26,13 @@ import com.todoroo.astrid.dao.TaskAttachmentDao;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.ui.DraggableListView;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.preferences.Preferences;
import org.tasks.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import java.util.ArrayList;
@ -47,10 +49,12 @@ public class AstridOrderedListFragmentHelper<LIST> implements OrderedListFragmen
private final AstridOrderedListUpdater<LIST> updater;
private DialogBuilder dialogBuilder;
private CheckBoxes checkBoxes;
private final TagService tagService;
private final TaskListFragment fragment;
private final Preferences preferences;
private final TaskAttachmentDao taskAttachmentDao;
private final TaskService taskService;
private final ThemeCache themeCache;
private DraggableTaskAdapter taskAdapter;
@ -58,7 +62,8 @@ public class AstridOrderedListFragmentHelper<LIST> implements OrderedListFragmen
public AstridOrderedListFragmentHelper(Preferences preferences, TaskAttachmentDao taskAttachmentDao,
TaskService taskService, TaskListFragment fragment,
AstridOrderedListUpdater<LIST> updater, DialogBuilder dialogBuilder, CheckBoxes checkBoxes) {
AstridOrderedListUpdater<LIST> updater, DialogBuilder dialogBuilder,
CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) {
this.preferences = preferences;
this.taskAttachmentDao = taskAttachmentDao;
this.taskService = taskService;
@ -66,6 +71,8 @@ public class AstridOrderedListFragmentHelper<LIST> implements OrderedListFragmen
this.updater = updater;
this.dialogBuilder = dialogBuilder;
this.checkBoxes = checkBoxes;
this.tagService = tagService;
this.themeCache = themeCache;
}
// --- ui component setup
@ -177,7 +184,8 @@ public class AstridOrderedListFragmentHelper<LIST> implements OrderedListFragmen
public TaskAdapter createTaskAdapter(Context context, TodorooCursor<Task> cursor,
AtomicReference<String> sqlQueryTemplate) {
taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor, sqlQueryTemplate, dialogBuilder, checkBoxes);
taskAdapter = new DraggableTaskAdapter(context, preferences, fragment, cursor,
sqlQueryTemplate, dialogBuilder, checkBoxes, tagService, themeCache);
taskAdapter.addOnCompletedTaskListener(new OnCompletedTaskListener() {
@Override
@ -192,8 +200,9 @@ public class AstridOrderedListFragmentHelper<LIST> implements OrderedListFragmen
private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(Context context, Preferences preferences, TaskListFragment activity,
Cursor c, AtomicReference<String> query, DialogBuilder dialogBuilder, CheckBoxes checkBoxes) {
super(context, preferences, taskAttachmentDao, taskService, activity, c, query, null, dialogBuilder, checkBoxes);
Cursor c, AtomicReference<String> query, DialogBuilder dialogBuilder,
CheckBoxes checkBoxes, TagService tagService, ThemeCache themeCache) {
super(context, preferences, taskAttachmentDao, taskService, activity, c, query, null, dialogBuilder, checkBoxes, tagService, themeCache);
}
@Override

@ -23,12 +23,14 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.gtasks.GtasksListFragment;
import com.todoroo.astrid.service.TaskService;
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.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import javax.inject.Inject;
@ -59,6 +61,8 @@ public class SubtasksListFragment extends TaskListFragment {
@Inject DialogBuilder dialogBuilder;
@Inject TaskListMetadataDao taskListMetadataDao;
@Inject CheckBoxes checkBoxes;
@Inject TagService tagService;
@Inject ThemeCache themeCache;
@Override
public void onAttach(Activity activity) {
@ -68,7 +72,8 @@ public class SubtasksListFragment extends TaskListFragment {
}
protected OrderedListFragmentHelperInterface createFragmentHelper() {
return new AstridOrderedListFragmentHelper<>(preferences, taskAttachmentDao, taskService, this, subtasksFilterUpdater, dialogBuilder, checkBoxes);
return new AstridOrderedListFragmentHelper<>(preferences, taskAttachmentDao, taskService,
this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagService, themeCache);
}
@Override

@ -22,12 +22,14 @@ import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.service.TaskService;
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.themes.ThemeCache;
import org.tasks.ui.CheckBoxes;
import javax.inject.Inject;
@ -49,6 +51,8 @@ public class SubtasksTagListFragment extends TagViewFragment {
@Inject DialogBuilder dialogBuilder;
@Inject TaskListMetadataDao taskListMetadataDao;
@Inject CheckBoxes checkBoxes;
@Inject TagService tagService;
@Inject ThemeCache themeCache;
private AstridOrderedListFragmentHelper<TaskListMetadata> helper;
@ -58,7 +62,8 @@ public class SubtasksTagListFragment extends TagViewFragment {
public void onAttach(Activity activity) {
super.onAttach(activity);
helper = new AstridOrderedListFragmentHelper<>(preferences, taskAttachmentDao, taskService, this, subtasksFilterUpdater, dialogBuilder, checkBoxes);
helper = new AstridOrderedListFragmentHelper<>(preferences, taskAttachmentDao, taskService,
this, subtasksFilterUpdater, dialogBuilder, checkBoxes, tagService, themeCache);
}
@Override

@ -14,6 +14,7 @@ import org.tasks.filters.FilterProvider;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.themes.Theme;
import org.tasks.themes.ThemeCache;
import javax.inject.Inject;
@ -29,6 +30,7 @@ public class FilterSelectionActivity extends InjectingAppCompatActivity {
@Inject FilterCounter filterCounter;
@Inject DialogBuilder dialogBuilder;
@Inject Theme theme;
@Inject ThemeCache themeCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -37,7 +39,7 @@ public class FilterSelectionActivity extends InjectingAppCompatActivity {
final boolean returnFilter = getIntent().getBooleanExtra(EXTRA_RETURN_FILTER, false);
final FilterAdapter filterAdapter = new FilterAdapter(filterProvider, filterCounter, this,
theme.getLayoutInflater(this), null, false);
null, false, theme, themeCache);
filterAdapter.populateList();
dialogBuilder.newDialog()

@ -26,6 +26,10 @@ public class Theme {
this.themeAccent = themeAccent;
}
public ThemeBase getThemeBase() {
return themeBase;
}
public int getDialogStyle() {
return themeBase.getDialogStyle();
}

@ -31,6 +31,7 @@ import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingFragment;
import org.tasks.preferences.AppearancePreferences;
import org.tasks.themes.Theme;
import org.tasks.themes.ThemeCache;
import javax.inject.Inject;
@ -64,6 +65,7 @@ public class NavigationDrawerFragment extends InjectingFragment {
@Inject FilterCounter filterCounter;
@Inject FilterProvider filterProvider;
@Inject Theme theme;
@Inject ThemeCache themeCache;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -145,7 +147,7 @@ public class NavigationDrawerFragment extends InjectingFragment {
private void setUpList() {
adapter = new FilterAdapter(filterProvider, filterCounter, getActivity(),
theme.getLayoutInflater(getContext()), mDrawerListView, true);
mDrawerListView, true, theme, themeCache);
mDrawerListView.setAdapter(adapter);
registerForContextMenu(mDrawerListView);
}

@ -9,38 +9,92 @@
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="top">
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="fill_parent"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<TextView
android:id="@+id/tag_label"
style="@style/TextAppearance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="@string/name" />
<EditText
android:id="@+id/tag_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tag_label"
android:layout_marginTop="16dp"
android:background="#00000000"
android:hint="@string/enter_tag_name"
android:imeOptions="flagNoExtractUi"
android:inputType="textCapSentences"
android:singleLine="true"
android:textColor="?attr/asTextColorHint"
android:textColorHint="?attr/asTextColorHint"
android:textSize="15sp" />
</RelativeLayout>
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
android:orientation="vertical">
<RelativeLayout style="@style/TagSettingsRow">
<TextView
android:id="@+id/tag_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:alpha="?attr/alpha_secondary"
android:text="@string/name"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp" />
<EditText
android:id="@+id/tag_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tag_label"
android:layout_marginTop="@dimen/keyline_first"
android:background="@null"
android:hint="@string/enter_tag_name"
android:imeOptions="flagNoExtractUi"
android:inputType="textCapSentences"
android:nextFocusLeft="@id/tag_name"
android:nextFocusUp="@id/tag_name"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"
android:textColorHint="?android:attr/textColorHint"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/theme_row"
style="@style/TagSettingsRow"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:id="@+id/theme_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:alpha="?attr/alpha_secondary"
android:text="@string/color"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp" />
<TextView
android:id="@+id/theme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@id/theme_label"
android:layout_marginTop="@dimen/keyline_first"
android:alpha="?attr/alpha_primary"
android:textColor="?android:attr/textColorPrimary"
android:textSize="18sp" />
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_below="@id/theme_label"
android:layout_gravity="center"
android:layout_marginTop="@dimen/keyline_first"
android:alpha="?attr/alpha_secondary"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:src="@drawable/ic_cancel_24dp"
android:tint="?attr/icon_tint" />
</RelativeLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

@ -1,107 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rowBody"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:paddingEnd="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first">
<com.todoroo.astrid.ui.CheckableImageView
android:id="@+id/completeBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:gravity="center"
android:paddingLeft="@dimen/keyline_first"
android:paddingStart="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_second"
android:paddingEnd="@dimen/keyline_second"
android:layout_centerVertical="true" />
<LinearLayout
android:id="@+id/task_row"
android:layout_toRightOf="@id/completeBox"
android:layout_toEndOf="@id/completeBox"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="horizontal"
android:gravity="center_vertical">
<!-- task name -->
<LinearLayout
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="100"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/title"
style="@style/TextAppearance.TAd_ItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
android:singleLine="true"
android:ellipsize="end" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/dueDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical" />
<TextView
android:id="@+id/tagsDisplay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
style="@style/TextAppearance.TAd_ItemDueDate"/>
</LinearLayout>
</LinearLayout>
<!-- due date -->
<LinearLayout
android:id="@+id/taskActionContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:orientation="vertical"
android:gravity="end|center_vertical">
<ImageView
android:id="@+id/taskActionIcon"
android:layout_width="20dip"
android:layout_height="20dip"
android:scaleType="fitCenter"
android:visibility="gone"
tools:ignore="ContentDescription" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<View style="@style/horizontal_divider" />
<RelativeLayout
android:id="@+id/rowBody"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dip"
android:layout_marginTop="5dip">
<com.todoroo.astrid.ui.CheckableImageView
android:id="@+id/completeBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:gravity="center"
android:paddingEnd="@dimen/keyline_second"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_second"
android:paddingStart="@dimen/keyline_first"
android:scaleType="center" />
<LinearLayout
android:id="@+id/task_row"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/completeBox"
android:layout_toRightOf="@id/completeBox"
android:gravity="center_vertical"
android:orientation="vertical">
<!-- row 1 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
style="@style/TextAppearance.TAd_ItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:paddingEnd="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:singleLine="true" />
<LinearLayout
android:id="@+id/taskActionContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end|center_vertical"
android:orientation="vertical"
android:paddingEnd="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:visibility="gone">
<ImageView
android:id="@+id/taskActionIcon"
android:layout_width="24dp"
android:layout_height="24dp"
android:scaleType="fitCenter"
tools:ignore="ContentDescription" />
</LinearLayout>
</LinearLayout>
<!-- row 2 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/due_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:ellipsize="end"
android:gravity="center_vertical"
android:paddingEnd="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:singleLine="true" />
<TextView
android:id="@+id/tag_block"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:ellipsize="none"
android:maxLines="1"
android:paddingEnd="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:singleLine="true"
android:textColor="@android:color/white" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<View style="@style/horizontal_divider" />
</LinearLayout>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="tag_characters" format="float" type="dimen">16</item>
</resources>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="tag_characters" format="float" type="dimen">20</item>
</resources>

@ -15,6 +15,8 @@
<dimen name="task_edit_drawable_padding_top_bottom">17dp</dimen>
<dimen name="task_edit_text_size">16sp</dimen>
<item name="tag_characters" format="float" type="dimen">12</item>
<item name="alpha_primary_light" format="float" type="dimen">0.87</item>
<item name="alpha_secondary_light" format="float" type="dimen">0.54</item>
<item name="alpha_disabled_light" format="float" type="dimen">0.38</item>

@ -1,4 +1,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- ========================================================== General -->
@ -30,17 +31,18 @@
<item name="colorControlHighlight">#3fff</item>
</style>
<style name="TagSettingsRow">
<item name="android:padding">@dimen/keyline_first</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
<style name="WidgetConfigRow">
<item name="android:paddingLeft">@dimen/keyline_first</item>
<item name="android:paddingStart">@dimen/keyline_first</item>
<item name="android:paddingRight">@dimen/keyline_first</item>
<item name="android:paddingEnd">@dimen/keyline_first</item>
<item name="android:padding">@dimen/keyline_first</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">?attr/selectableItemBackground</item>
<item name="android:textSize">18sp</item>
<item name="android:paddingTop">15dp</item>
<item name="android:paddingBottom">15dp</item>
</style>
<style name="WidgetConfigRow.CheckBox">

Loading…
Cancel
Save