Populate recurrence picker with existing settings

pull/574/head
Alex Baker 7 years ago
parent 02aae4c5c2
commit 7ece10726f

@ -386,7 +386,11 @@ public class Task extends RemoteModel {
} }
public String sanitizedRecurrence() { public String sanitizedRecurrence() {
return getRecurrence().replaceAll("BYDAY=;", "").replaceAll(";?FROM=[^;]*", ""); //$NON-NLS-1$//$NON-NLS-2$ return getRecurrenceWithoutFrom().replaceAll("BYDAY=;", ""); //$NON-NLS-1$//$NON-NLS-2$
}
public String getRecurrenceWithoutFrom() {
return getRecurrence().replaceAll(";?FROM=[^;]*", "");
} }
/** /**

@ -24,7 +24,6 @@ import android.widget.TextView;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.primitives.Booleans;
import com.google.ical.values.Frequency; import com.google.ical.values.Frequency;
import com.google.ical.values.RRule; import com.google.ical.values.RRule;
import com.google.ical.values.Weekday; import com.google.ical.values.Weekday;
@ -49,7 +48,6 @@ import java.text.DateFormatSymbols;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -57,11 +55,15 @@ import javax.inject.Inject;
import butterknife.BindView; import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.OnItemSelected; import butterknife.OnItemSelected;
import timber.log.Timber;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
import static com.google.common.collect.Iterables.any;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static com.google.ical.values.Frequency.DAILY;
import static com.google.ical.values.Frequency.HOURLY;
import static com.google.ical.values.Frequency.MINUTELY;
import static com.google.ical.values.Frequency.MONTHLY;
import static com.google.ical.values.Frequency.WEEKLY;
import static com.google.ical.values.Frequency.YEARLY;
import static org.tasks.repeats.CustomRecurrenceDialog.newCustomRecurrenceDialog; import static org.tasks.repeats.CustomRecurrenceDialog.newCustomRecurrenceDialog;
/** /**
@ -74,15 +76,12 @@ public class RepeatControlSet extends TaskEditControlFragment
implements CustomRecurrenceDialog.CustomRecurrenceCallback { implements CustomRecurrenceDialog.CustomRecurrenceCallback {
public static final int TAG = R.string.TEA_ctrl_repeat_pref; public static final int TAG = R.string.TEA_ctrl_repeat_pref;
public static final List<Weekday> WEEKDAYS = Arrays.asList(Weekday.values());
private static final String FRAG_TAG_CUSTOM_RECURRENCE = "frag_tag_custom_recurrence"; private static final String FRAG_TAG_CUSTOM_RECURRENCE = "frag_tag_custom_recurrence";
@Override @Override
public void onSelected(int frequency, int interval, long repeatUntilValue, boolean[] isChecked) { public void onSelected(RRule rrule) {
doRepeat = true; this.rrule = rrule;
this.interval = interval;
this.frequency = frequency;
this.repeatUntilValue = repeatUntilValue;
this.isChecked = isChecked;
refreshDisplayView(); refreshDisplayView();
} }
@ -91,23 +90,10 @@ public class RepeatControlSet extends TaskEditControlFragment
} }
private static final String EXTRA_RECURRENCE = "extra_recurrence"; 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"; private static final String EXTRA_REPEAT_AFTER_COMPLETION = "extra_repeat_after_completion";
// --- spinner constants public static final int TYPE_DUE_DATE = 1;
public static final int TYPE_COMPLETION_DATE = 2;
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;
public static final int TYPE_DUE_DATE = 0;
public static final int TYPE_COMPLETION_DATE = 1;
//private final CheckBox enabled;
private boolean doRepeat = false;
@Inject DialogBuilder dialogBuilder; @Inject DialogBuilder dialogBuilder;
@Inject Preferences preferences; @Inject Preferences preferences;
@ -119,12 +105,7 @@ public class RepeatControlSet extends TaskEditControlFragment
@BindView(R.id.repeatType) Spinner typeSpinner; @BindView(R.id.repeatType) Spinner typeSpinner;
@BindView(R.id.repeatTypeContainer) LinearLayout repeatTypeContainer; @BindView(R.id.repeatTypeContainer) LinearLayout repeatTypeContainer;
private String recurrence; private RRule rrule;
private int interval;
private int frequency;
private long repeatUntilValue;
private boolean[] isChecked;
private final Weekday[] weekdays = new Weekday[7];
private final List<String> repeatTypes = new ArrayList<>(); private final List<String> repeatTypes = new ArrayList<>();
private HiddenTopArrayAdapter<String> typeAdapter; private HiddenTopArrayAdapter<String> typeAdapter;
@ -137,8 +118,16 @@ public class RepeatControlSet extends TaskEditControlFragment
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState); View view = super.onCreateView(inflater, container, savedInstanceState);
if (savedInstanceState != null) { if (savedInstanceState != null) {
recurrence = savedInstanceState.getString(EXTRA_RECURRENCE); String recurrence = savedInstanceState.getString(EXTRA_RECURRENCE);
repeatUntilValue = savedInstanceState.getLong(EXTRA_REPEAT_UNTIL); if (Strings.isNullOrEmpty(recurrence)) {
rrule = null;
} else {
try {
rrule = new RRule(recurrence);
} catch (ParseException e) {
rrule = null;
}
}
repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION); repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION);
} }
@ -165,60 +154,12 @@ public class RepeatControlSet extends TaskEditControlFragment
typeSpinner.setAdapter(typeAdapter); typeSpinner.setAdapter(typeAdapter);
typeSpinner.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : TYPE_DUE_DATE); typeSpinner.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : TYPE_DUE_DATE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
for(int i = 0; i < 7; i++) {
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
weekdays[i] = Weekday.values()[dayOfWeek - 1];
calendar.add(Calendar.DATE, 1);
}
doRepeat = !Strings.isNullOrEmpty(recurrence);
if (doRepeat) {
try {
RRule rrule = new RRule(recurrence);
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)) {
isChecked[i] = true;
}
}
}
switch (rrule.getFreq()) {
case DAILY:
frequency = FREQUENCY_DAYS;
break;
case WEEKLY:
frequency = FREQUENCY_WEEKS;
break;
case MONTHLY:
frequency = FREQUENCY_MONTHS;
break;
case HOURLY:
frequency = FREQUENCY_HOURS;
break;
case MINUTELY:
frequency = FREQUENCY_MINUTES;
break;
case YEARLY:
frequency = FREQUENCY_YEARS;
break;
}
} catch (ParseException e) {
recurrence = "";
Timber.e(e, e.getMessage());
}
}
refreshDisplayView(); refreshDisplayView();
return view; return view;
} }
@OnItemSelected(R.id.repeatType) @OnItemSelected(R.id.repeatType)
public void onRepeatTypeChanged(Spinner spinner, int position) { public void onRepeatTypeChanged(int position) {
repeatAfterCompletion = position == TYPE_COMPLETION_DATE; repeatAfterCompletion = position == TYPE_COMPLETION_DATE;
repeatTypes.set(0, repeatAfterCompletion ? repeatTypes.get(2) : repeatTypes.get(1)); repeatTypes.set(0, repeatAfterCompletion ? repeatTypes.get(2) : repeatTypes.get(1));
typeAdapter.notifyDataSetChanged(); typeAdapter.notifyDataSetChanged();
@ -228,8 +169,7 @@ public class RepeatControlSet extends TaskEditControlFragment
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putString(EXTRA_RECURRENCE, getRecurrence()); outState.putString(EXTRA_RECURRENCE, rrule == null ? "" : rrule.toIcal());
outState.putLong(EXTRA_REPEAT_UNTIL, repeatUntilValue);
outState.putBoolean(EXTRA_REPEAT_AFTER_COMPLETION, repeatAfterCompletion); outState.putBoolean(EXTRA_REPEAT_AFTER_COMPLETION, repeatAfterCompletion);
} }
@ -246,14 +186,15 @@ public class RepeatControlSet extends TaskEditControlFragment
} }
private boolean isCustomValue() { private boolean isCustomValue() {
if (!doRepeat) { if (rrule == null) {
return false; return false;
} }
return frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b) || Frequency frequency = rrule.getFreq();
frequency == FREQUENCY_HOURS || return frequency == WEEKLY && !rrule.getByDay().isEmpty() ||
frequency == FREQUENCY_MINUTES || frequency == HOURLY ||
repeatUntilValue != 0 || frequency == MINUTELY ||
interval != 1; rrule.getUntil() != null ||
rrule.getInterval() != 1;
} }
@OnClick(R.id.display_row_edit) @OnClick(R.id.display_row_edit)
@ -264,21 +205,21 @@ public class RepeatControlSet extends TaskEditControlFragment
if (customPicked) { if (customPicked) {
adapter.insert(getRepeatString(), 0); adapter.insert(getRepeatString(), 0);
adapter.setChecked(0); adapter.setChecked(0);
} else if (!doRepeat) { } else if (rrule == null) {
adapter.setChecked(0); adapter.setChecked(0);
} else { } else {
int selected; int selected;
switch(frequency) { switch (rrule.getFreq()) {
case FREQUENCY_DAYS: case DAILY:
selected = 1; selected = 1;
break; break;
case FREQUENCY_WEEKS: case WEEKLY:
selected = 2; selected = 2;
break; break;
case FREQUENCY_MONTHS: case MONTHLY:
selected = 3; selected = 3;
break; break;
case FREQUENCY_YEARS: case YEARLY:
selected = 4; selected = 4;
break; break;
default: default:
@ -296,35 +237,33 @@ public class RepeatControlSet extends TaskEditControlFragment
i--; i--;
} }
if (i == 0) { if (i == 0) {
doRepeat = false; rrule = null;
} else if (i == 5) { } else if (i == 5) {
newCustomRecurrenceDialog(this) newCustomRecurrenceDialog(this, rrule)
.show(getFragmentManager(), FRAG_TAG_CUSTOM_RECURRENCE); .show(getFragmentManager(), FRAG_TAG_CUSTOM_RECURRENCE);
return; return;
} else { } else {
doRepeat = true; rrule = new RRule();
rrule.setInterval(1);
repeatAfterCompletion = false; repeatAfterCompletion = false;
interval = 1;
repeatUntilValue = 0;
switch (i) { switch (i) {
case 1: case 1:
frequency = FREQUENCY_DAYS; rrule.setFreq(DAILY);
break; break;
case 2: case 2:
frequency = FREQUENCY_WEEKS; rrule.setFreq(WEEKLY);
isChecked = new boolean[7];
break; break;
case 3: case 3:
frequency = FREQUENCY_MONTHS; rrule.setFreq(MONTHLY);
break; break;
case 4: case 4:
frequency = FREQUENCY_YEARS; rrule.setFreq(YEARLY);
break; break;
} }
} }
callback.repeatChanged(doRepeat); callback.repeatChanged(rrule != null);
refreshDisplayView(); refreshDisplayView();
}) })
@ -350,115 +289,89 @@ public class RepeatControlSet extends TaskEditControlFragment
@Override @Override
public void initialize(boolean isNewTask, Task task) { public void initialize(boolean isNewTask, Task task) {
repeatAfterCompletion = task.repeatAfterCompletion(); repeatAfterCompletion = task.repeatAfterCompletion();
recurrence = task.sanitizedRecurrence(); try {
repeatUntilValue = task.getRepeatUntil(); rrule = new RRule(task.getRecurrenceWithoutFrom());
rrule.setUntil(new DateTime(task.getRepeatUntil()).toDateValue());
} catch (ParseException e) {
rrule = null;
}
} }
@Override @Override
public boolean hasChanges(Task original) { public boolean hasChanges(Task original) {
return !getRecurrenceValue().equals(original.getRecurrence()) || repeatUntilValue != original.getRepeatUntil(); return !getRecurrenceValue().equals(original.getRecurrence()) ||
original.getRepeatUntil() != (rrule == null ? 0 : DateTime.from(rrule.getUntil()).getMillis());
} }
@Override @Override
public void apply(Task task) { public void apply(Task task) {
task.setRepeatUntil(rrule == null ? 0 : DateTime.from(rrule.getUntil()).getMillis());
task.setRecurrence(getRecurrenceValue()); task.setRecurrence(getRecurrenceValue());
task.setRepeatUntil(repeatUntilValue);
} }
private String getRecurrenceValue() { private String getRecurrenceValue() {
String result = getRecurrence(); if (rrule == null) {
return "";
if (repeatAfterCompletion && !TextUtils.isEmpty(result)) {
result += ";FROM=COMPLETION"; //$NON-NLS-1$
}
return result;
} }
RRule copy;
private String getRecurrence() { try {
String result; copy = new RRule(rrule.toIcal());
if(!doRepeat) { } catch (ParseException e) {
result = ""; //$NON-NLS-1$ return "";
} else {
RRule rrule = new RRule();
rrule.setInterval(interval);
switch(frequency) {
case FREQUENCY_DAYS:
rrule.setFreq(Frequency.DAILY);
break;
case FREQUENCY_WEEKS: {
rrule.setFreq(Frequency.WEEKLY);
ArrayList<WeekdayNum> days = new ArrayList<>();
for (int i = 0 ; i < isChecked.length ; i++) {
if (isChecked[i]) {
days.add(new WeekdayNum(0, weekdays[i]));
}
}
rrule.setByDay(days);
break;
}
case FREQUENCY_MONTHS:
rrule.setFreq(Frequency.MONTHLY);
break;
case FREQUENCY_HOURS:
rrule.setFreq(Frequency.HOURLY);
break;
case FREQUENCY_MINUTES:
rrule.setFreq(Frequency.MINUTELY);
break;
case FREQUENCY_YEARS:
rrule.setFreq(Frequency.YEARLY);
break;
} }
copy.setUntil(null);
result = rrule.toIcal(); String result = copy.toIcal();
if (repeatAfterCompletion && !TextUtils.isEmpty(result)) {
result += ";FROM=COMPLETION"; //$NON-NLS-1$
} }
return result; return result;
} }
private void refreshDisplayView() { private void refreshDisplayView() {
if (doRepeat) { if (rrule == null) {
displayView.setText(getRepeatString());
displayView.setTextColor(getColor(context, R.color.text_primary));
repeatTypeContainer.setVisibility(View.VISIBLE);
} else {
displayView.setText(R.string.repeat_option_does_not_repeat); displayView.setText(R.string.repeat_option_does_not_repeat);
displayView.setTextColor(getColor(context, R.color.text_tertiary)); displayView.setTextColor(getColor(context, R.color.text_tertiary));
repeatTypeContainer.setVisibility(View.GONE); repeatTypeContainer.setVisibility(View.GONE);
} else {
displayView.setText(getRepeatString());
displayView.setTextColor(getColor(context, R.color.text_primary));
repeatTypeContainer.setVisibility(View.VISIBLE);
} }
} }
private String getRepeatString() { private String getRepeatString() {
int interval = rrule.getInterval();
Frequency frequency = rrule.getFreq();
DateTime repeatUntil = rrule.getUntil() == null ? null : DateTime.from(rrule.getUntil());
if (interval == 1) { if (interval == 1) {
String frequencyString = getString(getSingleFrequencyResource(frequency)); String frequencyString = getString(getSingleFrequencyResource(frequency));
if (frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b)) { if (frequency == WEEKLY && !rrule.getByDay().isEmpty()) {
String dayString = getDayString(); String dayString = getDayString();
if (repeatUntilValue > 0) { if (repeatUntil == null) {
return getString(R.string.repeats_single_on_until, frequencyString, dayString, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
} else {
return getString(R.string.repeats_single_on, frequencyString, dayString); return getString(R.string.repeats_single_on, frequencyString, dayString);
}
} else if (repeatUntilValue > 0) {
return getString(R.string.repeats_single_until, frequencyString, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
} else { } else {
return getString(R.string.repeats_single_on_until, frequencyString, dayString, DateUtilities.getLongDateString(repeatUntil));
}
} else if (repeatUntil == null) {
return getString(R.string.repeats_single, frequencyString); return getString(R.string.repeats_single, frequencyString);
} else {
return getString(R.string.repeats_single_until, frequencyString, DateUtilities.getLongDateString(repeatUntil));
} }
} else { } else {
int plural = getFrequencyPlural(frequency); int plural = getFrequencyPlural(frequency);
String frequencyPlural = getResources().getQuantityString(plural, interval, interval); String frequencyPlural = getResources().getQuantityString(plural, interval, interval);
if (frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b)) { if (frequency == WEEKLY && !rrule.getByDay().isEmpty()) {
String dayString = getDayString(); String dayString = getDayString();
if (repeatUntilValue > 0) { if (repeatUntil == null) {
return getString(R.string.repeats_plural_on_until, frequencyPlural, dayString, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
} else {
return getString(R.string.repeats_plural_on, frequencyPlural, dayString); return getString(R.string.repeats_plural_on, frequencyPlural, dayString);
}
} else if (repeatUntilValue > 0) {
return getString(R.string.repeats_plural_until, frequencyPlural, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
} else { } else {
return getString(R.string.repeats_plural_on_until, frequencyPlural, dayString, DateUtilities.getLongDateString(repeatUntil));
}
} else if (repeatUntil == null) {
return getString(R.string.repeats_plural, frequencyPlural); return getString(R.string.repeats_plural, frequencyPlural);
} else {
return getString(R.string.repeats_plural_until, frequencyPlural, DateUtilities.getLongDateString(repeatUntil));
} }
} }
} }
@ -467,46 +380,44 @@ public class RepeatControlSet extends TaskEditControlFragment
DateFormatSymbols dfs = new DateFormatSymbols(locale.getLocale()); DateFormatSymbols dfs = new DateFormatSymbols(locale.getLocale());
String[] shortWeekdays = dfs.getShortWeekdays(); String[] shortWeekdays = dfs.getShortWeekdays();
List<String> days = new ArrayList<>(); List<String> days = new ArrayList<>();
for (int i = 0 ; i < 7 ; i++) { for (WeekdayNum weekday : rrule.getByDay()) {
if (isChecked[i]) { days.add(shortWeekdays[WEEKDAYS.indexOf(weekday.wday) + 1]);
days.add(shortWeekdays[i + 1]);
}
} }
return Joiner.on(getString(R.string.list_separator_with_space)).join(days); return Joiner.on(getString(R.string.list_separator_with_space)).join(days);
} }
private int getSingleFrequencyResource(int frequency) { private int getSingleFrequencyResource(Frequency frequency) {
switch (frequency) { switch (frequency) {
case FREQUENCY_MINUTES: case MINUTELY:
return R.string.repeats_minutely; return R.string.repeats_minutely;
case FREQUENCY_HOURS: case HOURLY:
return R.string.repeats_hourly; return R.string.repeats_hourly;
case FREQUENCY_DAYS: case DAILY:
return R.string.repeats_daily; return R.string.repeats_daily;
case FREQUENCY_WEEKS: case WEEKLY:
return R.string.repeats_weekly; return R.string.repeats_weekly;
case FREQUENCY_MONTHS: case MONTHLY:
return R.string.repeats_monthly; return R.string.repeats_monthly;
case FREQUENCY_YEARS: case YEARLY:
return R.string.repeats_yearly; return R.string.repeats_yearly;
default: default:
throw new RuntimeException("Invalid frequency: " + frequency); throw new RuntimeException("Invalid frequency: " + frequency);
} }
} }
private int getFrequencyPlural(int frequency) { private int getFrequencyPlural(Frequency frequency) {
switch (frequency) { switch (frequency) {
case FREQUENCY_MINUTES: case MINUTELY:
return R.plurals.repeat_n_minutes; return R.plurals.repeat_n_minutes;
case FREQUENCY_HOURS: case HOURLY:
return R.plurals.repeat_n_hours; return R.plurals.repeat_n_hours;
case FREQUENCY_DAYS: case DAILY:
return R.plurals.repeat_n_days; return R.plurals.repeat_n_days;
case FREQUENCY_WEEKS: case WEEKLY:
return R.plurals.repeat_n_weeks; return R.plurals.repeat_n_weeks;
case FREQUENCY_MONTHS: case MONTHLY:
return R.plurals.repeat_n_months; return R.plurals.repeat_n_months;
case FREQUENCY_YEARS: case YEARLY:
return R.plurals.repeat_n_years; return R.plurals.repeat_n_years;
default: default:
throw new RuntimeException("Invalid frequency: " + frequency); throw new RuntimeException("Invalid frequency: " + frequency);

@ -19,9 +19,12 @@ import android.widget.TextView;
import com.appeaser.sublimepickerlibrary.drawables.CheckableDrawable; import com.appeaser.sublimepickerlibrary.drawables.CheckableDrawable;
import com.appeaser.sublimepickerlibrary.recurrencepicker.WeekButton; import com.appeaser.sublimepickerlibrary.recurrencepicker.WeekButton;
import com.google.common.base.Strings;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.google.ical.values.WeekdayNum;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.repeats.RepeatControlSet;
import org.tasks.R; import org.tasks.R;
import org.tasks.activities.DatePickerActivity; import org.tasks.activities.DatePickerActivity;
@ -36,8 +39,10 @@ import org.tasks.themes.ThemeAccent;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -46,29 +51,39 @@ import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnItemSelected; import butterknife.OnItemSelected;
import butterknife.OnTextChanged; import butterknife.OnTextChanged;
import timber.log.Timber;
import static android.support.v4.content.ContextCompat.getColor; import static android.support.v4.content.ContextCompat.getColor;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_DAYS; import static com.google.ical.values.Frequency.DAILY;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_HOURS; import static com.google.ical.values.Frequency.HOURLY;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_MINUTES; import static com.google.ical.values.Frequency.MINUTELY;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_MONTHS; import static com.google.ical.values.Frequency.MONTHLY;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_WEEKS; import static com.google.ical.values.Frequency.WEEKLY;
import static com.todoroo.astrid.repeats.RepeatControlSet.FREQUENCY_YEARS; import static com.google.ical.values.Frequency.YEARLY;
import static com.todoroo.astrid.repeats.RepeatControlSet.TYPE_COMPLETION_DATE; import static com.todoroo.astrid.repeats.RepeatControlSet.WEEKDAYS;
import static java.util.Arrays.asList;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
public class CustomRecurrenceDialog extends InjectingDialogFragment { public class CustomRecurrenceDialog extends InjectingDialogFragment {
public static CustomRecurrenceDialog newCustomRecurrenceDialog(Fragment target) { public static CustomRecurrenceDialog newCustomRecurrenceDialog(Fragment target, RRule rrule) {
CustomRecurrenceDialog dialog = new CustomRecurrenceDialog(); CustomRecurrenceDialog dialog = new CustomRecurrenceDialog();
dialog.setTargetFragment(target, 0); dialog.setTargetFragment(target, 0);
Bundle arguments = new Bundle();
if (rrule != null) {
arguments.putString(EXTRA_RRULE, rrule.toIcal());
}
dialog.setArguments(arguments);
return dialog; return dialog;
} }
public interface CustomRecurrenceCallback { public interface CustomRecurrenceCallback {
void onSelected(int frequency, int interval, long repeatUntilValue, boolean[] isChecked); void onSelected(RRule rrule);
} }
private static final List<Frequency> FREQUENCIES = asList(MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY);
private static final String EXTRA_RRULE = "extra_rrule";
private static final int REQUEST_PICK_DATE = 505; private static final int REQUEST_PICK_DATE = 505;
@Inject @ForActivity Context context; @Inject @ForActivity Context context;
@ -93,11 +108,8 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
private ArrayAdapter<String> repeatUntilAdapter; private ArrayAdapter<String> repeatUntilAdapter;
private final List<String> repeatUntilOptions = new ArrayList<>(); private final List<String> repeatUntilOptions = new ArrayList<>();
private final boolean[] isChecked = new boolean[7];
private int frequency; private RRule rrule;
private int interval;
private long repeatUntilValue;
@NonNull @NonNull
@Override @Override
@ -105,23 +117,33 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
LayoutInflater inflater = LayoutInflater.from(getActivity()); LayoutInflater inflater = LayoutInflater.from(getActivity());
View dialogView = inflater.inflate(R.layout.control_set_repeat, null); View dialogView = inflater.inflate(R.layout.control_set_repeat, null);
Bundle arguments = getArguments();
String rule = arguments.getString(EXTRA_RRULE);
if (!Strings.isNullOrEmpty(rule)) {
try {
rrule = new RRule(rule);
} catch (Exception ignored) {
}
}
if (rrule == null) {
rrule = new RRule();
rrule.setInterval(1);
rrule.setFreq(WEEKLY);
}
ButterKnife.bind(this, dialogView); ButterKnife.bind(this, dialogView);
ArrayAdapter<CharSequence> frequencyAdapter = ArrayAdapter.createFromResource(context, R.array.repeat_frequency, R.layout.frequency_item); ArrayAdapter<CharSequence> frequencyAdapter = ArrayAdapter.createFromResource(context, R.array.repeat_frequency, R.layout.frequency_item);
frequencyAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); frequencyAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
frequencySpinner.setAdapter(frequencyAdapter); frequencySpinner.setAdapter(frequencyAdapter);
frequencySpinner.setSelection(3); frequencySpinner.setSelection(FREQUENCIES.indexOf(rrule.getFreq()));
intervalEditText.setText(locale.formatNumber(1));
intervalEditText.setSelectAllOnFocus(true); intervalEditText.setText(locale.formatNumber(rrule.getInterval()));
intervalEditText.selectAll();
repeatUntilAdapter = new ArrayAdapter<>(context, R.layout.simple_spinner_item, repeatUntilOptions); repeatUntilAdapter = new ArrayAdapter<>(context, R.layout.simple_spinner_item, repeatUntilOptions);
repeatUntilAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); repeatUntilAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
repeatUntilSpinner.setAdapter(repeatUntilAdapter); repeatUntilSpinner.setAdapter(repeatUntilAdapter);
updateRepeatUntilOptions();
setInterval(1, true);
setRepeatUntilValue(repeatUntilValue);
WeekButton[] weekButtons = new WeekButton[] { day1, day2, day3, day4, day5, day6, day7 }; WeekButton[] weekButtons = new WeekButton[] { day1, day2, day3, day4, day5, day6, day7 };
int expandedWidthHeight = getResources() int expandedWidthHeight = getResources()
@ -137,32 +159,55 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek()); calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
String[] shortWeekdays = dfs.getShortWeekdays(); String[] shortWeekdays = dfs.getShortWeekdays();
for(int i = 0; i < 7; i++) { for(int i = 0; i < 7; i++) {
final int index = i; String text = shortWeekdays[calendar.get(Calendar.DAY_OF_WEEK)];
WeekButton weekButton = weekButtons[index]; WeekdayNum weekdayNum = new WeekdayNum(0, WEEKDAYS.get(i));
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); WeekButton weekButton = weekButtons[i];
String text = shortWeekdays[dayOfWeek];
weekButton.setBackgroundDrawable(new CheckableDrawable(accent.getAccentColor(), false, expandedWidthHeight)); weekButton.setBackgroundDrawable(new CheckableDrawable(accent.getAccentColor(), false, expandedWidthHeight));
weekButton.setTextColor(weekButtonUnselectedTextColor); weekButton.setTextColor(weekButtonUnselectedTextColor);
weekButton.setTextOff(text); weekButton.setTextOff(text);
weekButton.setTextOn(text); weekButton.setTextOn(text);
weekButton.setText(text); weekButton.setText(text);
weekButton.setOnCheckedChangeListener((compoundButton, b) -> CustomRecurrenceDialog.this.isChecked[index] = b); if (rrule.getByDay().contains(weekdayNum)) {
weekButton.setChecked(true);
}
weekButton.setOnCheckedChangeListener((compoundButton, b) -> {
List<WeekdayNum> days = rrule.getByDay();
if (b) {
days.add(weekdayNum);
} else {
days.remove(weekdayNum);
}
});
calendar.add(Calendar.DATE, 1); calendar.add(Calendar.DATE, 1);
} }
return dialogBuilder.newDialog() return dialogBuilder.newDialog()
.setView(dialogView) .setView(dialogView)
.setPositiveButton(android.R.string.ok, (dialog12, which) -> .setPositiveButton(android.R.string.ok, (dialog12, which) -> {
((CustomRecurrenceCallback) getTargetFragment()) if (rrule.getFreq() != WEEKLY) {
.onSelected(frequency, interval, repeatUntilValue, isChecked)) rrule.setByDay(Collections.emptyList());
}
((CustomRecurrenceCallback) getTargetFragment()).onSelected(rrule);
})
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setOnCancelListener(DialogInterface::dismiss) .setOnCancelListener(DialogInterface::dismiss)
.show(); .show();
} }
private void setFrequency(Frequency frequency) {
rrule.setFreq(frequency);
int weekVisibility = frequency == WEEKLY ? View.VISIBLE : View.GONE;
weekGroup1.setVisibility(weekVisibility);
if (weekGroup2 != null) {
weekGroup2.setVisibility(weekVisibility);
}
updateIntervalTextView();
}
private void setInterval(int interval, boolean updateEditText) { private void setInterval(int interval, boolean updateEditText) {
this.interval = interval; rrule.setInterval(interval);
if (updateEditText) { if (updateEditText) {
intervalEditText.setText(locale.formatNumber(interval)); intervalEditText.setText(locale.formatNumber(interval));
} }
@ -171,31 +216,31 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
private void updateIntervalTextView() { private void updateIntervalTextView() {
int resource = getFrequencyPlural(); int resource = getFrequencyPlural();
String quantityString = getResources().getQuantityString(resource, interval); String quantityString = getResources().getQuantityString(resource, rrule.getInterval());
intervalTextView.setText(quantityString); intervalTextView.setText(quantityString);
} }
private int getFrequencyPlural() { private int getFrequencyPlural() {
switch (frequency) { switch (rrule.getFreq()) {
case FREQUENCY_MINUTES: case MINUTELY:
return R.plurals.repeat_minutes; return R.plurals.repeat_minutes;
case FREQUENCY_HOURS: case HOURLY:
return R.plurals.repeat_hours; return R.plurals.repeat_hours;
case FREQUENCY_DAYS: case DAILY:
return R.plurals.repeat_days; return R.plurals.repeat_days;
case FREQUENCY_WEEKS: case WEEKLY:
return R.plurals.repeat_weeks; return R.plurals.repeat_weeks;
case FREQUENCY_MONTHS: case MONTHLY:
return R.plurals.repeat_months; return R.plurals.repeat_months;
case FREQUENCY_YEARS: case YEARLY:
return R.plurals.repeat_years; return R.plurals.repeat_years;
default: default:
throw new RuntimeException("Invalid frequency: " + frequency); throw new RuntimeException("Invalid frequency: " + rrule.getFreq());
} }
} }
@OnItemSelected(R.id.repeat_until) @OnItemSelected(R.id.repeat_until)
public void onRepeatUntilChanged(Spinner spinner, int position) { public void onRepeatUntilChanged(int position) {
if (repeatUntilOptions.size() == 2) { if (repeatUntilOptions.size() == 2) {
if (position == 0) { if (position == 0) {
setRepeatUntilValue(0); setRepeatUntilValue(0);
@ -212,14 +257,8 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
} }
@OnItemSelected(R.id.frequency) @OnItemSelected(R.id.frequency)
public void onFrequencyChanged(Spinner spinner, int position) { public void onFrequencyChanged(int position) {
int weekVisibility = position == RepeatControlSet.FREQUENCY_WEEKS ? View.VISIBLE : View.GONE; setFrequency(FREQUENCIES.get(position));
weekGroup1.setVisibility(weekVisibility);
if (weekGroup2 != null) {
weekGroup2.setVisibility(weekVisibility);
}
frequency = position;
updateIntervalTextView();
} }
@OnTextChanged(R.id.repeatValue) @OnTextChanged(R.id.repeatValue)
@ -236,20 +275,22 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
} }
private void setRepeatUntilValue(long newValue) { private void setRepeatUntilValue(long newValue) {
repeatUntilValue = newValue; rrule.setUntil(new DateTime(newValue).toDateValue());
updateRepeatUntilOptions(); updateRepeatUntilOptions();
} }
private void repeatUntilClick() { private void repeatUntilClick() {
Intent intent = new Intent(context, DatePickerActivity.class); Intent intent = new Intent(context, DatePickerActivity.class);
intent.putExtra(DatePickerActivity.EXTRA_TIMESTAMP, repeatUntilValue > 0 ? repeatUntilValue : 0L); long repeatUntil = DateTime.from(rrule.getUntil()).getMillis();
intent.putExtra(DatePickerActivity.EXTRA_TIMESTAMP, repeatUntil > 0 ? repeatUntil : 0L);
startActivityForResult(intent, REQUEST_PICK_DATE); startActivityForResult(intent, REQUEST_PICK_DATE);
} }
private void updateRepeatUntilOptions() { private void updateRepeatUntilOptions() {
repeatUntilOptions.clear(); repeatUntilOptions.clear();
if (repeatUntilValue > 0) { long repeatUntil = DateTime.from(rrule.getUntil()).getMillis();
repeatUntilOptions.add(getString(R.string.repeat_until, getDisplayString(context, repeatUntilValue))); if (repeatUntil > 0) {
repeatUntilOptions.add(getString(R.string.repeat_until, getDisplayString(context, repeatUntil)));
} }
repeatUntilOptions.add(getString(R.string.repeat_forever)); repeatUntilOptions.add(getString(R.string.repeat_forever));
repeatUntilOptions.add(getString(R.string.repeat_until, "").trim()); repeatUntilOptions.add(getString(R.string.repeat_until, "").trim());
@ -263,7 +304,7 @@ public class CustomRecurrenceDialog extends InjectingDialogFragment {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
setRepeatUntilValue(data.getLongExtra(DatePickerActivity.EXTRA_TIMESTAMP, 0L)); setRepeatUntilValue(data.getLongExtra(DatePickerActivity.EXTRA_TIMESTAMP, 0L));
} else { } else {
setRepeatUntilValue(repeatUntilValue); setRepeatUntilValue(DateTime.from(rrule.getUntil()).getMillis());
} }
} }
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);

@ -1,5 +1,8 @@
package org.tasks.time; package org.tasks.time;
import com.google.ical.values.DateValue;
import com.google.ical.values.DateValueImpl;
import org.tasks.locale.Locale; import org.tasks.locale.Locale;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -19,6 +22,12 @@ public class DateTime {
private final TimeZone timeZone; private final TimeZone timeZone;
private final long timestamp; private final long timestamp;
public static DateTime from(DateValue dateValue) {
return dateValue == null
? new DateTime(0)
: new DateTime(dateValue.year(), dateValue.month(), dateValue.day());
}
public DateTime(int year, int month, int day) { public DateTime(int year, int month, int day) {
this(year, month, day, 0, 0, 0, 0); this(year, month, day, 0, 0, 0, 0);
} }
@ -268,6 +277,12 @@ public class DateTime {
return calendar; return calendar;
} }
public DateValue toDateValue() {
return timestamp == 0
? null
: new DateValueImpl(getYear(), getMonthOfYear(), getDayOfMonth());
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;

Loading…
Cancel
Save