Google calendar style recurrence picker

pull/574/head
Alex Baker 7 years ago
parent aaf6a5b31b
commit 156c67b01a

@ -8,6 +8,7 @@ import org.tasks.dialogs.SortDialog;
import org.tasks.reminders.MissedCallDialog;
import org.tasks.reminders.NotificationDialog;
import org.tasks.reminders.SnoozeDialog;
import org.tasks.repeats.CustomRecurrenceDialog;
import dagger.Subcomponent;
@ -28,4 +29,6 @@ public interface DialogFragmentComponent {
void inject(ColorPickerDialog colorPickerDialog);
void inject(RecordAudioDialog recordAudioDialog);
void inject(CustomRecurrenceDialog customRecurrenceDialog);
}

@ -8,6 +8,7 @@ import org.tasks.dialogs.SortDialog;
import org.tasks.reminders.MissedCallDialog;
import org.tasks.reminders.NotificationDialog;
import org.tasks.reminders.SnoozeDialog;
import org.tasks.repeats.CustomRecurrenceDialog;
import dagger.Subcomponent;
@ -28,4 +29,6 @@ public interface DialogFragmentComponent {
void inject(ColorPickerDialog colorPickerDialog);
void inject(RecordAudioDialog recordAudioDialog);
void inject(CustomRecurrenceDialog customRecurrenceDialog);
}

@ -12,6 +12,7 @@ import org.tasks.gtasks.RenameListDialog;
import org.tasks.reminders.MissedCallDialog;
import org.tasks.reminders.NotificationDialog;
import org.tasks.reminders.SnoozeDialog;
import org.tasks.repeats.CustomRecurrenceDialog;
import dagger.Subcomponent;
@ -41,4 +42,6 @@ public interface DialogFragmentComponent {
void inject(DeleteListDialog deleteListDialog);
void inject(RenameListDialog renameListDialog);
void inject(CustomRecurrenceDialog customRecurrenceDialog);
}

@ -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;
}
}

@ -7,23 +7,12 @@ package com.todoroo.astrid.repeats;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import com.google.common.base.Strings;
@ -33,19 +22,19 @@ import com.google.ical.values.Weekday;
import com.google.ical.values.WeekdayNum;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.ui.NumberPickerDialog;
import org.tasks.R;
import org.tasks.activities.DatePickerActivity;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.preferences.Preferences;
import org.tasks.repeats.CustomRecurrenceDialog;
import org.tasks.themes.Theme;
import org.tasks.time.DateTime;
import org.tasks.ui.SingleCheckedArrayAdapter;
import org.tasks.ui.TaskEditControlFragment;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -57,7 +46,9 @@ import butterknife.OnClick;
import timber.log.Timber;
import static android.support.v4.content.ContextCompat.getColor;
import static com.google.common.collect.Lists.newArrayList;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.repeats.CustomRecurrenceDialog.newCustomRecurrenceDialog;
/**
* Control Set for managing repeats
@ -65,56 +56,60 @@ import static org.tasks.date.DateTimeUtils.newDateTime;
* @author Tim Su <tim@todoroo.com>
*
*/
public class RepeatControlSet extends TaskEditControlFragment {
public class RepeatControlSet extends TaskEditControlFragment
implements CustomRecurrenceDialog.CustomRecurrenceCallback {
public static final int TAG = R.string.TEA_ctrl_repeat_pref;
private static final String FRAG_TAG_CUSTOM_RECURRENCE = "frag_tag_custom_recurrence";
@Override
public void onSelected(int frequency, int interval, long repeatUntilValue,
boolean repeatAfterCompletion, boolean[] isChecked) {
doRepeat = true;
this.interval = interval;
this.frequency = frequency;
this.repeatUntilValue = repeatUntilValue;
this.isChecked = isChecked;
this.repeatAfterCompletion = repeatAfterCompletion;
refreshDisplayView();
}
public interface RepeatChangedListener {
void repeatChanged(boolean repeat);
}
private static final int REQUEST_PICK_DATE = 505;
private static final String EXTRA_RECURRENCE = "extra_recurrence";
private static final String EXTRA_REPEAT_UNTIL = "extra_repeat_until";
private static final String EXTRA_REPEAT_AFTER_COMPLETION = "extra_repeat_after_completion";
// --- spinner constants
private static final int INTERVAL_DAYS = 0;
private static final int INTERVAL_WEEKS = 1;
private static final int INTERVAL_MONTHS = 2;
private static final int INTERVAL_HOURS = 3;
private static final int INTERVAL_MINUTES = 4;
private static final int INTERVAL_YEARS = 5;
public static final int FREQUENCY_MINUTES = 0;
public static final int FREQUENCY_HOURS = 1;
public static final int FREQUENCY_DAYS = 2;
public static final int FREQUENCY_WEEKS = 3;
public static final int FREQUENCY_MONTHS = 4;
public static final int FREQUENCY_YEARS = 5;
private static final int TYPE_DUE_DATE = 0;
private static final int TYPE_COMPLETION_DATE = 1;
public static final int TYPE_DUE_DATE = 0;
public static final int TYPE_COMPLETION_DATE = 1;
//private final CheckBox enabled;
private boolean doRepeat = false;
private Button value;
private Spinner repeatUntil;
@Inject DialogBuilder dialogBuilder;
@Inject Preferences preferences;
@Inject @ForActivity Context context;
@Inject Theme theme;
@BindView(R.id.clear) ImageView clear;
@BindView(R.id.display_row_edit) TextView displayView;
private ArrayAdapter<String> repeatUntilAdapter;
private final List<String> repeatUntilOptions = new ArrayList<>();
private LinearLayout daysOfWeekContainer;
private final Weekday[] weekdays = new Weekday[7];
private final boolean[] isChecked = new boolean[7];
private String recurrence;
private int repeatValue;
private int intervalValue;
private int interval;
private int frequency;
private long repeatUntilValue;
private View dialogView;
private AlertDialog dialog;
private boolean[] isChecked;
private final Weekday[] weekdays = new Weekday[7];
private RepeatChangedListener callback;
@ -130,137 +125,53 @@ public class RepeatControlSet extends TaskEditControlFragment {
repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION);
}
dialogView = inflater.inflate(R.layout.control_set_repeat, null);
value = dialogView.findViewById(R.id.repeatValue);
Spinner interval = dialogView.findViewById(R.id.repeatInterval);
ArrayAdapter<String> intervalAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.repeat_interval));
intervalAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
interval.setAdapter(intervalAdapter);
Spinner type = dialogView.findViewById(R.id.repeatType);
ArrayAdapter<String> typeAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.repeat_type));
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
type.setAdapter(typeAdapter);
type.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
repeatAfterCompletion = position == TYPE_COMPLETION_DATE;
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
daysOfWeekContainer = dialogView.findViewById(R.id.repeatDayOfWeekContainer);
repeatUntil = dialogView.findViewById(R.id.repeat_until);
repeatUntilAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, repeatUntilOptions);
repeatUntilAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
repeatUntil.setAdapter(repeatUntilAdapter);
// set up days of week
DateFormatSymbols dfs = new DateFormatSymbols();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
CompoundButton[] daysOfWeek = new CompoundButton[7];
for(int i = 0; i < 7; i++) {
final int index = i;
CheckBox checkBox = (CheckBox) daysOfWeekContainer.getChildAt(i);
checkBox.setOnCheckedChangeListener((buttonView, isChecked1) -> RepeatControlSet.this.isChecked[index] = isChecked1);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
checkBox.setText(dfs.getShortWeekdays()[dayOfWeek].substring(0, 1));
daysOfWeek[i] = checkBox;
weekdays[i] = Weekday.values()[dayOfWeek - 1];
calendar.add(Calendar.DATE, 1);
}
// set up listeners
value.setOnClickListener(v -> repeatValueClick());
setRepeatValue(1);
interval.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View view, int position, long id) {
daysOfWeekContainer.setVisibility(position == INTERVAL_WEEKS ? View.VISIBLE : View.GONE);
intervalValue = position;
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
//
}
});
setRepeatUntilValue(repeatUntilValue);
repeatUntil.setOnItemSelectedListener(new OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
if (repeatUntilOptions.size() == 2) {
if (i == 0) {
setRepeatUntilValue(0);
} else {
repeatUntilClick();
}
} else {
if (i == 1) {
setRepeatUntilValue(0);
} else if (i == 2) {
repeatUntilClick();
}
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
//
}
});
daysOfWeekContainer.setVisibility(View.GONE);
type.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : TYPE_DUE_DATE);
doRepeat = !Strings.isNullOrEmpty(recurrence);
if (doRepeat) {
// read recurrence rule
try {
RRule rrule = new RRule(recurrence);
setRepeatValue(rrule.getInterval());
for(WeekdayNum day : rrule.getByDay()) {
for(int i = 0; i < 7; i++) {
interval = rrule.getInterval();
isChecked = new boolean[7];
for (WeekdayNum day : rrule.getByDay()) {
for (int i = 0 ; i < 7 ; i++) {
if (weekdays[i].equals(day.wday)) {
daysOfWeek[i].setChecked(true);
isChecked[i] = true;
}
}
}
switch(rrule.getFreq()) {
switch (rrule.getFreq()) {
case DAILY:
intervalValue = INTERVAL_DAYS;
frequency = FREQUENCY_DAYS;
break;
case WEEKLY:
intervalValue = INTERVAL_WEEKS;
frequency = FREQUENCY_WEEKS;
break;
case MONTHLY:
intervalValue = INTERVAL_MONTHS;
frequency = FREQUENCY_MONTHS;
break;
case HOURLY:
intervalValue = INTERVAL_HOURS;
frequency = FREQUENCY_HOURS;
break;
case MINUTELY:
intervalValue = INTERVAL_MINUTES;
frequency = FREQUENCY_MINUTES;
break;
case YEARLY:
intervalValue = INTERVAL_YEARS;
frequency = FREQUENCY_YEARS;
break;
default:
Timber.e(new Exception("Unhandled rrule frequency: " + recurrence), "repeat-unhandled-rule");
}
interval.setSelection(intervalValue);
} catch (Exception e) {
// invalid RRULE
recurrence = ""; //$NON-NLS-1$
}
} catch (ParseException e) {
recurrence = "";
Timber.e(e, e.getMessage());
}
}
refreshDisplayView();
return view;
@ -287,33 +198,96 @@ public class RepeatControlSet extends TaskEditControlFragment {
component.inject(this);
}
@OnClick(R.id.clear)
void clearRepeat(View view) {
doRepeat = false;
refreshDisplayView();
callback.repeatChanged(doRepeat);
private boolean isCustomValue() {
if (!doRepeat) {
return false;
}
if (frequency == FREQUENCY_WEEKS) {
for (boolean checked : isChecked) {
if (checked) {
return true;
}
}
}
return frequency == FREQUENCY_HOURS ||
frequency == FREQUENCY_MINUTES ||
!(repeatUntilValue == 0 && interval == 1 && !repeatAfterCompletion);
}
@OnClick(R.id.display_row_edit)
void openPopup(View view) {
if (dialog == null) {
dialog = buildDialog();
boolean customPicked = isCustomValue();
List<String> repeatOptions = newArrayList(context.getResources().getStringArray(R.array.repeat_options));
SingleCheckedArrayAdapter<String> adapter = new SingleCheckedArrayAdapter<>(context, repeatOptions);
if (customPicked) {
adapter.insert(getRepeatString(), 0);
adapter.setChecked(0);
} else if (!doRepeat) {
adapter.setChecked(0);
} else {
int selected;
switch(frequency) {
case FREQUENCY_DAYS:
selected = 1;
break;
case FREQUENCY_WEEKS:
selected = 2;
break;
case FREQUENCY_MONTHS:
selected = 3;
break;
case FREQUENCY_YEARS:
selected = 4;
break;
default:
selected = 0;
break;
}
adapter.setChecked(selected);
}
dialog.show();
}
private AlertDialog buildDialog() {
return dialogBuilder.newDialog()
.setView(dialogView)
.setPositiveButton(android.R.string.ok, (dialog12, which) -> {
doRepeat = true;
dialogBuilder.newDialog()
.setAdapter(adapter, (dialogInterface, i) -> {
if (customPicked) {
if (i == 0) {
return;
}
i--;
}
if (i == 0) {
doRepeat = false;
} else if (i == 5) {
newCustomRecurrenceDialog(this)
.show(getFragmentManager(), FRAG_TAG_CUSTOM_RECURRENCE);
return;
} else {
doRepeat = true;
repeatAfterCompletion = false;
interval = 1;
repeatUntilValue = 0;
switch (i) {
case 1:
frequency = FREQUENCY_DAYS;
break;
case 2:
frequency = FREQUENCY_WEEKS;
isChecked = new boolean[7];
break;
case 3:
frequency = FREQUENCY_MONTHS;
break;
case 4:
frequency = FREQUENCY_YEARS;
break;
}
}
callback.repeatChanged(doRepeat);
refreshDisplayView();
})
.setOnCancelListener(dialog1 -> refreshDisplayView())
.create();
.setOnCancelListener(d -> refreshDisplayView())
.show();
}
@Override
@ -365,12 +339,12 @@ public class RepeatControlSet extends TaskEditControlFragment {
result = ""; //$NON-NLS-1$
} else {
RRule rrule = new RRule();
rrule.setInterval(repeatValue);
switch(intervalValue) {
case INTERVAL_DAYS:
rrule.setInterval(interval);
switch(frequency) {
case FREQUENCY_DAYS:
rrule.setFreq(Frequency.DAILY);
break;
case INTERVAL_WEEKS: {
case FREQUENCY_WEEKS: {
rrule.setFreq(Frequency.WEEKLY);
ArrayList<WeekdayNum> days = new ArrayList<>();
@ -382,16 +356,16 @@ public class RepeatControlSet extends TaskEditControlFragment {
rrule.setByDay(days);
break;
}
case INTERVAL_MONTHS:
case FREQUENCY_MONTHS:
rrule.setFreq(Frequency.MONTHLY);
break;
case INTERVAL_HOURS:
case FREQUENCY_HOURS:
rrule.setFreq(Frequency.HOURLY);
break;
case INTERVAL_MINUTES:
case FREQUENCY_MINUTES:
rrule.setFreq(Frequency.MINUTELY);
break;
case INTERVAL_YEARS:
case FREQUENCY_YEARS:
rrule.setFreq(Frequency.YEARLY);
break;
}
@ -402,65 +376,35 @@ public class RepeatControlSet extends TaskEditControlFragment {
return result;
}
/** Set up the repeat value button */
private void setRepeatValue(int newValue) {
repeatValue = newValue;
value.setText(getString(R.string.repeat_every, newValue));
}
private void setRepeatUntilValue(long newValue) {
repeatUntilValue = newValue;
updateRepeatUntilOptions();
}
private void repeatValueClick() {
int dialogValue = repeatValue;
if(dialogValue == 0) {
dialogValue = 1;
}
NumberPickerDialog dialog = new NumberPickerDialog(theme.getThemedDialog(getActivity()), this::setRepeatValue, getResources().getString(R.string.repeat_interval_prompt),
dialogValue, 1, 1, 365);
theme.applyToContext(dialog.getContext());
dialog.show();
}
private void repeatUntilClick() {
Intent intent = new Intent(context, DatePickerActivity.class);
intent.putExtra(DatePickerActivity.EXTRA_TIMESTAMP, repeatUntilValue > 0 ? repeatUntilValue : 0L);
startActivityForResult(intent, REQUEST_PICK_DATE);
}
@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);
}
private void refreshDisplayView() {
if (doRepeat) {
displayView.setText(getRepeatString());
displayView.setTextColor(getColor(context, R.color.text_primary));
clear.setVisibility(View.VISIBLE);
} else {
displayView.setText(R.string.repeat_never);
displayView.setText(R.string.repeat_option_does_not_repeat);
displayView.setTextColor(getColor(context, R.color.text_tertiary));
clear.setVisibility(View.GONE);
}
}
private String getRepeatString() {
if (!isCustomValue()) {
switch (frequency) {
case FREQUENCY_DAYS:
return getString(R.string.repeat_option_every_day);
case FREQUENCY_WEEKS:
return getString(R.string.repeat_option_every_week);
case FREQUENCY_MONTHS:
return getString(R.string.repeat_option_every_month);
case FREQUENCY_YEARS:
return getString(R.string.repeat_option_every_year);
}
}
int arrayResource = R.array.repeat_interval;
String[] dates = getResources().getStringArray(
arrayResource);
String date = String.format("%s %s", repeatValue, dates[intervalValue]); //$NON-NLS-1$
arrayResource);
String date = String.format("%s %s", interval, dates[frequency]); //$NON-NLS-1$
if (repeatUntilValue > 0) {
return getString(R.string.repeat_detail_duedate_until, date, getDisplayString());
} else {
@ -468,18 +412,11 @@ public class RepeatControlSet extends TaskEditControlFragment {
}
}
private void updateRepeatUntilOptions() {
repeatUntilOptions.clear();
if (repeatUntilValue > 0) {
repeatUntilOptions.add(getString(R.string.repeat_until, getDisplayString()));
}
repeatUntilOptions.add(getString(R.string.repeat_forever));
repeatUntilOptions.add(getString(R.string.repeat_until, "").trim());
repeatUntilAdapter.notifyDataSetChanged();
repeatUntil.setSelection(0);
private String getDisplayString() {
return getDisplayString(context, repeatUntilValue);
}
private String getDisplayString() {
public static String getDisplayString(Context context, long repeatUntilValue) {
StringBuilder displayString = new StringBuilder();
DateTime d = newDateTime(repeatUntilValue);
if (d.getMillis() > 0) {

@ -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());
}
}
}

@ -18,6 +18,9 @@ import com.google.common.base.Strings;
import org.tasks.R;
import java.text.NumberFormat;
import java.text.ParseException;
import timber.log.Timber;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastJellybeanMR1;
@ -156,6 +159,16 @@ public class Locale {
return NumberFormat.getNumberInstance(appLocale).format(number);
}
public Integer parseInteger(String number) {
try {
return NumberFormat.getNumberInstance(appLocale)
.parse(number)
.intValue();
} catch (ParseException e) {
return null;
}
}
public String formatPercentage(int percentage) {
return NumberFormat.getPercentInstance(appLocale).format(percentage / 100.0);
}

@ -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);
}
}

@ -40,6 +40,10 @@ public class Theme {
return themeColor;
}
public ThemeAccent getThemeAccent() {
return themeAccent;
}
public LayoutInflater getLayoutInflater(Context context) {
return (LayoutInflater) wrap(context).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@ -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>

@ -3,120 +3,111 @@
**
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingLeft="5dip"
android:paddingRight="5dip">
android:orientation="vertical">
<LinearLayout
android:id="@+id/repeatContainer"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="100"
android:orientation="vertical"
android:paddingBottom="5dp"
android:paddingTop="5dp">
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:background="?colorAccentDialog">
<Button
android:id="@+id/repeatValue"
android:layout_width="fill_parent"
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/frequency"
style="Widget.AppCompat.Spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textColor="?attr/asTextColor"/>
android:layout_gravity="center_horizontal"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:paddingStart="@dimen/keyline_first"
app:backgroundTint="?fab_text" />
<Spinner
android:id="@+id/repeatInterval"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:prompt="@string/repeat_interval_prompt"
android:textColor="?attr/asTextColor" />
</LinearLayout>
<Spinner
android:id="@+id/repeatType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:textColor="?attr/asTextColor" />
</FrameLayout>
<LinearLayout
android:id="@+id/repeatDayOfWeekContainer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:focusableInTouchMode="true"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp">
android:layout_marginTop="8dp">
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_height="wrap_content"
android:paddingEnd="0dp"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="0dp"
android:paddingStart="@dimen/keyline_first"
android:text="@string/repeat_every"
android:textAppearance="@style/TextAppearance" />
<EditText
android:id="@+id/repeatValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_height="wrap_content"
android:ems="3"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="center_horizontal"
android:inputType="number"
android:maxLength="3"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:selectAllOnFocus="true"
android:singleLine="true"
android:textSize="15sp" />
<TextView
android:id="@+id/intervalText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="0dp"
android:paddingRight="@dimen/keyline_first"
android:paddingStart="0dp"
android:textAppearance="@style/TextAppearance" />
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/repeatType"
style="Widget.AppCompat.Spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:paddingStart="@dimen/keyline_first"
android:textColor="?attr/colorPrimary" />
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<include layout="@layout/week_buttons" />
<CheckBox
style="@style/TextAppearance"
android:layout_weight="1"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="@+id/repeat_until"
style="Widget.AppCompat.Spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingEnd="@dimen/keyline_first"
android:paddingLeft="@dimen/keyline_first"
android:paddingRight="@dimen/keyline_first"
android:paddingStart="@dimen/keyline_first"
android:textColor="?attr/asTextColor" />
</LinearLayout>
</LinearLayout>
<Spinner
android:id="@+id/repeat_until"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="5dp"
android:paddingTop="5dp"
android:textColor="?attr/asTextColor" />
</LinearLayout>
</ScrollView>

@ -26,6 +26,4 @@
</LinearLayout>
<include layout="@layout/control_set_clear_button" />
</LinearLayout>

@ -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" />

@ -25,9 +25,6 @@
<string name="CFC_title_contains_text">Titel bevat: ?</string>
<string name="gcal_TEA_error">Kon nie taak by kalender voeg nie!</string>
<string name="rmd_EPr_defaultRemind_title">Ewekansige herinneringe</string>
<string name="repeat_every">Elke %d</string>
<string name="repeat_interval_prompt">Herhaal intervalle</string>
<string name="repeat_never">Geen herhaal</string>
<string name="translations">Dra by tot vertalings</string>
<string name="quiet_hours_summary">Geen herinneringe gedurende stil ure nie</string>
<string name="show_hidden">Wys onsigbare</string>

@ -113,8 +113,6 @@
<string name="default_random_reminder_bi_weekly">مرتين في الاسبوع</string>
<string name="default_random_reminder_monthly">شهري</string>
<string name="default_random_reminder_bi_monthly">مرتين في الشهر</string>
<string name="repeat_interval_prompt">مجال التكرار</string>
<string name="repeat_never">لا تتكرر</string>
<string name="repeat_interval_day">أيام</string>
<string name="repeat_interval_week">أسابيع</string>
<string name="repeat_interval_month">أشهُر</string>

@ -199,9 +199,6 @@
<string name="default_random_reminder_bi_weekly">два пъти седмично</string>
<string name="default_random_reminder_monthly">месечно</string>
<string name="default_random_reminder_bi_monthly">на два месеца</string>
<string name="repeat_every">Всеки %d</string>
<string name="repeat_interval_prompt">Интервал на повторение</string>
<string name="repeat_never">Без повторение</string>
<string name="repeat_interval_day">Ден(дни)</string>
<string name="repeat_interval_week">Седмица(и)</string>
<string name="repeat_interval_month">Месец(и)</string>

@ -95,9 +95,6 @@
<string name="rmd_EPr_quiet_hours_start_title">Inici de Silenci</string>
<string name="rmd_EPr_quiet_hours_end_title">Final de Silenci</string>
<string name="rmd_EPr_defaultRemind_title">Notificacions al Atzar</string>
<string name="repeat_every">Cada %d</string>
<string name="repeat_interval_prompt">Interval de Repecitiò</string>
<string name="repeat_never">Sense repetir</string>
<string name="repeat_detail_duedate">Cada %s</string>
<string name="repeat_detail_duedate_until">Cada %1$s\nfins %2$s</string>
<string name="repeat_forever">Repeteix indefinidament</string>

@ -182,9 +182,6 @@
<string name="default_random_reminder_bi_weekly">každých ctrnáct dní</string>
<string name="default_random_reminder_monthly">měsíčně</string>
<string name="default_random_reminder_bi_monthly">každý druhý měsíc</string>
<string name="repeat_every">Každý %d</string>
<string name="repeat_interval_prompt">Opakovací interval</string>
<string name="repeat_never">Bez opakování</string>
<string name="repeat_interval_day">Dnů</string>
<string name="repeat_interval_week">Týdnů</string>
<string name="repeat_interval_month">Měsíců</string>

@ -83,9 +83,6 @@
<string name="rmd_EPr_quiet_hours_start_title">Stille timer start</string>
<string name="rmd_EPr_quiet_hours_end_title">Stille timer slut</string>
<string name="rmd_EPr_defaultRemind_title">Tilfældige påmindelser</string>
<string name="repeat_every">Hver %d</string>
<string name="repeat_interval_prompt">Interval for gentagelse</string>
<string name="repeat_never">Gentages ikke</string>
<string name="repeat_detail_duedate">Hver %s</string>
<string name="repeat_detail_duedate_until">Hver %1$s\nindtil %2$s</string>
<string name="repeat_forever">Gentag uendeligt</string>

@ -192,9 +192,6 @@
<string name="default_random_reminder_bi_weekly">vierzehntägig</string>
<string name="default_random_reminder_monthly">monatlich</string>
<string name="default_random_reminder_bi_monthly">alle zwei Monate</string>
<string name="repeat_every">Jeden %d</string>
<string name="repeat_interval_prompt">Wiederholungsintervall</string>
<string name="repeat_never">Nicht wiederholen</string>
<string name="repeat_interval_day">Tag(e)</string>
<string name="repeat_interval_week">Woche(n)</string>
<string name="repeat_interval_month">Monat(e)</string>

@ -162,9 +162,6 @@
<string name="default_random_reminder_bi_weekly">κάθε δυο εβδομάδες</string>
<string name="default_random_reminder_monthly">μηνιαία</string>
<string name="default_random_reminder_bi_monthly">διμηνιαία</string>
<string name="repeat_every">Κάθε %d</string>
<string name="repeat_interval_prompt">Διάστημα επανάληψης</string>
<string name="repeat_never">Μή επαναλαμβανόμενα</string>
<string name="repeat_interval_day">Μέρα(ες)</string>
<string name="repeat_interval_week">Εβδομαδα(ές)</string>
<string name="repeat_interval_month">Μήνας(ές)</string>

@ -195,9 +195,6 @@
<string name="default_random_reminder_bi_weekly">quincenalmente</string>
<string name="default_random_reminder_monthly">mensualmente</string>
<string name="default_random_reminder_bi_monthly">bimensualmente</string>
<string name="repeat_every">Cada %d</string>
<string name="repeat_interval_prompt">Intervalo de repetición</string>
<string name="repeat_never">Sin repetir</string>
<string name="repeat_interval_day">Día(s)</string>
<string name="repeat_interval_week">Semana(s)</string>
<string name="repeat_interval_month">Mes(es)</string>

@ -143,9 +143,6 @@
<string name="default_random_reminder_bi_weekly">یک هفته در میان</string>
<string name="default_random_reminder_monthly">هر ماه</string>
<string name="default_random_reminder_bi_monthly">یک ماه درمیان</string>
<string name="repeat_every">هر %d</string>
<string name="repeat_interval_prompt">دوره تکرار</string>
<string name="repeat_never">بدون تکرار</string>
<string name="repeat_interval_day">روز(ها)</string>
<string name="repeat_interval_week">هفته(ها)</string>
<string name="repeat_interval_month">ماه(ها)</string>

@ -199,9 +199,6 @@
<string name="default_random_reminder_bi_weekly">Jokatoinen viikko</string>
<string name="default_random_reminder_monthly">Kuukausittain</string>
<string name="default_random_reminder_bi_monthly">Jokatoinen kuukausi</string>
<string name="repeat_every">Toista %d</string>
<string name="repeat_interval_prompt">Toistoväli</string>
<string name="repeat_never">Ei toistuva</string>
<string name="repeat_interval_day">Päivä(t)</string>
<string name="repeat_interval_week">Viikko(t)</string>
<string name="repeat_interval_month">Kuukausi</string>

@ -193,9 +193,6 @@
<string name="default_random_reminder_bi_weekly">bi-hebdomadaire</string>
<string name="default_random_reminder_monthly">mensuel</string>
<string name="default_random_reminder_bi_monthly">bi-mensuel</string>
<string name="repeat_every">Tous les %d</string>
<string name="repeat_interval_prompt">Interval de répétition</string>
<string name="repeat_never">Pas de répétition</string>
<string name="repeat_interval_day">Jour(s)</string>
<string name="repeat_interval_week">Semaine(s)</string>
<string name="repeat_interval_month">Mois</string>

@ -195,9 +195,6 @@
<string name="default_random_reminder_bi_weekly">quincenalmente</string>
<string name="default_random_reminder_monthly">mensualmente</string>
<string name="default_random_reminder_bi_monthly">bimensualmente</string>
<string name="repeat_every">Cada %d</string>
<string name="repeat_interval_prompt">Intervalo de repetición</string>
<string name="repeat_never">Sen repetir</string>
<string name="repeat_interval_day">Día(s)</string>
<string name="repeat_interval_week">Semana(s)</string>
<string name="repeat_interval_month">Mes(es)</string>

@ -199,9 +199,6 @@
<string name="default_random_reminder_bi_weekly">Kéthetente</string>
<string name="default_random_reminder_monthly">Havonta</string>
<string name="default_random_reminder_bi_monthly">Kéthavonta</string>
<string name="repeat_every">Minden %d</string>
<string name="repeat_interval_prompt">Ismétlési időköz</string>
<string name="repeat_never">Nem ismétlődő</string>
<string name="repeat_interval_day">Nap</string>
<string name="repeat_interval_week">Hét</string>
<string name="repeat_interval_month">Hónap</string>

@ -197,9 +197,6 @@
<string name="default_random_reminder_bi_weekly">bi-settimanalmente</string>
<string name="default_random_reminder_monthly">mensilmente</string>
<string name="default_random_reminder_bi_monthly">bi-mensilmente</string>
<string name="repeat_every">Ogni %d</string>
<string name="repeat_interval_prompt">Intervallo di ripetizione</string>
<string name="repeat_never">Non ricorrente</string>
<string name="repeat_interval_day">Giorno(i)</string>
<string name="repeat_interval_week">Settimana(e)</string>
<string name="repeat_interval_month">Mese(i)</string>

@ -196,9 +196,6 @@
<string name="default_random_reminder_bi_weekly">דו שבועי</string>
<string name="default_random_reminder_monthly">חודשי</string>
<string name="default_random_reminder_bi_monthly">דו חודשי</string>
<string name="repeat_every">כל %d</string>
<string name="repeat_interval_prompt">תדירות חזרה</string>
<string name="repeat_never">ללא חזרה</string>
<string name="repeat_interval_day">יום/ימים</string>
<string name="repeat_interval_week">שבוע/(ות)</string>
<string name="repeat_interval_month">חודש/ים</string>

@ -197,9 +197,6 @@
<string name="default_random_reminder_bi_weekly">一週間おき</string>
<string name="default_random_reminder_monthly">毎月</string>
<string name="default_random_reminder_bi_monthly">一ヶ月おき</string>
<string name="repeat_every">%d 毎</string>
<string name="repeat_interval_prompt">繰り返し間隔</string>
<string name="repeat_never">Tasks はアクセス許可が必要です</string>
<string name="repeat_interval_day">日毎</string>
<string name="repeat_interval_week">週毎</string>
<string name="repeat_interval_month">か月毎</string>

@ -200,9 +200,6 @@
<string name="default_random_reminder_bi_weekly">격주로</string>
<string name="default_random_reminder_monthly">매달</string>
<string name="default_random_reminder_bi_monthly">격월로</string>
<string name="repeat_every">매 %d</string>
<string name="repeat_interval_prompt">반복 주기</string>
<string name="repeat_never">반복하지 않기</string>
<string name="repeat_interval_day">일마다</string>
<string name="repeat_interval_week">주마다</string>
<string name="repeat_interval_month">월마다</string>

@ -73,8 +73,6 @@
<string name="rmd_EPr_quiet_hours_start_title">Stilletimer start</string>
<string name="rmd_EPr_quiet_hours_end_title">Stilletimer slutt</string>
<string name="rmd_EPr_defaultRemind_title">Tilfeldige påminnelser</string>
<string name="repeat_every">Hver %d</string>
<string name="repeat_interval_prompt">Gjentakelsesintervall</string>
<string name="repeat_detail_duedate">Hver %s</string>
<string name="TPl_notification">Tidtaker aktiv for %s!</string>
<string name="TFE_workingOn">Oppgaver med tidtaker</string>

@ -196,9 +196,6 @@
<string name="default_random_reminder_bi_weekly">tweewekelijks</string>
<string name="default_random_reminder_monthly">maandelijks</string>
<string name="default_random_reminder_bi_monthly">tweemaandelijks</string>
<string name="repeat_every">Elke %d</string>
<string name="repeat_interval_prompt">Herhaal interval</string>
<string name="repeat_never">Niet herhalend</string>
<string name="repeat_interval_day">Dag(en)</string>
<string name="repeat_interval_week">week/weken</string>
<string name="repeat_interval_month">maand(en)</string>

@ -195,9 +195,6 @@
<string name="default_random_reminder_bi_weekly">raz na dwa tygodnie</string>
<string name="default_random_reminder_monthly">raz w miesiącu</string>
<string name="default_random_reminder_bi_monthly">raz na dwa miesiące</string>
<string name="repeat_every">Co %d</string>
<string name="repeat_interval_prompt">Odstęp powtarzania</string>
<string name="repeat_never">Jednorazowo</string>
<string name="repeat_interval_day">Dzień/Dni</string>
<string name="repeat_interval_week">Tydzień/Tygodni(e)</string>
<string name="repeat_interval_month">Miesiąc/Miesiący(e)</string>

@ -192,9 +192,6 @@
<string name="default_random_reminder_bi_weekly">a cada duas semanas</string>
<string name="default_random_reminder_monthly">mensalmente</string>
<string name="default_random_reminder_bi_monthly">a cada dois meses</string>
<string name="repeat_every">A cada %d</string>
<string name="repeat_interval_prompt">Intervalo de repetição</string>
<string name="repeat_never">Não repetir</string>
<string name="repeat_interval_day">Dia(s)</string>
<string name="repeat_interval_week">Semana(s)</string>
<string name="repeat_interval_month">Mês(es)</string>

@ -179,9 +179,6 @@
<string name="default_random_reminder_bi_weekly">bissemanal</string>
<string name="default_random_reminder_monthly">mensal</string>
<string name="default_random_reminder_bi_monthly">bimensal</string>
<string name="repeat_every">Cada %d</string>
<string name="repeat_interval_prompt">Intervalo de repetição</string>
<string name="repeat_never">Não repete</string>
<string name="repeat_interval_day">Dia(s)</string>
<string name="repeat_interval_week">Semana(s)</string>
<string name="repeat_interval_month">Mês(es)</string>

@ -196,9 +196,6 @@
<string name="default_random_reminder_bi_weekly">каждые две недели</string>
<string name="default_random_reminder_monthly">ежемесячно</string>
<string name="default_random_reminder_bi_monthly">каждые два месяца</string>
<string name="repeat_every">С интервалом в %d</string>
<string name="repeat_interval_prompt">Интервал повтора</string>
<string name="repeat_never">Без повторений</string>
<string name="repeat_interval_day">День(дней)</string>
<string name="repeat_interval_week">Неделя(ль)</string>
<string name="repeat_interval_month">Месяц(ев)</string>

@ -174,9 +174,6 @@
<string name="default_random_reminder_bi_weekly">každý druhý týždeň</string>
<string name="default_random_reminder_monthly">mesačne</string>
<string name="default_random_reminder_bi_monthly">každý druhý mesiac</string>
<string name="repeat_every">Každý %d</string>
<string name="repeat_interval_prompt">Interval opakovania</string>
<string name="repeat_never">Neopakovať</string>
<string name="repeat_interval_day">Deň</string>
<string name="repeat_interval_week">Týždeň</string>
<string name="repeat_interval_month">Mesiac</string>

@ -166,9 +166,6 @@
<string name="default_random_reminder_bi_weekly">vsake dva tedna</string>
<string name="default_random_reminder_monthly">mesečno</string>
<string name="default_random_reminder_bi_monthly">vsake dva meseca</string>
<string name="repeat_every">Vsakih %d</string>
<string name="repeat_interval_prompt">Pogostost ponovitev</string>
<string name="repeat_never">Brez ponovitev</string>
<string name="repeat_interval_day">Dan/dni</string>
<string name="repeat_interval_week">V tednih</string>
<string name="repeat_interval_month">Mesec/a /e /ev</string>

@ -24,8 +24,6 @@
<string name="CFC_dueBefore_text">Po datumu: ?</string>
<string name="gcal_completed_title">%s (završeno)</string>
<string name="rmd_EPr_defaultRemind_title">Nasumice posetnik</string>
<string name="repeat_interval_prompt">Interval ponavljanja</string>
<string name="repeat_never">Bez ponavljanja</string>
<string name="repeat_detail_duedate">Svaki %s</string>
<string name="repeat_forever">Ponavljaj zauvek</string>
<string name="repeat_until">Interval ponavljanja %s</string>

@ -196,9 +196,6 @@
<string name="default_random_reminder_bi_weekly">varannan vecka</string>
<string name="default_random_reminder_monthly">varje månad</string>
<string name="default_random_reminder_bi_monthly">varannan månad</string>
<string name="repeat_every">Varje %d</string>
<string name="repeat_interval_prompt">Upprepningsintervall</string>
<string name="repeat_never">Inte upprepande</string>
<string name="repeat_interval_day">Dag(ar)</string>
<string name="repeat_interval_week">Vecka (veckor)</string>
<string name="repeat_interval_month">Månad(er)</string>

@ -201,9 +201,6 @@
<string name="default_random_reminder_bi_weekly">haftada 2 kez</string>
<string name="default_random_reminder_monthly">ayda bir</string>
<string name="default_random_reminder_bi_monthly">ayda 2 kez</string>
<string name="repeat_every">Her %d</string>
<string name="repeat_interval_prompt">Yineleme Aralığı</string>
<string name="repeat_never">Yenilenmeyen</string>
<string name="repeat_interval_day">Gün</string>
<string name="repeat_interval_week">Hafta</string>
<string name="repeat_interval_month">Ay</string>

@ -198,9 +198,6 @@
<string name="default_random_reminder_bi_weekly">два рази на тиждень</string>
<string name="default_random_reminder_monthly">щомісяця</string>
<string name="default_random_reminder_bi_monthly">два рази на місяць</string>
<string name="repeat_every">Кожні %d</string>
<string name="repeat_interval_prompt">Інтервал повторення</string>
<string name="repeat_never">Не повторювати</string>
<string name="repeat_interval_day">Днів</string>
<string name="repeat_interval_week">Тижнів</string>
<string name="repeat_interval_month">Місяців</string>

@ -152,9 +152,6 @@
<string name="default_random_reminder_bi_weekly">每两周</string>
<string name="default_random_reminder_monthly">每月</string>
<string name="default_random_reminder_bi_monthly">每两个月</string>
<string name="repeat_every">每 %d</string>
<string name="repeat_interval_prompt">重复间隔</string>
<string name="repeat_never">不重复</string>
<string name="repeat_interval_day"></string>
<string name="repeat_interval_week">星期</string>
<string name="repeat_interval_month"></string>

@ -161,8 +161,6 @@
<string name="default_random_reminder_bi_weekly">每2週</string>
<string name="default_random_reminder_monthly">每月</string>
<string name="default_random_reminder_bi_monthly">每2個月</string>
<string name="repeat_every">每 %d</string>
<string name="repeat_interval_prompt">重複間隔</string>
<string name="repeat_interval_day"></string>
<string name="repeat_interval_week">星期</string>
<string name="repeat_interval_month"></string>

@ -204,12 +204,30 @@
<item>@string/default_random_reminder_bi_monthly</item>
</string-array>
<string-array name="repeat_options">
<item>@string/repeat_option_does_not_repeat</item>
<item>@string/repeat_option_every_day</item>
<item>@string/repeat_option_every_week</item>
<item>@string/repeat_option_every_month</item>
<item>@string/repeat_option_every_year</item>
<item>@string/repeat_option_custom</item>
</string-array>
<string-array name="repeat_frequency">
<item>@string/repeat_minutely</item>
<item>@string/repeat_hourly</item>
<item>@string/repeat_daily</item>
<item>@string/repeat_weekly</item>
<item>@string/repeat_monthly</item>
<item>@string/repeat_yearly</item>
</string-array>
<string-array name="repeat_interval">
<item>@string/repeat_interval_minute</item>
<item>@string/repeat_interval_hour</item>
<item>@string/repeat_interval_day</item>
<item>@string/repeat_interval_week</item>
<item>@string/repeat_interval_month</item>
<item>@string/repeat_interval_hour</item>
<item>@string/repeat_interval_minute</item>
<item>@string/repeat_interval_year</item>
</string-array>

@ -23,4 +23,5 @@
<dimen name="elevation_padding">0dp</dimen>
<dimen name="widget_padding">10dp</dimen>
<dimen name="week_button_state_on_circle_size">48dp</dimen>
</resources>

@ -514,12 +514,46 @@ File %1$s contained %2$s.\n\n
<!-- Resources for built-in repeat plug-in -->
<!-- slide 20b: button for "every x" part of repeat (%d -> repeat value) -->
<string name="repeat_every">Every %d</string>
<!-- hint when opening repeat interval -->
<string name="repeat_interval_prompt">Repeat interval</string>
<string name="repeat_never">Not repeating</string>
<string name="repeat_every">Every</string>
<string name="repeat_option_does_not_repeat">Does not repeat</string>
<string name="repeat_option_every_day">Every day</string>
<string name="repeat_option_every_week">Every week</string>
<string name="repeat_option_every_month">Every month</string>
<string name="repeat_option_every_year">Every year</string>
<string name="repeat_option_custom">Custom…</string>
<string name="repeat_minutely">REPEAT MINUTELY</string>
<string name="repeat_hourly">REPEAT HOURLY</string>
<string name="repeat_daily">REPEAT DAILY</string>
<string name="repeat_weekly">REPEAT WEEKLY</string>
<string name="repeat_monthly">REPEAT MONTHLY</string>
<string name="repeat_yearly">REPEAT YEARLY</string>
<plurals name="repeat_minutes">
<item quantity="one">minute</item>
<item quantity="other">minutes</item>
</plurals>
<plurals name="repeat_hours">
<item quantity="one">hour</item>
<item quantity="other">hours</item>
</plurals>
<plurals name="repeat_days">
<item quantity="one">day</item>
<item quantity="other">days</item>
</plurals>
<plurals name="repeat_weeks">
<item quantity="one">week</item>
<item quantity="other">weeks</item>
</plurals>
<plurals name="repeat_months">
<item quantity="one">month</item>
<item quantity="other">months</item>
</plurals>
<plurals name="repeat_years">
<item quantity="one">year</item>
<item quantity="other">years</item>
</plurals>
<string name="repeat_interval_day">Day(s)</string>
<string name="repeat_interval_week">Week(s)</string>

Loading…
Cancel
Save