|
|
@ -7,15 +7,24 @@ package com.todoroo.astrid.repeats;
|
|
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.app.Activity;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
import android.os.Bundle;
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
|
|
|
import android.support.annotation.NonNull;
|
|
|
|
import android.support.annotation.Nullable;
|
|
|
|
import android.support.annotation.Nullable;
|
|
|
|
|
|
|
|
import android.support.v4.content.ContextCompat;
|
|
|
|
|
|
|
|
import android.support.v4.graphics.drawable.DrawableCompat;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
import android.view.ViewGroup;
|
|
|
|
|
|
|
|
import android.widget.AdapterView;
|
|
|
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
|
|
|
import android.widget.Spinner;
|
|
|
|
import android.widget.TextView;
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
@ -27,15 +36,19 @@ import org.tasks.R;
|
|
|
|
import org.tasks.dialogs.DialogBuilder;
|
|
|
|
import org.tasks.dialogs.DialogBuilder;
|
|
|
|
import org.tasks.injection.ForActivity;
|
|
|
|
import org.tasks.injection.ForActivity;
|
|
|
|
import org.tasks.injection.FragmentComponent;
|
|
|
|
import org.tasks.injection.FragmentComponent;
|
|
|
|
|
|
|
|
import org.tasks.locale.Locale;
|
|
|
|
import org.tasks.preferences.Preferences;
|
|
|
|
import org.tasks.preferences.Preferences;
|
|
|
|
import org.tasks.repeats.CustomRecurrenceDialog;
|
|
|
|
import org.tasks.repeats.CustomRecurrenceDialog;
|
|
|
|
import org.tasks.themes.Theme;
|
|
|
|
import org.tasks.themes.Theme;
|
|
|
|
import org.tasks.time.DateTime;
|
|
|
|
import org.tasks.time.DateTime;
|
|
|
|
|
|
|
|
import org.tasks.ui.HiddenTopArrayAdapter;
|
|
|
|
import org.tasks.ui.SingleCheckedArrayAdapter;
|
|
|
|
import org.tasks.ui.SingleCheckedArrayAdapter;
|
|
|
|
import org.tasks.ui.TaskEditControlFragment;
|
|
|
|
import org.tasks.ui.TaskEditControlFragment;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.Calendar;
|
|
|
|
import java.util.Calendar;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
@ -43,11 +56,12 @@ import javax.inject.Inject;
|
|
|
|
|
|
|
|
|
|
|
|
import butterknife.BindView;
|
|
|
|
import butterknife.BindView;
|
|
|
|
import butterknife.OnClick;
|
|
|
|
import butterknife.OnClick;
|
|
|
|
|
|
|
|
import butterknife.OnItemSelected;
|
|
|
|
import timber.log.Timber;
|
|
|
|
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 org.tasks.date.DateTimeUtils.newDateTime;
|
|
|
|
|
|
|
|
import static org.tasks.repeats.CustomRecurrenceDialog.newCustomRecurrenceDialog;
|
|
|
|
import static org.tasks.repeats.CustomRecurrenceDialog.newCustomRecurrenceDialog;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -63,14 +77,12 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
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,
|
|
|
|
public void onSelected(int frequency, int interval, long repeatUntilValue, boolean[] isChecked) {
|
|
|
|
boolean repeatAfterCompletion, boolean[] isChecked) {
|
|
|
|
|
|
|
|
doRepeat = true;
|
|
|
|
doRepeat = true;
|
|
|
|
this.interval = interval;
|
|
|
|
this.interval = interval;
|
|
|
|
this.frequency = frequency;
|
|
|
|
this.frequency = frequency;
|
|
|
|
this.repeatUntilValue = repeatUntilValue;
|
|
|
|
this.repeatUntilValue = repeatUntilValue;
|
|
|
|
this.isChecked = isChecked;
|
|
|
|
this.isChecked = isChecked;
|
|
|
|
this.repeatAfterCompletion = repeatAfterCompletion;
|
|
|
|
|
|
|
|
refreshDisplayView();
|
|
|
|
refreshDisplayView();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -101,8 +113,11 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
@Inject Preferences preferences;
|
|
|
|
@Inject Preferences preferences;
|
|
|
|
@Inject @ForActivity Context context;
|
|
|
|
@Inject @ForActivity Context context;
|
|
|
|
@Inject Theme theme;
|
|
|
|
@Inject Theme theme;
|
|
|
|
|
|
|
|
@Inject Locale locale;
|
|
|
|
|
|
|
|
|
|
|
|
@BindView(R.id.display_row_edit) TextView displayView;
|
|
|
|
@BindView(R.id.display_row_edit) TextView displayView;
|
|
|
|
|
|
|
|
@BindView(R.id.repeatType) Spinner typeSpinner;
|
|
|
|
|
|
|
|
@BindView(R.id.repeatTypeContainer) LinearLayout repeatTypeContainer;
|
|
|
|
|
|
|
|
|
|
|
|
private String recurrence;
|
|
|
|
private String recurrence;
|
|
|
|
private int interval;
|
|
|
|
private int interval;
|
|
|
@ -110,6 +125,8 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
private long repeatUntilValue;
|
|
|
|
private long repeatUntilValue;
|
|
|
|
private boolean[] isChecked;
|
|
|
|
private boolean[] isChecked;
|
|
|
|
private final Weekday[] weekdays = new Weekday[7];
|
|
|
|
private final Weekday[] weekdays = new Weekday[7];
|
|
|
|
|
|
|
|
private final List<String> repeatTypes = new ArrayList<>();
|
|
|
|
|
|
|
|
private HiddenTopArrayAdapter<String> typeAdapter;
|
|
|
|
|
|
|
|
|
|
|
|
private RepeatChangedListener callback;
|
|
|
|
private RepeatChangedListener callback;
|
|
|
|
|
|
|
|
|
|
|
@ -125,6 +142,29 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION);
|
|
|
|
repeatAfterCompletion = savedInstanceState.getBoolean(EXTRA_REPEAT_AFTER_COMPLETION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
repeatTypes.add("");
|
|
|
|
|
|
|
|
repeatTypes.addAll(Arrays.asList(getResources().getStringArray(R.array.repeat_type)));
|
|
|
|
|
|
|
|
typeAdapter = new HiddenTopArrayAdapter<String>(context, 0, repeatTypes) {
|
|
|
|
|
|
|
|
@NonNull
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
|
|
|
|
|
|
|
|
int selectedItemPosition = position;
|
|
|
|
|
|
|
|
if (parent instanceof AdapterView) {
|
|
|
|
|
|
|
|
selectedItemPosition = ((AdapterView) parent).getSelectedItemPosition();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TextView tv = (TextView) inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
|
|
|
|
|
|
|
|
tv.setPadding(0, 0, 0, 0);
|
|
|
|
|
|
|
|
tv.setText(repeatTypes.get(selectedItemPosition));
|
|
|
|
|
|
|
|
return tv;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Drawable drawable = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.textfield_underline_black));
|
|
|
|
|
|
|
|
drawable.mutate();
|
|
|
|
|
|
|
|
DrawableCompat.setTint(drawable, getColor(context, R.color.text_primary));
|
|
|
|
|
|
|
|
typeSpinner.setBackgroundDrawable(drawable);
|
|
|
|
|
|
|
|
typeSpinner.setAdapter(typeAdapter);
|
|
|
|
|
|
|
|
typeSpinner.setSelection(repeatAfterCompletion ? TYPE_COMPLETION_DATE : TYPE_DUE_DATE);
|
|
|
|
|
|
|
|
|
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
|
Calendar calendar = Calendar.getInstance();
|
|
|
|
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
|
|
|
|
calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
|
|
|
|
for(int i = 0; i < 7; i++) {
|
|
|
|
for(int i = 0; i < 7; i++) {
|
|
|
@ -177,6 +217,13 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
return view;
|
|
|
|
return view;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@OnItemSelected(R.id.repeatType)
|
|
|
|
|
|
|
|
public void onRepeatTypeChanged(Spinner spinner, int position) {
|
|
|
|
|
|
|
|
repeatAfterCompletion = position == TYPE_COMPLETION_DATE;
|
|
|
|
|
|
|
|
repeatTypes.set(0, repeatAfterCompletion ? repeatTypes.get(2) : repeatTypes.get(1));
|
|
|
|
|
|
|
|
typeAdapter.notifyDataSetChanged();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
@ -202,16 +249,11 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
if (!doRepeat) {
|
|
|
|
if (!doRepeat) {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (frequency == FREQUENCY_WEEKS) {
|
|
|
|
return frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b) ||
|
|
|
|
for (boolean checked : isChecked) {
|
|
|
|
frequency == FREQUENCY_HOURS ||
|
|
|
|
if (checked) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return frequency == FREQUENCY_HOURS ||
|
|
|
|
|
|
|
|
frequency == FREQUENCY_MINUTES ||
|
|
|
|
frequency == FREQUENCY_MINUTES ||
|
|
|
|
!(repeatUntilValue == 0 && interval == 1 && !repeatAfterCompletion);
|
|
|
|
repeatUntilValue != 0 ||
|
|
|
|
|
|
|
|
interval != 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@OnClick(R.id.display_row_edit)
|
|
|
|
@OnClick(R.id.display_row_edit)
|
|
|
@ -380,52 +422,94 @@ public class RepeatControlSet extends TaskEditControlFragment
|
|
|
|
if (doRepeat) {
|
|
|
|
if (doRepeat) {
|
|
|
|
displayView.setText(getRepeatString());
|
|
|
|
displayView.setText(getRepeatString());
|
|
|
|
displayView.setTextColor(getColor(context, R.color.text_primary));
|
|
|
|
displayView.setTextColor(getColor(context, R.color.text_primary));
|
|
|
|
|
|
|
|
repeatTypeContainer.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String getRepeatString() {
|
|
|
|
private String getRepeatString() {
|
|
|
|
if (!isCustomValue()) {
|
|
|
|
if (interval == 1) {
|
|
|
|
switch (frequency) {
|
|
|
|
String frequencyString = getString(getSingleFrequencyResource(frequency));
|
|
|
|
case FREQUENCY_DAYS:
|
|
|
|
if (frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b)) {
|
|
|
|
return getString(R.string.repeat_option_every_day);
|
|
|
|
String dayString = getDayString();
|
|
|
|
case FREQUENCY_WEEKS:
|
|
|
|
if (repeatUntilValue > 0) {
|
|
|
|
return getString(R.string.repeat_option_every_week);
|
|
|
|
return getString(R.string.repeats_single_on_until, frequencyString, dayString, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
|
|
|
|
case FREQUENCY_MONTHS:
|
|
|
|
} else {
|
|
|
|
return getString(R.string.repeat_option_every_month);
|
|
|
|
return getString(R.string.repeats_single_on, frequencyString, dayString);
|
|
|
|
case FREQUENCY_YEARS:
|
|
|
|
}
|
|
|
|
return getString(R.string.repeat_option_every_year);
|
|
|
|
} else if (repeatUntilValue > 0) {
|
|
|
|
|
|
|
|
return getString(R.string.repeats_single_until, frequencyString, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return getString(R.string.repeats_single, frequencyString);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
int plural = getFrequencyPlural(frequency);
|
|
|
|
|
|
|
|
String frequencyPlural = getResources().getQuantityString(plural, interval, interval);
|
|
|
|
|
|
|
|
if (frequency == FREQUENCY_WEEKS && any(Booleans.asList(isChecked), b -> b)) {
|
|
|
|
|
|
|
|
String dayString = getDayString();
|
|
|
|
|
|
|
|
if (repeatUntilValue > 0) {
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (repeatUntilValue > 0) {
|
|
|
|
|
|
|
|
return getString(R.string.repeats_plural_until, frequencyPlural, DateUtilities.getLongDateString(new DateTime(repeatUntilValue)));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return getString(R.string.repeats_plural, frequencyPlural);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int arrayResource = R.array.repeat_interval;
|
|
|
|
private String getDayString() {
|
|
|
|
|
|
|
|
DateFormatSymbols dfs = new DateFormatSymbols(locale.getLocale());
|
|
|
|
String[] dates = getResources().getStringArray(
|
|
|
|
String[] shortWeekdays = dfs.getShortWeekdays();
|
|
|
|
arrayResource);
|
|
|
|
List<String> days = new ArrayList<>();
|
|
|
|
String date = String.format("%s %s", interval, dates[frequency]); //$NON-NLS-1$
|
|
|
|
for (int i = 0 ; i < 7 ; i++) {
|
|
|
|
if (repeatUntilValue > 0) {
|
|
|
|
if (isChecked[i]) {
|
|
|
|
return getString(R.string.repeat_detail_duedate_until, date, getDisplayString());
|
|
|
|
days.add(shortWeekdays[i + 1]);
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
return getString(R.string.repeat_detail_duedate, date); // Every freq int
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Joiner.on(getString(R.string.list_separator_with_space)).join(days);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String getDisplayString() {
|
|
|
|
private int getSingleFrequencyResource(int frequency) {
|
|
|
|
return getDisplayString(context, repeatUntilValue);
|
|
|
|
switch (frequency) {
|
|
|
|
|
|
|
|
case FREQUENCY_MINUTES:
|
|
|
|
|
|
|
|
return R.string.repeats_minutely;
|
|
|
|
|
|
|
|
case FREQUENCY_HOURS:
|
|
|
|
|
|
|
|
return R.string.repeats_hourly;
|
|
|
|
|
|
|
|
case FREQUENCY_DAYS:
|
|
|
|
|
|
|
|
return R.string.repeats_daily;
|
|
|
|
|
|
|
|
case FREQUENCY_WEEKS:
|
|
|
|
|
|
|
|
return R.string.repeats_weekly;
|
|
|
|
|
|
|
|
case FREQUENCY_MONTHS:
|
|
|
|
|
|
|
|
return R.string.repeats_monthly;
|
|
|
|
|
|
|
|
case FREQUENCY_YEARS:
|
|
|
|
|
|
|
|
return R.string.repeats_yearly;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
throw new RuntimeException("Invalid frequency: " + frequency);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static String getDisplayString(Context context, long repeatUntilValue) {
|
|
|
|
private int getFrequencyPlural(int frequency) {
|
|
|
|
StringBuilder displayString = new StringBuilder();
|
|
|
|
switch (frequency) {
|
|
|
|
DateTime d = newDateTime(repeatUntilValue);
|
|
|
|
case FREQUENCY_MINUTES:
|
|
|
|
if (d.getMillis() > 0) {
|
|
|
|
return R.plurals.repeat_n_minutes;
|
|
|
|
displayString.append(DateUtilities.getDateString(d));
|
|
|
|
case FREQUENCY_HOURS:
|
|
|
|
if (Task.hasDueTime(repeatUntilValue)) {
|
|
|
|
return R.plurals.repeat_n_hours;
|
|
|
|
displayString.append(", "); //$NON-NLS-1$ //$NON-NLS-2$
|
|
|
|
case FREQUENCY_DAYS:
|
|
|
|
displayString.append(DateUtilities.getTimeString(context, repeatUntilValue));
|
|
|
|
return R.plurals.repeat_n_days;
|
|
|
|
}
|
|
|
|
case FREQUENCY_WEEKS:
|
|
|
|
|
|
|
|
return R.plurals.repeat_n_weeks;
|
|
|
|
|
|
|
|
case FREQUENCY_MONTHS:
|
|
|
|
|
|
|
|
return R.plurals.repeat_n_months;
|
|
|
|
|
|
|
|
case FREQUENCY_YEARS:
|
|
|
|
|
|
|
|
return R.plurals.repeat_n_years;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
throw new RuntimeException("Invalid frequency: " + frequency);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return displayString.toString();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|