Use material checkboxes

pull/384/head
Alex Baker 9 years ago
parent c2918d1722
commit 70ba717d65

@ -11,7 +11,6 @@ import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
@ -20,8 +19,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.CursorAdapter;
import android.widget.Filterable;
import android.widget.ImageView;
@ -51,6 +48,7 @@ import com.todoroo.astrid.ui.CheckableImageView;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.preferences.ActivityPreferences;
import org.tasks.ui.CheckBoxes;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicReference;
@ -95,41 +93,9 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
FILE_ID_PROPERTY // File id
};
public static final int[] IMPORTANCE_RESOURCES = new int[] {
R.drawable.check_box_1,
R.drawable.check_box_2,
R.drawable.check_box_3,
R.drawable.check_box_4,
};
public static final int[] IMPORTANCE_RESOURCES_CHECKED = new int[] {
R.drawable.check_box_checked_1,
R.drawable.check_box_checked_2,
R.drawable.check_box_checked_3,
R.drawable.check_box_checked_4,
};
public static final int[] IMPORTANCE_REPEAT_RESOURCES = new int[] {
R.drawable.check_box_repeat_1,
R.drawable.check_box_repeat_2,
R.drawable.check_box_repeat_3,
R.drawable.check_box_repeat_4,
};
public static final int[] IMPORTANCE_REPEAT_RESOURCES_CHECKED = new int[] {
R.drawable.check_box_repeat_checked_1,
R.drawable.check_box_repeat_checked_2,
R.drawable.check_box_repeat_checked_3,
R.drawable.check_box_repeat_checked_4,
};
public static final Drawable[] IMPORTANCE_DRAWABLES = new Drawable[IMPORTANCE_RESOURCES.length];
public static final Drawable[] IMPORTANCE_DRAWABLES_CHECKED = new Drawable[IMPORTANCE_RESOURCES_CHECKED.length];
public static final Drawable[] IMPORTANCE_REPEAT_DRAWABLES = new Drawable[IMPORTANCE_REPEAT_RESOURCES.length];
public static final Drawable[] IMPORTANCE_REPEAT_DRAWABLES_CHECKED = new Drawable[IMPORTANCE_REPEAT_RESOURCES_CHECKED.length];
// --- instance variables
private final CheckBoxes checkBoxes;
private final ActivityPreferences preferences;
private final TaskAttachmentDao taskAttachmentDao;
private final TaskService taskService;
@ -141,7 +107,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
protected OnCompletedTaskListener onCompletedTaskListener = null;
protected final LayoutInflater inflater;
private int fontSize;
private final ScaleAnimation scaleAnimation;
private final AtomicReference<String> query;
@ -155,6 +120,7 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
Cursor c, AtomicReference<String> query, OnCompletedTaskListener onCompletedTaskListener,
DialogBuilder dialogBuilder) {
super(context, c, false);
this.checkBoxes = new CheckBoxes(context);
this.preferences = preferences;
this.taskAttachmentDao = taskAttachmentDao;
this.taskService = taskService;
@ -173,21 +139,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
fragment.getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
this.minRowHeight = computeMinRowHeight();
scaleAnimation = new ScaleAnimation(1.4f, 1.0f, 1.4f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(100);
preloadDrawables(IMPORTANCE_RESOURCES, IMPORTANCE_DRAWABLES);
preloadDrawables(IMPORTANCE_RESOURCES_CHECKED, IMPORTANCE_DRAWABLES_CHECKED);
preloadDrawables(IMPORTANCE_REPEAT_RESOURCES, IMPORTANCE_REPEAT_DRAWABLES);
preloadDrawables(IMPORTANCE_REPEAT_RESOURCES_CHECKED, IMPORTANCE_REPEAT_DRAWABLES_CHECKED);
}
private void preloadDrawables(int[] resourceIds, Drawable[] drawables) {
for (int i = 0; i < resourceIds.length; i++) {
drawables[i] = resources.getDrawable(resourceIds[i]);
}
}
protected int computeMinRowHeight() {
@ -483,7 +434,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
protected final View.OnClickListener completeBoxListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int[] location = new int[2];
v.getLocationOnScreen(location);
ViewHolder viewHolder = getTagFromCheckBox(v);
@ -499,9 +449,6 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
// set check box to actual action item state
setTaskAppearance(viewHolder, task);
if (viewHolder.completeBox.getVisibility() == View.VISIBLE) {
viewHolder.completeBox.startAnimation(scaleAnimation);
}
}
};
@ -554,27 +501,20 @@ public class TaskAdapter extends CursorAdapter implements Filterable {
}
private void setupCompleteBox(ViewHolder viewHolder) {
// complete box
// complete box
final Task task = viewHolder.task;
final CheckableImageView checkBoxView = viewHolder.completeBox; {
boolean completed = task.isCompleted();
checkBoxView.setChecked(completed);
checkBoxView.setEnabled(true);
int value = task.getImportance();
if (value >= IMPORTANCE_RESOURCES.length) {
value = IMPORTANCE_RESOURCES.length - 1;
}
Drawable[] boxes;
if (!TextUtils.isEmpty(task.getRecurrence())) {
boxes = completed ? IMPORTANCE_REPEAT_DRAWABLES_CHECKED : IMPORTANCE_REPEAT_DRAWABLES;
} else {
boxes = completed ? IMPORTANCE_DRAWABLES_CHECKED : IMPORTANCE_DRAWABLES;
}
checkBoxView.setImageDrawable(boxes[value]);
checkBoxView.setVisibility(View.VISIBLE);
final CheckableImageView checkBoxView = viewHolder.completeBox;
boolean completed = task.isCompleted();
checkBoxView.setChecked(completed);
if (completed) {
checkBoxView.setImageDrawable(checkBoxes.getCompletedCheckbox(task.getImportance()));
} else if (TextUtils.isEmpty(task.getRecurrence())) {
checkBoxView.setImageDrawable(checkBoxes.getCheckBox(task.getImportance()));
} else {
checkBoxView.setImageDrawable(checkBoxes.getRepeatingCheckBox(task.getImportance()));
}
checkBoxView.invalidate();
}
// Returns due date text width

@ -12,20 +12,19 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.helper.TaskEditControlSet;
import com.todoroo.astrid.repeats.RepeatControlSet.RepeatChangedListener;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.ui.ImportanceControlSet.ImportanceChangedListener;
import org.tasks.ui.CheckBoxes;
/**
* Control set for mapping a Property to an EditText
* @author Tim Su <tim@todoroo.com>
@ -36,12 +35,14 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange
private final EditText editText;
private CheckableImageView completeBox;
private final CheckBoxes checkBoxes;
private boolean isRepeating;
private int importanceValue;
private Task model;
private final TaskService taskService;
public EditTitleControlSet(TaskService taskService, final Activity activity, final EditText editText, CheckableImageView completeBox) {
this.checkBoxes = new CheckBoxes(activity);
this.editText = editText;
this.completeBox = completeBox;
this.taskService = taskService;
@ -81,11 +82,7 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange
completeBox.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ScaleAnimation scaleAnimation = new ScaleAnimation(1.5f, 1.0f, 1.5f, 1.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(100);
// set check box to actual action item state
completeBox.startAnimation(scaleAnimation);
updateCompleteBox();
}
});
@ -114,18 +111,13 @@ public class EditTitleControlSet implements TaskEditControlSet, ImportanceChange
private void updateCompleteBox() {
boolean checked = completeBox.isChecked();
int[] resourceArray = isRepeating ? (checked ? TaskAdapter.IMPORTANCE_REPEAT_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_REPEAT_RESOURCES)
: (checked ? TaskAdapter.IMPORTANCE_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_RESOURCES);
int valueToUse = importanceValue;
if (valueToUse >= resourceArray.length) {
valueToUse = resourceArray.length - 1;
}
if(valueToUse < resourceArray.length) {
if (isRepeating) {
completeBox.setImageResource(resourceArray[valueToUse]);
} else {
completeBox.setImageResource(resourceArray[valueToUse]);
}
if (checked) {
completeBox.setImageDrawable(checkBoxes.getCompletedCheckbox(importanceValue));
} else if (isRepeating) {
completeBox.setImageDrawable(checkBoxes.getRepeatingCheckBox(importanceValue));
} else {
completeBox.setImageDrawable(checkBoxes.getCheckBox(importanceValue));
}
if (checked) {

@ -0,0 +1,91 @@
package org.tasks.ui;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.drawable.DrawableCompat;
import org.tasks.R;
import org.tasks.injection.ForApplication;
import java.util.List;
import javax.inject.Inject;
import timber.log.Timber;
import static java.util.Arrays.asList;
public class CheckBoxes {
private static final int MAX_IMPORTANCE_INDEX = 3;
private static boolean initialized;
private static List<Drawable> checkboxes;
private static List<Drawable> repeatingCheckboxes;
private static List<Drawable> completedCheckboxes;
@Inject
public CheckBoxes(@ForApplication Context context) {
if (!initialized) {
Timber.d("Initializing checkboxes");
checkboxes = wrapDrawable(context, R.drawable.ic_check_box_outline_blank_24dp);
repeatingCheckboxes = wrapDrawable(context, R.drawable.ic_repeat_24dp);
completedCheckboxes = wrapDrawable(context, R.drawable.ic_check_box_24dp);
initialized = true;
}
}
List<Drawable> getCheckBoxes() {
return checkboxes;
}
List<Drawable> getRepeatingCheckBoxes() {
return repeatingCheckboxes;
}
List<Drawable> getCompletedCheckBoxes() {
return completedCheckboxes;
}
private static List<Drawable> wrapDrawable(Context context, int resId) {
return asList(
getDrawable(context, resId, 0),
getDrawable(context, resId, 1),
getDrawable(context, resId, 2),
getDrawable(context, resId, 3));
}
public Drawable getCompletedCheckbox(int importance) {
return completedCheckboxes.get(Math.min(importance, MAX_IMPORTANCE_INDEX));
}
public Drawable getRepeatingCheckBox(int importance) {
return repeatingCheckboxes.get(Math.min(importance, MAX_IMPORTANCE_INDEX));
}
public Drawable getCheckBox(int importance) {
return checkboxes.get(Math.min(importance, MAX_IMPORTANCE_INDEX));
}
private static Drawable getDrawable(Context context, int resId, int importance) {
Resources resources = context.getResources();
Drawable original = resources.getDrawable(resId);
Drawable wrapped = DrawableCompat.wrap(original.mutate());
DrawableCompat.setTint(wrapped, resources.getColor(getImportanceResId(importance)));
return wrapped;
}
private static int getImportanceResId(int importance) {
switch (importance) {
case 0:
return R.color.importance_1;
case 1:
return R.color.importance_2;
case 2:
return R.color.importance_3;
default:
return R.color.importance_4;
}
}
}

@ -0,0 +1,77 @@
package org.tasks.ui;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import com.google.common.base.Function;
import org.tasks.injection.ForApplication;
import java.util.List;
import javax.annotation.Nullable;
import javax.inject.Inject;
import timber.log.Timber;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
public class WidgetCheckBoxes {
private static boolean initialized;
private static List<Bitmap> checkboxes;
private static List<Bitmap> repeatingCheckboxes;
private static List<Bitmap> completedCheckboxes;
@Inject
public WidgetCheckBoxes(@ForApplication Context context) {
if (!initialized) {
CheckBoxes checkBoxes = new CheckBoxes(context);
Timber.d("Initializing widget checkboxes");
checkboxes = convertToBitmap(checkBoxes.getCheckBoxes());
repeatingCheckboxes = convertToBitmap(checkBoxes.getRepeatingCheckBoxes());
completedCheckboxes = convertToBitmap(checkBoxes.getCompletedCheckBoxes());
initialized = true;
}
}
public Bitmap getCompletedCheckbox(int importance) {
return completedCheckboxes.get(importance);
}
public Bitmap getRepeatingCheckBox(int importance) {
return repeatingCheckboxes.get(importance);
}
public Bitmap getCheckBox(int importance) {
return checkboxes.get(importance);
}
private static List<Bitmap> convertToBitmap(final List<Drawable> drawables) {
return newArrayList(transform(drawables, new Function<Drawable, Bitmap>() {
@Nullable
@Override
public Bitmap apply(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
Bitmap bitmap = drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0
? Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
: Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}));
}
}

@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.os.Build;
import android.text.TextUtils;
@ -15,7 +16,6 @@ import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.astrid.activity.TaskEditFragment;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.Database;
@ -28,12 +28,17 @@ import com.todoroo.astrid.widget.WidgetConfigActivity;
import org.tasks.R;
import org.tasks.preferences.Preferences;
import org.tasks.ui.CheckBoxes;
import org.tasks.ui.WidgetCheckBoxes;
import java.util.List;
import timber.log.Timber;
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final WidgetCheckBoxes checkBoxes;
private final Database database;
private final TaskService taskService;
private final SubtasksHelper subtasksHelper;
@ -64,6 +69,7 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
this.database = database;
this.taskService = taskService;
checkBoxes = new WidgetCheckBoxes(context);
dueDateFormatter = new DueDateFormatter(context);
dark = preferences.useDarkWidgetTheme(widgetId);
showDueDates = preferences.getBoolean(WidgetConfigActivity.PREF_SHOW_DUE_DATE + widgetId, false);
@ -117,20 +123,14 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
return true;
}
private int getCheckbox(Task task) {
boolean completed = task.isCompleted();
int value = task.getImportance();
if (value >= TaskAdapter.IMPORTANCE_RESOURCES.length) {
value = TaskAdapter.IMPORTANCE_RESOURCES.length - 1;
}
int[] boxes;
if (!TextUtils.isEmpty(task.getRecurrence())) {
boxes = completed ? TaskAdapter.IMPORTANCE_REPEAT_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_REPEAT_RESOURCES;
private Bitmap getCheckbox(Task task) {
if (task.isCompleted()) {
return checkBoxes.getCompletedCheckbox(task.getImportance());
} else if (TextUtils.isEmpty(task.getRecurrence())) {
return checkBoxes.getCheckBox(task.getImportance());
} else {
boxes = completed ? TaskAdapter.IMPORTANCE_RESOURCES_CHECKED : TaskAdapter.IMPORTANCE_RESOURCES;
return checkBoxes.getRepeatingCheckBox(task.getImportance());
}
return boxes[value];
}
public RemoteViews buildUpdate(int position) {
@ -163,7 +163,7 @@ public class ScrollableViewsFactory implements RemoteViewsService.RemoteViewsFac
row.setTextViewText(R.id.text, textContent);
row.setTextColor(R.id.text, textColor);
row.setImageViewResource(R.id.completeBox, getCheckbox(task));
row.setImageViewBitmap(R.id.completeBox, getCheckbox(task));
Intent editIntent = new Intent();
editIntent.setAction(TasksWidget.EDIT_TASK);

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.11,0 2,-0.9 2,-2V5c0,-1.1 -0.89,-2 -2,-2zm-9,14l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,5v14H5V5h14m0,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

@ -4,8 +4,8 @@
android:id="@+id/notes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="@dimen/task_edit_padding_right"
android:paddingEnd="@dimen/task_edit_padding_right"
android:paddingRight="@dimen/task_edit_drawable_padding_left_right"
android:paddingEnd="@dimen/task_edit_drawable_padding_left_right"
android:scrollbars="vertical"
android:hint="@string/TEA_note_label"
android:textColorHint="?attr/asTextColorHint"

@ -9,8 +9,8 @@
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingRight="@dimen/task_edit_padding_right"
android:paddingEnd="@dimen/task_edit_padding_right">
android:paddingRight="@dimen/task_edit_drawable_padding_left_right"
android:paddingEnd="@dimen/task_edit_drawable_padding_left_right">
<TextView
android:id="@+id/display_row_edit"

@ -11,5 +11,5 @@
android:gravity="start"
android:textColor="?attr/asThemeTextColor"
android:textSize="@dimen/task_edit_text_size"
android:paddingRight="@dimen/task_edit_padding_right"
android:paddingEnd="@dimen/task_edit_padding_right" />
android:paddingRight="@dimen/task_edit_drawable_padding_left_right"
android:paddingEnd="@dimen/task_edit_drawable_padding_left_right" />

@ -9,8 +9,10 @@
android:layout_height="wrap_content"
android:paddingTop="@dimen/task_edit_title_padding_top_bottom"
android:paddingBottom="@dimen/task_edit_title_padding_top_bottom"
android:paddingLeft="@dimen/task_edit_padding_left"
android:paddingRight="@dimen/task_edit_padding_right"
android:paddingLeft="@dimen/task_edit_drawable_padding_left_right"
android:paddingStart="@dimen/task_edit_drawable_padding_left_right"
android:paddingRight="@dimen/task_edit_drawable_padding_left_right"
android:paddingEnd="@dimen/task_edit_drawable_padding_left_right"
android:gravity="center_vertical"
android:orientation="horizontal" >

@ -12,8 +12,6 @@
<dimen name="task_edit_double_padding_top_bottom">18dp</dimen>
<dimen name="task_edit_drawable_padding_left_right">20dp</dimen>
<dimen name="task_edit_drawable_padding_top_bottom">17dp</dimen>
<dimen name="task_edit_padding_left">10dp</dimen>
<dimen name="task_edit_padding_right">10dp</dimen>
<dimen name="task_edit_text_size">16sp</dimen>
<item name="drawer_icon_alpha" format="float" type="dimen">0.54</item>
<item name="drawer_text_alpha" format="float" type="dimen">0.87</item>

Loading…
Cancel
Save