mirror of https://github.com/tasks/tasks
Google calendar style recurrence picker
parent
aaf6a5b31b
commit
156c67b01a
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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<RectF> {
|
||||
|
||||
/**
|
||||
* 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 <code>reuseRect</code>
|
||||
* 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 <code>fraction</code> 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).
|
||||
* <p>If #CRectFEvaluator(android.graphics.Rect) was used to construct
|
||||
* this RectEvaluator, the object returned will be the <code>reuseRect</code>
|
||||
* passed into the constructor.</p>
|
||||
*
|
||||
* @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
|
||||
* <code>fraction</code> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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(isChecked() ? mCheckedTextColor : mDefaultTextColor);
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package com.todoroo.astrid.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import org.tasks.R;
|
||||
|
||||
public class NumberPickerDialog extends AlertDialog implements OnClickListener {
|
||||
|
||||
public interface OnNumberPickedListener {
|
||||
void onNumberPicked(int number);
|
||||
}
|
||||
|
||||
private final NumberPicker mPicker;
|
||||
private final OnNumberPickedListener mCallback;
|
||||
|
||||
public NumberPickerDialog(Context context, OnNumberPickedListener callBack,
|
||||
String title, int initialValue, int incrementBy, int start, int end) {
|
||||
super(context);
|
||||
mCallback = callBack;
|
||||
|
||||
setButton(DialogInterface.BUTTON_POSITIVE, context.getText(android.R.string.ok), this);
|
||||
setButton(DialogInterface.BUTTON_NEGATIVE, context.getText(android.R.string.cancel), (OnClickListener) null);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View view = inflater.inflate(R.layout.number_picker_dialog, null);
|
||||
setView(view);
|
||||
|
||||
setTitle(title);
|
||||
mPicker = view.findViewById(R.id.numberPicker);
|
||||
mPicker.setIncrementBy(incrementBy);
|
||||
mPicker.setRange(start, end);
|
||||
mPicker.setCurrent(initialValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (mCallback != null) {
|
||||
mPicker.clearFocus();
|
||||
mCallback.onNumberPicked(mPicker.getCurrent());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,288 @@
|
||||
package org.tasks.repeats;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.appeaser.sublimepickerlibrary.drawables.CheckableDrawable;
|
||||
import com.appeaser.sublimepickerlibrary.recurrencepicker.WeekButton;
|
||||
import com.todoroo.astrid.repeats.RepeatControlSet;
|
||||
|
||||
import org.tasks.R;
|
||||
import org.tasks.activities.DatePickerActivity;
|
||||
import org.tasks.dialogs.DialogBuilder;
|
||||
import org.tasks.injection.DialogFragmentComponent;
|
||||
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 java.text.DateFormatSymbols;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnItemSelected;
|
||||
import butterknife.OnTextChanged;
|
||||
|
||||
import static android.support.v4.content.ContextCompat.getColor;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_DAYS;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_HOURS;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_MINUTES;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_MONTHS;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_WEEKS;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_YEARS;
|
||||
import static com.todoroo.astrid.repeats.RepeatControlSet.TYPE_COMPLETION_DATE;
|
||||
|
||||
public class CustomRecurrenceDialog extends InjectingDialogFragment {
|
||||
|
||||
public static CustomRecurrenceDialog newCustomRecurrenceDialog(Fragment target) {
|
||||
CustomRecurrenceDialog dialog = new CustomRecurrenceDialog();
|
||||
dialog.setTargetFragment(target, 0);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public interface CustomRecurrenceCallback {
|
||||
void onSelected(int frequency, int interval, long repeatUntilValue,
|
||||
boolean repeatAfterCompletion, boolean[] isChecked);
|
||||
}
|
||||
|
||||
private static final int REQUEST_PICK_DATE = 505;
|
||||
|
||||
@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.repeat_until) Spinner repeatUntilSpinner;
|
||||
@BindView(R.id.repeatType) Spinner typeSpinner;
|
||||
@BindView(R.id.frequency) Spinner frequencySpinner;
|
||||
@BindView(R.id.repeatValue) EditText intervalEditText;
|
||||
@BindView(R.id.intervalText) TextView intervalTextView;
|
||||
|
||||
private ArrayAdapter<String> repeatUntilAdapter;
|
||||
private final List<String> repeatUntilOptions = new ArrayList<>();
|
||||
private final boolean[] isChecked = new boolean[7];
|
||||
|
||||
private int frequency;
|
||||
private int interval;
|
||||
private long repeatUntilValue;
|
||||
|
||||
private boolean repeatAfterCompletion;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
LayoutInflater inflater = LayoutInflater.from(getActivity());
|
||||
View dialogView = inflater.inflate(R.layout.control_set_repeat, null);
|
||||
|
||||
ButterKnife.bind(this, dialogView);
|
||||
|
||||
ArrayAdapter<CharSequence> frequencyAdapter = ArrayAdapter.createFromResource(context, R.array.repeat_frequency, R.layout.frequency_item);
|
||||
frequencyAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
frequencySpinner.setAdapter(frequencyAdapter);
|
||||
frequencySpinner.setSelection(3);
|
||||
intervalEditText.setText(locale.formatNumber(1));
|
||||
intervalEditText.setSelectAllOnFocus(true);
|
||||
intervalEditText.selectAll();
|
||||
|
||||
ArrayAdapter<String> typeAdapter = new ArrayAdapter<>(context, R.layout.simple_spinner_item, getResources().getStringArray(R.array.repeat_type));
|
||||
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
typeSpinner.setAdapter(typeAdapter);
|
||||
|
||||
repeatUntilAdapter = new ArrayAdapter<>(context, R.layout.simple_spinner_item, repeatUntilOptions);
|
||||
repeatUntilAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
repeatUntilSpinner.setAdapter(repeatUntilAdapter);
|
||||
|
||||
setInterval(1, true);
|
||||
|
||||
setRepeatUntilValue(repeatUntilValue);
|
||||
|
||||
WeekButton[] 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);
|
||||
|
||||
// set up days of week
|
||||
ThemeAccent accent = theme.getThemeAccent();
|
||||
DateFormatSymbols dfs = new DateFormatSymbols();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
|
||||
String[] shortWeekdays = dfs.getShortWeekdays();
|
||||
for(int i = 0; i < 7; i++) {
|
||||
final int index = i;
|
||||
WeekButton weekButton = weekButtons[i];
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
String text = shortWeekdays[dayOfWeek];
|
||||
weekButton.setBackgroundDrawable(new CheckableDrawable(accent.getAccentColor(), false, expandedWidthHeight));
|
||||
weekButton.setTextColor(weekButtonUnselectedTextColor);
|
||||
weekButton.setTextOff(text);
|
||||
weekButton.setTextOn(text);
|
||||
weekButton.setText(text);
|
||||
weekButton.setOnCheckedChangeListener((compoundButton, b) -> CustomRecurrenceDialog.this.isChecked[index] = b);
|
||||
calendar.add(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
typeSpinner.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : RepeatControlSet.TYPE_DUE_DATE);
|
||||
|
||||
return dialogBuilder.newDialog()
|
||||
.setView(dialogView)
|
||||
.setPositiveButton(android.R.string.ok, (dialog12, which) ->
|
||||
((CustomRecurrenceCallback) getTargetFragment())
|
||||
.onSelected(frequency, interval, repeatUntilValue,
|
||||
repeatAfterCompletion, isChecked))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setOnCancelListener(DialogInterface::dismiss)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void setInterval(int interval, boolean updateEditText) {
|
||||
this.interval = interval;
|
||||
if (updateEditText) {
|
||||
intervalEditText.setText(locale.formatNumber(interval));
|
||||
}
|
||||
updateIntervalTextView();
|
||||
}
|
||||
|
||||
private void updateIntervalTextView() {
|
||||
int resource = getFrequencyPlural();
|
||||
String quantityString = getResources().getQuantityString(resource, interval);
|
||||
intervalTextView.setText(quantityString);
|
||||
}
|
||||
|
||||
private int getFrequencyPlural() {
|
||||
switch (frequency) {
|
||||
case FREQUENCY_MINUTES:
|
||||
return R.plurals.repeat_minutes;
|
||||
case FREQUENCY_HOURS:
|
||||
return R.plurals.repeat_hours;
|
||||
case FREQUENCY_DAYS:
|
||||
return R.plurals.repeat_days;
|
||||
case FREQUENCY_WEEKS:
|
||||
return R.plurals.repeat_weeks;
|
||||
case FREQUENCY_MONTHS:
|
||||
return R.plurals.repeat_months;
|
||||
case FREQUENCY_YEARS:
|
||||
return R.plurals.repeat_years;
|
||||
default:
|
||||
throw new RuntimeException("Invalid frequency: " + frequency);
|
||||
}
|
||||
}
|
||||
|
||||
@OnItemSelected(R.id.repeatType)
|
||||
public void onRepeatTypeChanged(Spinner spinner, int position) {
|
||||
repeatAfterCompletion = position == TYPE_COMPLETION_DATE;
|
||||
}
|
||||
|
||||
@OnItemSelected(R.id.repeat_until)
|
||||
public void onRepeatUntilChanged(Spinner spinner, int position) {
|
||||
if (repeatUntilOptions.size() == 2) {
|
||||
if (position == 0) {
|
||||
setRepeatUntilValue(0);
|
||||
} else {
|
||||
repeatUntilClick();
|
||||
}
|
||||
} else {
|
||||
if (position == 1) {
|
||||
setRepeatUntilValue(0);
|
||||
} else if (position == 2) {
|
||||
repeatUntilClick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnItemSelected(R.id.frequency)
|
||||
public void onFrequencyChanged(Spinner spinner, int position) {
|
||||
int weekVisibility = position == RepeatControlSet.FREQUENCY_WEEKS ? View.VISIBLE : View.GONE;
|
||||
weekGroup1.setVisibility(weekVisibility);
|
||||
if (weekGroup2 != null) {
|
||||
weekGroup2.setVisibility(weekVisibility);
|
||||
}
|
||||
frequency = position;
|
||||
updateIntervalTextView();
|
||||
}
|
||||
|
||||
@OnTextChanged(R.id.repeatValue)
|
||||
public void onRepeatValueChanged(CharSequence text) {
|
||||
Integer value = locale.parseInteger(text.toString());
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (value < 1) {
|
||||
setInterval(1, true);
|
||||
} else {
|
||||
setInterval(value, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRepeatUntilValue(long newValue) {
|
||||
repeatUntilValue = newValue;
|
||||
updateRepeatUntilOptions();
|
||||
}
|
||||
|
||||
private void repeatUntilClick() {
|
||||
Intent intent = new Intent(context, DatePickerActivity.class);
|
||||
intent.putExtra(DatePickerActivity.EXTRA_TIMESTAMP, repeatUntilValue > 0 ? repeatUntilValue : 0L);
|
||||
startActivityForResult(intent, REQUEST_PICK_DATE);
|
||||
}
|
||||
|
||||
private void updateRepeatUntilOptions() {
|
||||
repeatUntilOptions.clear();
|
||||
if (repeatUntilValue > 0) {
|
||||
repeatUntilOptions.add(getString(R.string.repeat_until, RepeatControlSet.getDisplayString(context, repeatUntilValue)));
|
||||
}
|
||||
repeatUntilOptions.add(getString(R.string.repeat_forever));
|
||||
repeatUntilOptions.add(getString(R.string.repeat_until, "").trim());
|
||||
repeatUntilAdapter.notifyDataSetChanged();
|
||||
repeatUntilSpinner.setSelection(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_PICK_DATE) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
setRepeatUntilValue(data.getLongExtra(DatePickerActivity.EXTRA_TIMESTAMP, 0L));
|
||||
} else {
|
||||
setRepeatUntilValue(repeatUntilValue);
|
||||
}
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void inject(DialogFragmentComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 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.
|
||||
-->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/weekGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_1"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_2"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_3"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_4"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_5"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_6"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_7"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@style/Widget.AppCompat.TextView.SpinnerItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:ellipsize="end"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingTop="12dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="?fab_text" />
|
@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="5dip">
|
||||
<com.todoroo.astrid.ui.NumberPicker android:id="@+id/numberPicker"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
</FrameLayout>
|
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
|
||||
**
|
||||
** Copyright 2006, The Android Open Source Project
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
-->
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
style="?android:attr/spinnerItemStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingStart="0dp"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="inherit" />
|
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 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.
|
||||
-->
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/weekGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_1"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_2"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_3"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_4"
|
||||
layout="@layout/week_day_button" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/weekGroup2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_5"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_6"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:id="@+id/week_day_7"
|
||||
layout="@layout/week_day_button" />
|
||||
|
||||
<include
|
||||
android:visibility="invisible"
|
||||
layout="@layout/week_day_button" />
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 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.
|
||||
-->
|
||||
<com.appeaser.sublimepickerlibrary.recurrencepicker.WeekButton
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="12sp"
|
||||
android:singleLine="true"
|
||||
android:gravity="center" />
|
Loading…
Reference in New Issue