Skip to content

Commit 5911aa6

Browse files
committed
List scheduled actions with the correct days of week.
We were showing the day of the week from the date the scheduled action was created instead. Fixes #617
1 parent d95b5ae commit 5911aa6

3 files changed

Lines changed: 158 additions & 101 deletions

File tree

app/src/main/java/org/gnucash/android/db/adapter/RecurrenceDbAdapter.java

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@
2020
import android.database.sqlite.SQLiteDatabase;
2121
import android.database.sqlite.SQLiteStatement;
2222
import android.support.annotation.NonNull;
23+
import android.support.annotation.Nullable;
2324

2425
import org.gnucash.android.app.GnuCashApplication;
2526
import org.gnucash.android.model.PeriodType;
2627
import org.gnucash.android.model.Recurrence;
2728

2829
import java.sql.Timestamp;
30+
import java.util.ArrayList;
31+
import java.util.Calendar;
32+
import java.util.Collections;
33+
import java.util.List;
2934

3035
import static org.gnucash.android.db.DatabaseSchema.RecurrenceEntry;
3136

@@ -58,7 +63,7 @@ public Recurrence buildModelInstance(@NonNull Cursor cursor) {
5863
long multiplier = cursor.getLong(cursor.getColumnIndexOrThrow(RecurrenceEntry.COLUMN_MULTIPLIER));
5964
String periodStart = cursor.getString(cursor.getColumnIndexOrThrow(RecurrenceEntry.COLUMN_PERIOD_START));
6065
String periodEnd = cursor.getString(cursor.getColumnIndexOrThrow(RecurrenceEntry.COLUMN_PERIOD_END));
61-
String byDay = cursor.getString(cursor.getColumnIndexOrThrow(RecurrenceEntry.COLUMN_BYDAY));
66+
String byDays = cursor.getString(cursor.getColumnIndexOrThrow(RecurrenceEntry.COLUMN_BYDAY));
6267

6368
PeriodType periodType = PeriodType.valueOf(type);
6469
periodType.setMultiplier((int) multiplier);
@@ -67,7 +72,7 @@ public Recurrence buildModelInstance(@NonNull Cursor cursor) {
6772
recurrence.setPeriodStart(Timestamp.valueOf(periodStart));
6873
if (periodEnd != null)
6974
recurrence.setPeriodEnd(Timestamp.valueOf(periodEnd));
70-
recurrence.setByDay(byDay);
75+
recurrence.setByDays(stringToByDays(byDays));
7176

7277
populateBaseModelAttributes(cursor, recurrence);
7378

@@ -79,8 +84,8 @@ public Recurrence buildModelInstance(@NonNull Cursor cursor) {
7984
stmt.clearBindings();
8085
stmt.bindLong(1, recurrence.getPeriodType().getMultiplier());
8186
stmt.bindString(2, recurrence.getPeriodType().name());
82-
if (recurrence.getByDay() != null)
83-
stmt.bindString(3, recurrence.getByDay());
87+
if (!recurrence.getByDays().isEmpty())
88+
stmt.bindString(3, byDaysToString(recurrence.getByDays()));
8489
//recurrence should always have a start date
8590
stmt.bindString(4, recurrence.getPeriodStart().toString());
8691

@@ -90,4 +95,87 @@ public Recurrence buildModelInstance(@NonNull Cursor cursor) {
9095

9196
return stmt;
9297
}
98+
99+
/**
100+
* Converts a list of days of week as Calendar constants to an String for
101+
* storing in the database.
102+
*
103+
* @param byDays list of days of week constants from Calendar
104+
* @return String of days of the week or null if {@code byDays} was empty
105+
*/
106+
private static @NonNull String byDaysToString(@NonNull List<Integer> byDays) {
107+
StringBuilder builder = new StringBuilder();
108+
for (int day : byDays) {
109+
switch (day) {
110+
case Calendar.MONDAY:
111+
builder.append("MO");
112+
break;
113+
case Calendar.TUESDAY:
114+
builder.append("TU");
115+
break;
116+
case Calendar.WEDNESDAY:
117+
builder.append("WE");
118+
break;
119+
case Calendar.THURSDAY:
120+
builder.append("TH");
121+
break;
122+
case Calendar.FRIDAY:
123+
builder.append("FR");
124+
break;
125+
case Calendar.SATURDAY:
126+
builder.append("SA");
127+
break;
128+
case Calendar.SUNDAY:
129+
builder.append("SU");
130+
break;
131+
default:
132+
throw new RuntimeException("bad day of week: " + day);
133+
}
134+
builder.append(",");
135+
}
136+
builder.deleteCharAt(builder.length()-1);
137+
return builder.toString();
138+
}
139+
140+
/**
141+
* Converts a String with the comma-separated days of the week into a
142+
* list of Calendar constants.
143+
*
144+
* @param byDaysString String with comma-separated days fo the week
145+
* @return list of days of the week as Calendar constants.
146+
*/
147+
private static @NonNull List<Integer> stringToByDays(@Nullable String byDaysString) {
148+
if (byDaysString == null)
149+
return Collections.emptyList();
150+
151+
List<Integer> byDaysList = new ArrayList<>();
152+
for (String day : byDaysString.split(",")) {
153+
switch (day) {
154+
case "MO":
155+
byDaysList.add(Calendar.MONDAY);
156+
break;
157+
case "TU":
158+
byDaysList.add(Calendar.TUESDAY);
159+
break;
160+
case "WE":
161+
byDaysList.add(Calendar.WEDNESDAY);
162+
break;
163+
case "TH":
164+
byDaysList.add(Calendar.THURSDAY);
165+
break;
166+
case "FR":
167+
byDaysList.add(Calendar.FRIDAY);
168+
break;
169+
case "SA":
170+
byDaysList.add(Calendar.SATURDAY);
171+
break;
172+
case "SU":
173+
byDaysList.add(Calendar.SUNDAY);
174+
break;
175+
default:
176+
throw new RuntimeException("bad day of week: " + day);
177+
}
178+
}
179+
return byDaysList;
180+
}
93181
}

app/src/main/java/org/gnucash/android/model/Recurrence.java

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.gnucash.android.R;
2323
import org.gnucash.android.app.GnuCashApplication;
2424
import org.gnucash.android.ui.util.RecurrenceParser;
25-
import org.joda.time.DateTime;
2625
import org.joda.time.Days;
2726
import org.joda.time.LocalDate;
2827
import org.joda.time.LocalDateTime;
@@ -32,8 +31,13 @@
3231
import org.joda.time.Years;
3332

3433
import java.sql.Timestamp;
34+
import java.text.DateFormat;
3535
import java.text.SimpleDateFormat;
36+
import java.util.ArrayList;
37+
import java.util.Calendar;
38+
import java.util.Collections;
3639
import java.util.Date;
40+
import java.util.List;
3741

3842
/**
3943
* Model for recurrences in the database
@@ -55,9 +59,9 @@ public class Recurrence extends BaseModel {
5559
private Timestamp mPeriodEnd;
5660

5761
/**
58-
* Describes which day on which to run the recurrence
62+
* Days of week on which to run the recurrence
5963
*/
60-
private String mByDay;
64+
private List<Integer> mByDays = Collections.emptyList();
6165

6266
public Recurrence(@NonNull PeriodType periodType){
6367
setPeriodType(periodType);
@@ -131,10 +135,9 @@ public String getRepeatString(){
131135
StringBuilder repeatBuilder = new StringBuilder(mPeriodType.getFrequencyRepeatString());
132136
Context context = GnuCashApplication.getAppContext();
133137

134-
String dayOfWeek = new SimpleDateFormat("EEEE", GnuCashApplication.getDefaultLocale())
135-
.format(new Date(mPeriodStart.getTime()));
136138
if (mPeriodType == PeriodType.WEEK) {
137-
repeatBuilder.append(" ").append(context.getString(R.string.repeat_on_weekday, dayOfWeek));
139+
repeatBuilder.append(" ").
140+
append(context.getString(R.string.repeat_on_weekday, getDaysOfWeekString()));
138141
}
139142

140143
if (mPeriodEnd != null){
@@ -144,7 +147,26 @@ public String getRepeatString(){
144147
return repeatBuilder.toString();
145148
}
146149

147-
/**
150+
/**
151+
* Returns a string with the days of the week set in the recurrence separated by commas.
152+
* @return string with the days of the week set in the recurrence separated by commas.
153+
*/
154+
private @NonNull String getDaysOfWeekString() {
155+
// XXX: mByDays should never be empty with PeriodType.WEEK, but we don't enforce it yet
156+
if (mByDays.isEmpty())
157+
return "";
158+
StringBuilder daysOfWeekString = new StringBuilder();
159+
Calendar calendar = Calendar.getInstance();
160+
DateFormat dayOfWeekFormatter =
161+
new SimpleDateFormat("EEEE", GnuCashApplication.getDefaultLocale());
162+
for (int day : mByDays) {
163+
calendar.set(Calendar.DAY_OF_WEEK, day);
164+
daysOfWeekString.append(dayOfWeekFormatter.format(calendar.getTime())).append(", ");
165+
}
166+
return daysOfWeekString.substring(0, daysOfWeekString.length()-2);
167+
}
168+
169+
/**
148170
* Creates an RFC 2445 string which describes this recurring event.
149171
* <p>See http://recurrance.sourceforge.net/</p>
150172
* <p>The output of this method is not meant for human consumption</p>
@@ -251,19 +273,27 @@ public String getTextOfCurrentPeriod(int periodNum){
251273
}
252274

253275
/**
254-
* Sets the string which determines on which day the recurrence will be run
255-
* @param byDay Byday string of recurrence rule (RFC 2445)
276+
* Return the days of week on which to run the recurrence.
277+
*
278+
* <p>Days are expressed as defined in {@link java.util.Calendar}.
279+
* For example, Calendar.MONDAY</p>
280+
*
281+
* @return list of days of week on which to run the recurrence.
256282
*/
257-
public void setByDay(String byDay){
258-
this.mByDay = byDay;
283+
public @NonNull List<Integer> getByDays(){
284+
return Collections.unmodifiableList(mByDays);
259285
}
260286

261287
/**
262-
* Return the byDay string of recurrence rule (RFC 2445)
263-
* @return String with by day specification
288+
* Sets the days on which to run the recurrence.
289+
*
290+
* <p>Days must be expressed as defined in {@link java.util.Calendar}.
291+
* For example, Calendar.MONDAY</p>
292+
*
293+
* @param byDays list of days of week on which to run the recurrence.
264294
*/
265-
public String getByDay(){
266-
return mByDay;
295+
public void setByDays(@NonNull List<Integer> byDays){
296+
mByDays = new ArrayList<>(byDays);
267297
}
268298

269299
/**

app/src/main/java/org/gnucash/android/ui/util/RecurrenceParser.java

Lines changed: 21 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.gnucash.android.ui.util;
1818

19+
import android.support.annotation.NonNull;
20+
import android.support.annotation.Nullable;
1921
import android.text.format.Time;
2022

2123
import com.codetroopers.betterpickers.recurrencepicker.EventRecurrence;
@@ -24,7 +26,10 @@
2426
import org.gnucash.android.model.Recurrence;
2527

2628
import java.sql.Timestamp;
29+
import java.util.ArrayList;
2730
import java.util.Calendar;
31+
import java.util.Collections;
32+
import java.util.List;
2833

2934
/**
3035
* Parses {@link EventRecurrence}s to generate
@@ -76,7 +81,7 @@ public static Recurrence parse(EventRecurrence eventRecurrence){
7681
periodType.setMultiplier(interval);
7782
Recurrence recurrence = new Recurrence(periodType);
7883
parseEndTime(eventRecurrence, recurrence);
79-
recurrence.setByDay(parseByDay(eventRecurrence.byday));
84+
recurrence.setByDays(parseByDay(eventRecurrence.byday));
8085
if (eventRecurrence.startDate != null)
8186
recurrence.setPeriodStart(new Timestamp(eventRecurrence.startDate.toMillis(false)));
8287

@@ -85,7 +90,7 @@ public static Recurrence parse(EventRecurrence eventRecurrence){
8590

8691
/**
8792
* Parses the end time from an EventRecurrence object and sets it to the <code>scheduledEvent</code>.
88-
* The end time is specified in the dialog either by number of occurences or a date.
93+
* The end time is specified in the dialog either by number of occurrences or a date.
8994
* @param eventRecurrence Event recurrence pattern obtained from dialog
9095
* @param recurrence Recurrence event to set the end period to
9196
*/
@@ -100,90 +105,24 @@ private static void parseEndTime(EventRecurrence eventRecurrence, Recurrence rec
100105
}
101106

102107
/**
103-
* Returns the date for the next day of the week
104-
* @param dow Day of the week (Calendar constants)
105-
* @return Calendar instance with the next day of the week
108+
* Parses an array of byDay values to return a list of days of week
109+
* constants from {@link Calendar}.
110+
*
111+
* <p>Currently only supports byDay values for weeks.</p>
112+
*
113+
* @param byDay Array of byDay values
114+
* @return list of days of week constants from Calendar.
106115
*/
107-
private static Calendar nextDayOfWeek(int dow) {
108-
Calendar date = Calendar.getInstance();
109-
int diff = dow - date.get(Calendar.DAY_OF_WEEK);
110-
if (!(diff > 0)) {
111-
diff += 7;
116+
private static @NonNull List<Integer> parseByDay(@Nullable int[] byDay) {
117+
if (byDay == null) {
118+
return Collections.emptyList();
112119
}
113-
date.add(Calendar.DAY_OF_MONTH, diff);
114-
return date;
115-
}
116120

117-
/**
118-
* Parses an array of byday values to return the string concatenation of days of the week.
119-
* <p>Currently only supports byDay values for weeks</p>
120-
* @param byday Array of byday values
121-
* @return String concat of days of the week or null if {@code byday} was empty
122-
*/
123-
private static String parseByDay(int[] byday){
124-
if (byday == null || byday.length == 0){
125-
return null;
126-
}
127-
//todo: parse for month and year as well, when our dialog supports those
128-
StringBuilder builder = new StringBuilder();
129-
for (int day : byday) {
130-
switch (day)
131-
{
132-
case EventRecurrence.SU:
133-
builder.append("SU");
134-
break;
135-
case EventRecurrence.MO:
136-
builder.append("MO");
137-
break;
138-
case EventRecurrence.TU:
139-
builder.append("TU");
140-
break;
141-
case EventRecurrence.WE:
142-
builder.append("WE");
143-
break;
144-
case EventRecurrence.TH:
145-
builder.append("TH");
146-
break;
147-
case EventRecurrence.FR:
148-
builder.append("FR");
149-
break;
150-
case EventRecurrence.SA:
151-
builder.append("SA");
152-
break;
153-
default:
154-
throw new RuntimeException("bad day of week: " + day);
155-
}
156-
builder.append(",");
121+
List<Integer> byDaysList = new ArrayList<>(byDay.length);
122+
for (int day : byDay) {
123+
byDaysList.add(EventRecurrence.day2CalendarDay(day));
157124
}
158-
builder.deleteCharAt(builder.length()-1);
159-
return builder.toString();
160-
}
161125

162-
/**
163-
* Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY
164-
* constants. btw, I think we should switch to those here too, to
165-
* get rid of this function, if possible.
166-
*/
167-
public static int day2CalendarDay(int day)
168-
{
169-
switch (day)
170-
{
171-
case EventRecurrence.SU:
172-
return Calendar.SUNDAY;
173-
case EventRecurrence.MO:
174-
return Calendar.MONDAY;
175-
case EventRecurrence.TU:
176-
return Calendar.TUESDAY;
177-
case EventRecurrence.WE:
178-
return Calendar.WEDNESDAY;
179-
case EventRecurrence.TH:
180-
return Calendar.THURSDAY;
181-
case EventRecurrence.FR:
182-
return Calendar.FRIDAY;
183-
case EventRecurrence.SA:
184-
return Calendar.SATURDAY;
185-
default:
186-
throw new RuntimeException("bad day of week: " + day);
187-
}
126+
return byDaysList;
188127
}
189128
}

0 commit comments

Comments
 (0)