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