diff --git a/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CRectFEvaluator.java b/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CRectFEvaluator.java deleted file mode 100644 index 468d295b7..000000000 --- a/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CRectFEvaluator.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * Copyright 2015 Vikram Kakkar - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.appeaser.sublimepickerlibrary.drawables; - -import android.animation.TypeEvaluator; -import android.graphics.RectF; - -/** - * This evaluator can be used to perform type interpolation between RectF values. - * It is a modified version of 'RectEvaluator' - */ -public class CRectFEvaluator implements TypeEvaluator { - - /** - * When null, a new Rect is returned on every evaluate call. When non-null, - * mRect will be modified and returned on every evaluate. - */ - private RectF mRectF; - - /** - * Construct a RectEvaluator that returns a new Rect on every evaluate call. - * To avoid creating an object for each evaluate call, - * {@link CRectFEvaluator#CRectFEvaluator(RectF)} should be used - * whenever possible. - */ - public CRectFEvaluator() { - } - - /** - * Constructs a RectEvaluator that modifies and returns reuseRect - * in #evaluate(float, android.graphics.RectF, android.graphics.Rect) calls. - * The value returned from - * #evaluate(float, android.graphics.RectF, android.graphics.Rect) should - * not be cached because it will change over time as the object is reused on each - * call. - * - * @param reuseRect A Rect to be modified and returned by evaluate. - */ - public CRectFEvaluator(RectF reuseRect) { - mRectF = reuseRect; - } - - /** - * This function returns the result of linearly interpolating the start and - * end Rect values, with fraction representing the proportion - * between the start and end values. The calculation is a simple parametric - * calculation on each of the separate components in the Rect objects - * (left, top, right, and bottom). - *

If #CRectFEvaluator(android.graphics.Rect) was used to construct - * this RectEvaluator, the object returned will be the reuseRect - * passed into the constructor.

- * - * @param fraction The fraction from the starting to the ending values - * @param startValue The start Rect - * @param endValue The end Rect - * @return A linear interpolation between the start and end values, given the - * fraction parameter. - */ - @Override - public RectF evaluate(float fraction, RectF startValue, RectF endValue) { - float left = startValue.left + (endValue.left - startValue.left) * fraction; - float top = startValue.top + (endValue.top - startValue.top) * fraction; - float right = startValue.right + (endValue.right - startValue.right) * fraction; - float bottom = startValue.bottom + (endValue.bottom - startValue.bottom) * fraction; - if (mRectF == null) { - return new RectF(left, top, right, bottom); - } else { - mRectF.set(left, top, right, bottom); - return mRectF; - } - } -} diff --git a/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CheckableDrawable.java b/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CheckableDrawable.java deleted file mode 100644 index 93ef9f48c..000000000 --- a/app/src/main/java/com/appeaser/sublimepickerlibrary/drawables/CheckableDrawable.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2015 Vikram Kakkar - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.appeaser.sublimepickerlibrary.drawables; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.view.animation.AnticipateInterpolator; -import android.view.animation.OvershootInterpolator; - -/** - * Provides animated transition between 'on' and 'off' state. - * Used as background for 'WeekButton'. - */ -public class CheckableDrawable extends Drawable { - - private final int ANIMATION_DURATION_EXPAND = 500, ANIMATION_DURATION_COLLAPSE = 400; - private int mMinAlpha, mMaxAlpha; - private Paint mPaint; - - private AnimatorSet asTransition; - private final OvershootInterpolator mExpandInterpolator = new OvershootInterpolator(); - private final AnticipateInterpolator mCollapseInterpolator = new AnticipateInterpolator(); - private final CRectFEvaluator mRectEvaluator = new CRectFEvaluator(); - - private RectF mRectToDraw, mCollapsedRect, mExpandedRect; - private int mExpandedWidthHeight; - - private boolean mChecked, mReady; - - public CheckableDrawable(int color, boolean checked, int expandedWidthHeight) { - mChecked = checked; - mExpandedWidthHeight = expandedWidthHeight; - - mMaxAlpha = Color.alpha(color); - // Todo: Provide an option to change this value - mMinAlpha = 0; - - mRectToDraw = new RectF(); - mExpandedRect = new RectF(); - mCollapsedRect = new RectF(); - mPaint = new Paint(); - mPaint.setColor(color); - mPaint.setAlpha(mMaxAlpha); - mPaint.setAntiAlias(true); - mPaint.setStyle(Paint.Style.FILL); - } - - // initialize dimensions - private void setDimens(int width, int height) { - mReady = true; - - float expandedLeft = (width - mExpandedWidthHeight) / 2f; - float expandedTop = (height - mExpandedWidthHeight) / 2f; - float expandedRight = (width + mExpandedWidthHeight) / 2f; - float expandedBottom = (height + mExpandedWidthHeight) / 2f; - - float collapsedLeft = width / 2f; - float collapsedTop = height / 2f; - float collapsedRight = width / 2f; - float collapsedBottom = height / 2f; - - mCollapsedRect = new RectF(collapsedLeft, collapsedTop, - collapsedRight, collapsedBottom); - mExpandedRect = new RectF(expandedLeft, expandedTop, - expandedRight, expandedBottom); - - reset(); - } - - // Called when 'WeekButton' checked state changes - public void setCheckedOnClick(boolean checked, final OnAnimationDone callback) { - mChecked = checked; - if (!mReady) { - invalidateSelf(); - return; - } - reset(); - onClick(callback); - } - - private void onClick(final OnAnimationDone callback) { - animate(mChecked, callback); - } - - private void cancelAnimationInTracks() { - if (asTransition != null && asTransition.isRunning()) { - asTransition.cancel(); - } - } - - // Set state without animation - public void setChecked(boolean checked) { - if (mChecked == checked) - return; - - mChecked = checked; - reset(); - } - - private void reset() { - cancelAnimationInTracks(); - - if (mChecked) { - mRectToDraw.set(mExpandedRect); - } else { - mRectToDraw.set(mCollapsedRect); - } - - invalidateSelf(); - } - - // Animate between 'on' & 'off' state - private void animate(boolean expand, final OnAnimationDone callback) { - RectF from = expand ? mCollapsedRect : mExpandedRect; - RectF to = expand ? mExpandedRect : mCollapsedRect; - - mRectToDraw.set(from); - - ObjectAnimator oaTransition = ObjectAnimator.ofObject(this, - "newRectBounds", - mRectEvaluator, from, to); - - int duration = expand ? - ANIMATION_DURATION_EXPAND : - ANIMATION_DURATION_COLLAPSE; - - oaTransition.setDuration(duration); - oaTransition.setInterpolator(expand ? - mExpandInterpolator : - mCollapseInterpolator); - - ObjectAnimator oaAlpha = ObjectAnimator.ofInt(this, - "alpha", - expand ? mMinAlpha : mMaxAlpha, - expand ? mMaxAlpha : mMinAlpha); - oaAlpha.setDuration(duration); - - asTransition = new AnimatorSet(); - asTransition.playTogether(oaTransition, oaAlpha); - - asTransition.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - - if (callback != null) { - callback.animationIsDone(); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - - if (callback != null) { - callback.animationHasBeenCancelled(); - } - } - }); - - asTransition.start(); - } - - @Override - public void draw(Canvas canvas) { - if (!mReady) { - setDimens(getBounds().width(), getBounds().height()); - return; - } - - canvas.drawOval(mRectToDraw, mPaint); - } - - @Override - public void setAlpha(int alpha) { - mPaint.setAlpha(alpha); - } - - @Override - public void setColorFilter(ColorFilter cf) { - - } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } - - // ObjectAnimator property - @SuppressWarnings("unused") - public void setNewRectBounds(RectF newRectBounds) { - mRectToDraw = newRectBounds; - invalidateSelf(); - } - - // Callback - public interface OnAnimationDone { - void animationIsDone(); - - void animationHasBeenCancelled(); - } -} diff --git a/app/src/main/java/com/appeaser/sublimepickerlibrary/recurrencepicker/WeekButton.java b/app/src/main/java/com/appeaser/sublimepickerlibrary/recurrencepicker/WeekButton.java deleted file mode 100644 index f303a606c..000000000 --- a/app/src/main/java/com/appeaser/sublimepickerlibrary/recurrencepicker/WeekButton.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * Copyright 2015 Vikram Kakkar - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.appeaser.sublimepickerlibrary.recurrencepicker; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.widget.ToggleButton; - -import com.appeaser.sublimepickerlibrary.drawables.CheckableDrawable; - -public class WeekButton extends ToggleButton { - - private static int mDefaultTextColor, mCheckedTextColor; - - // Drawable that provides animations between - // 'on' & 'off' states - private CheckableDrawable mDrawable; - - // Flag to disable animation on state change - private boolean noAnimate = false; - - public WeekButton(Context context) { - super(context); - } - - public WeekButton(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public WeekButton(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - // Syncs state - private CheckableDrawable.OnAnimationDone mCallback = new CheckableDrawable.OnAnimationDone() { - @Override - public void animationIsDone() { - setTextColor(isChecked() ? mCheckedTextColor : mDefaultTextColor); - mDrawable.setChecked(isChecked()); - } - - @Override - public void animationHasBeenCancelled() { - setTextColor(isChecked() ? mCheckedTextColor : mDefaultTextColor); - mDrawable.setChecked(isChecked()); - } - }; - - // Wrapper for 'setChecked(boolean)' that does not trigger - // state-animation - public void setCheckedNoAnimate(boolean checked) { - noAnimate = true; - setChecked(checked); - noAnimate = false; - } - - @Override - public void setChecked(final boolean checked) { - super.setChecked(checked); - - if (mDrawable != null) { - if (noAnimate) { - mDrawable.setChecked(checked); - setTextColor(isChecked() ? mCheckedTextColor : mDefaultTextColor); - } else { - // Reset text color for animation - // The correct state color will be - // set when animation is done or cancelled - setTextColor(mCheckedTextColor); - mDrawable.setCheckedOnClick(isChecked(), mCallback); - } - } - } - - @Override - public void setBackgroundDrawable(Drawable d) { - super.setBackgroundDrawable(d); - - if (d instanceof CheckableDrawable) { - mDrawable = (CheckableDrawable) d; - } else { - // Reset: in case setBackgroundDrawable - // is called more than once - mDrawable = null; - } - } - - // State-dependent text-colors - public static void setStateColors(int defaultColor, int checkedColor) { - mDefaultTextColor = defaultColor; - mCheckedTextColor = checkedColor; - } -} diff --git a/app/src/main/java/org/tasks/repeats/CustomRecurrenceDialog.java b/app/src/main/java/org/tasks/repeats/CustomRecurrenceDialog.java index 135c79051..c42730278 100644 --- a/app/src/main/java/org/tasks/repeats/CustomRecurrenceDialog.java +++ b/app/src/main/java/org/tasks/repeats/CustomRecurrenceDialog.java @@ -5,6 +5,11 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.StateListDrawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -20,9 +25,8 @@ import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Spinner; import android.widget.TextView; +import android.widget.ToggleButton; -import com.appeaser.sublimepickerlibrary.drawables.CheckableDrawable; -import com.appeaser.sublimepickerlibrary.recurrencepicker.WeekButton; import com.google.common.base.Strings; import com.google.ical.values.Frequency; import com.google.ical.values.RRule; @@ -39,8 +43,6 @@ import org.tasks.injection.ForActivity; import org.tasks.injection.InjectingDialogFragment; import org.tasks.locale.Locale; import org.tasks.preferences.ResourceResolver; -import org.tasks.themes.Theme; -import org.tasks.themes.ThemeAccent; import org.tasks.time.DateTime; import java.text.DateFormatSymbols; @@ -95,18 +97,17 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { @Inject @ForActivity Context context; @Inject DialogBuilder dialogBuilder; - @Inject Theme theme; @Inject Locale locale; @BindView(R.id.weekGroup) LinearLayout weekGroup1; @BindView(R.id.weekGroup2) @Nullable LinearLayout weekGroup2; - @BindView(R.id.week_day_1) WeekButton day1; - @BindView(R.id.week_day_2) WeekButton day2; - @BindView(R.id.week_day_3) WeekButton day3; - @BindView(R.id.week_day_4) WeekButton day4; - @BindView(R.id.week_day_5) WeekButton day5; - @BindView(R.id.week_day_6) WeekButton day6; - @BindView(R.id.week_day_7) WeekButton day7; + @BindView(R.id.week_day_1) ToggleButton day1; + @BindView(R.id.week_day_2) ToggleButton day2; + @BindView(R.id.week_day_3) ToggleButton day3; + @BindView(R.id.week_day_4) ToggleButton day4; + @BindView(R.id.week_day_5) ToggleButton day5; + @BindView(R.id.week_day_6) ToggleButton day6; + @BindView(R.id.week_day_7) ToggleButton day7; @BindView(R.id.month_group) RadioGroup monthGroup; @BindView(R.id.repeat_monthly_same_day) RadioButton repeatMonthlySameDay; @@ -122,17 +123,18 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { private final List repeatUntilOptions = new ArrayList<>(); private ArrayAdapter repeatUntilAdapter; - private WeekButton[] weekButtons; + private ToggleButton[] weekButtons; private RRule rrule; @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - LayoutInflater inflater = LayoutInflater.from(getActivity()); + LayoutInflater inflater = LayoutInflater.from(context); View dialogView = inflater.inflate(R.layout.control_set_repeat, null); Bundle arguments = getArguments(); + long dueDate = arguments.getLong(EXTRA_DATE, currentTimeMillis()); String rule = savedInstanceState == null ? arguments.getString(EXTRA_RRULE) : savedInstanceState.getString(EXTRA_RRULE); @@ -155,7 +157,7 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { ButterKnife.bind(this, dialogView); Calendar dayOfMonthCalendar = Calendar.getInstance(locale.getLocale()); - dayOfMonthCalendar.setTimeInMillis(arguments.getLong(EXTRA_DATE, currentTimeMillis())); + dayOfMonthCalendar.setTimeInMillis(dueDate); int dayOfWeekInMonth = dayOfMonthCalendar.get(Calendar.DAY_OF_WEEK_IN_MONTH); int maxDayOfWeekInMonth = dayOfMonthCalendar.getActualMaximum(Calendar.DAY_OF_WEEK_IN_MONTH); @@ -234,49 +236,60 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { repeatUntilSpinner.setAdapter(repeatUntilAdapter); updateRepeatUntilOptions(); - weekButtons = new WeekButton[] { day1, day2, day3, day4, day5, day6, day7 }; - int expandedWidthHeight = getResources() - .getDimensionPixelSize(R.dimen.week_button_state_on_circle_size); - - int weekButtonUnselectedTextColor = getColor(context, R.color.text_primary); - int weekButtonSelectedTextColor = ResourceResolver.getData(context, R.attr.fab_text); - WeekButton.setStateColors(weekButtonUnselectedTextColor, weekButtonSelectedTextColor); + weekButtons = new ToggleButton[] { day1, day2, day3, day4, day5, day6, day7 }; // set up days of week - ThemeAccent accent = theme.getThemeAccent(); Calendar dayOfWeekCalendar = Calendar.getInstance(locale.getLocale()); dayOfWeekCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeekCalendar.getFirstDayOfWeek()); + WeekdayNum todayWeekday = new WeekdayNum(0, new DateTime(dueDate).getWeekday()); + + ColorStateList colorStateList = new ColorStateList(new int[][]{ + new int[]{android.R.attr.state_checked}, + new int[]{-android.R.attr.state_checked} + }, new int[]{ + ResourceResolver.getData(context, R.attr.fab_text), + getColor(context, R.color.text_primary) + }); + int inset = (int) context.getResources().getDimension(R.dimen.week_button_inset); + int accentColor = ResourceResolver.getData(context, R.attr.colorAccent); + for(int i = 0; i < 7; i++) { - int index = i; + GradientDrawable ovalDrawable = (GradientDrawable) context.getResources().getDrawable(R.drawable.week_day_button_oval).mutate(); + ovalDrawable.setColor(accentColor); + LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{ovalDrawable}); + layerDrawable.setLayerInset(0, inset, inset, inset, inset); + int dayOfWeek = dayOfWeekCalendar.get(Calendar.DAY_OF_WEEK); + ToggleButton weekButton = weekButtons[i]; + ((StateListDrawable) weekButton.getBackground()) + .addState(new int[] {android.R.attr.state_checked}, layerDrawable); String text = shortWeekdays[dayOfWeek]; - WeekdayNum weekdayNum = new WeekdayNum(0, calendarDayToWeekday(dayOfWeek)); - WeekButton weekButton = weekButtons[i]; - weekButton.setTag(weekdayNum); - weekButton.setBackgroundDrawable(new CheckableDrawable(accent.getAccentColor(), false, expandedWidthHeight)); - weekButton.setTextColor(weekButtonUnselectedTextColor); - weekButton.setTextOff(text); + weekButton.setTextColor(colorStateList); weekButton.setTextOn(text); - weekButton.setText(text); + weekButton.setTextOff(text); + weekButton.setTag(new WeekdayNum(0, calendarDayToWeekday(dayOfWeek))); if (savedInstanceState == null) { - weekButton.setCheckedNoAnimate(rrule.getByDay().contains(weekdayNum)); + weekButton.setChecked(rrule.getFreq() != WEEKLY || rrule.getByDay().isEmpty() + ? todayWeekday.equals(weekButton.getTag()) + : rrule.getByDay().contains(weekButton.getTag())); } dayOfWeekCalendar.add(Calendar.DATE, 1); } + setCancelable(false); + return dialogBuilder.newDialog() .setView(dialogView) .setPositiveButton(android.R.string.ok, this::onRuleSelected) .setNegativeButton(android.R.string.cancel, null) - .setOnCancelListener(DialogInterface::dismiss) .show(); } private void onRuleSelected(DialogInterface dialogInterface, int which) { if (rrule.getFreq() == WEEKLY) { List checked = new ArrayList<>(); - for (WeekButton weekButton : weekButtons) { + for (ToggleButton weekButton : weekButtons) { if (weekButton.isChecked()) { checked.add((WeekdayNum) weekButton.getTag()); } @@ -298,6 +311,7 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { rrule.setByDay(Collections.emptyList()); } ((CustomRecurrenceCallback) getTargetFragment()).onSelected(rrule); + dismiss(); } private Weekday calendarDayToWeekday(int calendarDay) { @@ -320,15 +334,6 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment { throw new RuntimeException("Invalid calendar day: " + calendarDay); } - @Override - public void onResume() { - super.onResume(); - - for (WeekButton weekButton : weekButtons) { - weekButton.setCheckedNoAnimate(weekButton.isChecked()); - } - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/app/src/main/res/drawable/week_button_bg.xml b/app/src/main/res/drawable/week_button_bg.xml new file mode 100644 index 000000000..fb64159e0 --- /dev/null +++ b/app/src/main/res/drawable/week_button_bg.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/week_day_button_oval.xml b/app/src/main/res/drawable/week_day_button_oval.xml new file mode 100644 index 000000000..f0de65456 --- /dev/null +++ b/app/src/main/res/drawable/week_day_button_oval.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/layout/control_set_repeat.xml b/app/src/main/res/layout/control_set_repeat.xml index 3900b676f..ad340d4c8 100644 --- a/app/src/main/res/layout/control_set_repeat.xml +++ b/app/src/main/res/layout/control_set_repeat.xml @@ -1,7 +1,7 @@ - + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index ed644d67e..c821631f0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -6,6 +6,8 @@ --> + @android:color/transparent + #f44336 #d32f2f #ff1744 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 362310978..035d44786 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -23,5 +23,6 @@ 0dp 10dp + 6dp 48dp \ No newline at end of file