diff --git a/app/src/main/java/org/tasks/repeats/RepeatRuleToString.java b/app/src/main/java/org/tasks/repeats/RepeatRuleToString.java deleted file mode 100644 index 2f1c90d07..000000000 --- a/app/src/main/java/org/tasks/repeats/RepeatRuleToString.java +++ /dev/null @@ -1,227 +0,0 @@ -package org.tasks.repeats; - -import static com.todoroo.astrid.data.Task.withoutRRULE; -import static net.fortuna.ical4j.model.Recur.Frequency.MONTHLY; -import static net.fortuna.ical4j.model.Recur.Frequency.WEEKLY; - -import android.content.Context; -import com.google.common.base.Joiner; -import com.todoroo.andlib.utility.DateUtilities; -import dagger.hilt.android.qualifiers.ApplicationContext; -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.List; -import javax.inject.Inject; -import net.fortuna.ical4j.model.Recur; -import net.fortuna.ical4j.model.Recur.Frequency; -import net.fortuna.ical4j.model.WeekDay; -import net.fortuna.ical4j.model.WeekDay.Day; -import net.fortuna.ical4j.model.property.RRule; -import org.tasks.R; -import org.tasks.analytics.Firebase; -import org.tasks.locale.Locale; -import org.tasks.time.DateTime; - -public class RepeatRuleToString { - - private final Context context; - private final Locale locale; - private final Firebase firebase; - private final List weekdays = Arrays.asList(Day.values()); - - @Inject - public RepeatRuleToString( - @ApplicationContext Context context, - Locale locale, - Firebase firebase - ) { - this.context = context; - this.locale = locale; - this.firebase = firebase; - } - - public String toString(String rrule) { - try { - return toString(new RRule(withoutRRULE(rrule))); - } catch (ParseException e) { - firebase.reportException(e); - } - return null; - } - - public String toString(RRule r) { - Recur rrule = r.getRecur(); - int interval = rrule.getInterval(); - Frequency frequency = rrule.getFrequency(); - DateTime repeatUntil = rrule.getUntil() == null ? null : DateTime.from(rrule.getUntil()); - int count = rrule.getCount(); - String countString = - count > 0 ? context.getResources().getQuantityString(R.plurals.repeat_times, count) : ""; - if (interval <= 1) { - String frequencyString = context.getString(getSingleFrequencyResource(frequency)); - if ((frequency == WEEKLY || frequency == MONTHLY) && !rrule.getDayList().isEmpty()) { - String dayString = getDayString(rrule); - if (count > 0) { - return context.getString( - R.string.repeats_single_on_number_of_times, - frequencyString, - dayString, - count, - countString); - } else if (repeatUntil == null) { - return context.getString(R.string.repeats_single_on, frequencyString, dayString); - } else { - return context.getString( - R.string.repeats_single_on_until, - frequencyString, - dayString, - DateUtilities.getLongDateString(repeatUntil, locale.getLocale())); - } - } else if (count > 0) { - return context.getString( - R.string.repeats_single_number_of_times, frequencyString, count, countString); - } else if (repeatUntil == null) { - return context.getString(R.string.repeats_single, frequencyString); - } else { - return context.getString( - R.string.repeats_single_until, - frequencyString, - DateUtilities.getLongDateString(repeatUntil, locale.getLocale())); - } - } else { - int plural = getFrequencyPlural(frequency); - String frequencyPlural = context.getResources().getQuantityString(plural, interval, interval); - if ((frequency == WEEKLY || frequency == MONTHLY) && !rrule.getDayList().isEmpty()) { - String dayString = getDayString(rrule); - if (count > 0) { - return context.getString( - R.string.repeats_plural_on_number_of_times, - frequencyPlural, - dayString, - count, - countString); - } else if (repeatUntil == null) { - return context.getString(R.string.repeats_plural_on, frequencyPlural, dayString); - } else { - return context.getString( - R.string.repeats_plural_on_until, - frequencyPlural, - dayString, - DateUtilities.getLongDateString(repeatUntil, locale.getLocale())); - } - } else if (count > 0) { - return context.getString( - R.string.repeats_plural_number_of_times, frequencyPlural, count, countString); - } else if (repeatUntil == null) { - return context.getString(R.string.repeats_plural, frequencyPlural); - } else { - return context.getString( - R.string.repeats_plural_until, - frequencyPlural, - DateUtilities.getLongDateString(repeatUntil, locale.getLocale())); - } - } - } - - private String getDayString(Recur rrule) { - DateFormatSymbols dfs = new DateFormatSymbols(locale.getLocale()); - if (rrule.getFrequency() == WEEKLY) { - String[] shortWeekdays = dfs.getShortWeekdays(); - List days = new ArrayList<>(); - for (WeekDay weekday : rrule.getDayList()) { - days.add(shortWeekdays[weekdays.indexOf(weekday.getDay()) + 1]); - } - return Joiner.on(context.getString(R.string.list_separator_with_space)).join(days); - } else if (rrule.getFrequency() == MONTHLY) { - String[] longWeekdays = dfs.getWeekdays(); - WeekDay weekdayNum = rrule.getDayList().get(0); - String weekday; - Calendar dayOfWeekCalendar = Calendar.getInstance(locale.getLocale()); - dayOfWeekCalendar.set(Calendar.DAY_OF_WEEK, weekdayToCalendarDay(weekdayNum.getDay())); - weekday = longWeekdays[dayOfWeekCalendar.get(Calendar.DAY_OF_WEEK)]; - if (weekdayNum.getOffset() == -1) { - return context.getString( - R.string.repeat_monthly_every_day_of_nth_week, - context.getString(R.string.repeat_monthly_last_week), - weekday); - } else { - int[] resources = - new int[] { - R.string.repeat_monthly_first_week, - R.string.repeat_monthly_second_week, - R.string.repeat_monthly_third_week, - R.string.repeat_monthly_fourth_week, - R.string.repeat_monthly_fifth_week - }; - return context.getString( - R.string.repeat_monthly_every_day_of_nth_week, - context.getString(resources[weekdayNum.getOffset() - 1]), - weekday); - } - } else { - throw new RuntimeException(); - } - } - - private int weekdayToCalendarDay(Day weekday) { - switch (weekday) { - case SU: - return Calendar.SUNDAY; - case MO: - return Calendar.MONDAY; - case TU: - return Calendar.TUESDAY; - case WE: - return Calendar.WEDNESDAY; - case TH: - return Calendar.THURSDAY; - case FR: - return Calendar.FRIDAY; - case SA: - return Calendar.SATURDAY; - default: - throw new RuntimeException("Invalid weekday: " + weekday); - } - } - - private int getSingleFrequencyResource(Frequency frequency) { - switch (frequency) { - case MINUTELY: - return R.string.repeats_minutely; - case HOURLY: - return R.string.repeats_hourly; - case DAILY: - return R.string.repeats_daily; - case WEEKLY: - return R.string.repeats_weekly; - case MONTHLY: - return R.string.repeats_monthly; - case YEARLY: - return R.string.repeats_yearly; - default: - throw new RuntimeException("Invalid frequency: " + frequency); - } - } - - private int getFrequencyPlural(Frequency frequency) { - switch (frequency) { - case MINUTELY: - return R.plurals.repeat_n_minutes; - case HOURLY: - return R.plurals.repeat_n_hours; - case DAILY: - return R.plurals.repeat_n_days; - case WEEKLY: - return R.plurals.repeat_n_weeks; - case MONTHLY: - return R.plurals.repeat_n_months; - case YEARLY: - return R.plurals.repeat_n_years; - default: - throw new RuntimeException("Invalid frequency: " + frequency); - } - } -} diff --git a/app/src/main/java/org/tasks/repeats/RepeatRuleToString.kt b/app/src/main/java/org/tasks/repeats/RepeatRuleToString.kt new file mode 100644 index 000000000..4df265120 --- /dev/null +++ b/app/src/main/java/org/tasks/repeats/RepeatRuleToString.kt @@ -0,0 +1,189 @@ +package org.tasks.repeats + +import android.content.Context +import com.todoroo.andlib.utility.DateUtilities +import com.todoroo.astrid.data.Task.Companion.withoutRRULE +import dagger.hilt.android.qualifiers.ApplicationContext +import net.fortuna.ical4j.model.Recur +import net.fortuna.ical4j.model.Recur.Frequency +import net.fortuna.ical4j.model.Recur.Frequency.* +import net.fortuna.ical4j.model.WeekDay.Day +import net.fortuna.ical4j.model.WeekDay.Day.* +import net.fortuna.ical4j.model.property.RRule +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.locale.Locale +import org.tasks.time.DateTime +import java.text.DateFormatSymbols +import java.text.ParseException +import java.util.* +import javax.inject.Inject + +class RepeatRuleToString @Inject constructor( + @param:ApplicationContext private val context: Context, + private val locale: Locale, + private val firebase: Firebase +) { + private val weekdays = listOf(*Day.values()) + + fun toString(rrule: String?): String? = try { + toString(RRule(rrule.withoutRRULE())) + } catch (e: ParseException) { + firebase.reportException(e) + null + } + + fun toString(r: RRule): String { + val rrule = r.recur + val interval = rrule.interval + val frequency = rrule.frequency + val repeatUntil = if (rrule.until == null) null else DateTime.from(rrule.until) + val count = rrule.count + val countString = if (count > 0) context.resources.getQuantityString(R.plurals.repeat_times, count) else "" + return if (interval <= 1) { + val frequencyString = context.getString(getSingleFrequencyResource(frequency)) + if ((frequency == WEEKLY || frequency == MONTHLY) && !rrule.dayList.isEmpty()) { + val dayString = getDayString(rrule) + when { + count > 0 -> context.getString( + R.string.repeats_single_on_number_of_times, + frequencyString, + dayString, + count, + countString + ) + repeatUntil == null -> + context.getString(R.string.repeats_single_on, frequencyString, dayString) + else -> context.getString( + R.string.repeats_single_on_until, + frequencyString, + dayString, + DateUtilities.getLongDateString(repeatUntil, locale.locale) + ) + } + } else if (count > 0) { + context.getString( + R.string.repeats_single_number_of_times, frequencyString, count, countString) + } else if (repeatUntil == null) { + context.getString(R.string.repeats_single, frequencyString) + } else { + context.getString( + R.string.repeats_single_until, + frequencyString, + DateUtilities.getLongDateString(repeatUntil, locale.locale)) + } + } else { + val plural = getFrequencyPlural(frequency) + val frequencyPlural = context.resources.getQuantityString(plural, interval, interval) + if ((frequency == WEEKLY || frequency == MONTHLY) && !rrule.dayList.isEmpty()) { + val dayString = getDayString(rrule) + when { + count > 0 -> context.getString( + R.string.repeats_plural_on_number_of_times, + frequencyPlural, + dayString, + count, + countString + ) + repeatUntil == null -> + context.getString(R.string.repeats_plural_on, frequencyPlural, dayString) + else -> context.getString( + R.string.repeats_plural_on_until, + frequencyPlural, + dayString, + DateUtilities.getLongDateString(repeatUntil, locale.locale) + ) + } + } else if (count > 0) { + context.getString( + R.string.repeats_plural_number_of_times, frequencyPlural, count, countString) + } else if (repeatUntil == null) { + context.getString(R.string.repeats_plural, frequencyPlural) + } else { + context.getString( + R.string.repeats_plural_until, + frequencyPlural, + DateUtilities.getLongDateString(repeatUntil, locale.locale)) + } + } + } + + private fun getDayString(rrule: Recur): String { + val dfs = DateFormatSymbols(locale.locale) + return if (rrule.frequency == WEEKLY) { + val shortWeekdays = dfs.shortWeekdays + val days: MutableList = ArrayList() + for (weekday in rrule.dayList) { + days.add(shortWeekdays[weekdays.indexOf(weekday.day) + 1]) + } + days.joinToString(context.getString(R.string.list_separator_with_space)) + } else if (rrule.frequency == MONTHLY) { + val longWeekdays = dfs.weekdays + val weekdayNum = rrule.dayList[0] + val weekday: String + val dayOfWeekCalendar = Calendar.getInstance(locale.locale) + dayOfWeekCalendar[Calendar.DAY_OF_WEEK] = weekdayToCalendarDay(weekdayNum.day) + weekday = longWeekdays[dayOfWeekCalendar[Calendar.DAY_OF_WEEK]] + if (weekdayNum.offset == -1) { + context.getString( + R.string.repeat_monthly_every_day_of_nth_week, + context.getString(R.string.repeat_monthly_last_week), + weekday) + } else { + context.getString( + R.string.repeat_monthly_every_day_of_nth_week, + context.getString(NTH_WEEK[weekdayNum.offset - 1]), + weekday) + } + } else { + throw RuntimeException() + } + } + + private fun weekdayToCalendarDay(weekday: Day): Int { + return when (weekday) { + SU -> Calendar.SUNDAY + MO -> Calendar.MONDAY + TU -> Calendar.TUESDAY + WE -> Calendar.WEDNESDAY + TH -> Calendar.THURSDAY + FR -> Calendar.FRIDAY + SA -> Calendar.SATURDAY + else -> throw RuntimeException("Invalid weekday: $weekday") + } + } + + private fun getSingleFrequencyResource(frequency: Frequency): Int { + return when (frequency) { + MINUTELY -> R.string.repeats_minutely + HOURLY -> R.string.repeats_hourly + DAILY -> R.string.repeats_daily + WEEKLY -> R.string.repeats_weekly + MONTHLY -> R.string.repeats_monthly + YEARLY -> R.string.repeats_yearly + else -> throw RuntimeException("Invalid frequency: $frequency") + } + } + + private fun getFrequencyPlural(frequency: Frequency): Int { + return when (frequency) { + MINUTELY -> R.plurals.repeat_n_minutes + HOURLY -> R.plurals.repeat_n_hours + DAILY -> R.plurals.repeat_n_days + WEEKLY -> R.plurals.repeat_n_weeks + MONTHLY -> R.plurals.repeat_n_months + YEARLY -> R.plurals.repeat_n_years + else -> throw RuntimeException("Invalid frequency: $frequency") + } + } + + companion object { + private val NTH_WEEK = intArrayOf( + R.string.repeat_monthly_first_week, + R.string.repeat_monthly_second_week, + R.string.repeat_monthly_third_week, + R.string.repeat_monthly_fourth_week, + R.string.repeat_monthly_fifth_week + ) + } +} \ No newline at end of file