Allow user to change first day of the week

Closes #421
pull/538/head
Alinson S. Xavier 6 years ago
parent 5cdb9eb9d5
commit 7801c933f0

@ -6,6 +6,7 @@
* Improved calculation of streaks for non-daily habits: performing habits on irregular weekdays will no longer break your streak. * Improved calculation of streaks for non-daily habits: performing habits on irregular weekdays will no longer break your streak.
* Many more colors to choose from (now 20 in total). * Many more colors to choose from (now 20 in total).
* Ability to customize how transparent the widgets are on your home screen. * Ability to customize how transparent the widgets are on your home screen.
* Ability to customize the first day of the week.
* Yes/No buttons on notifications, instead of just "Check". * Yes/No buttons on notifications, instead of just "Check".
* Automatic dark theme according to phone settings (Android 10). * Automatic dark theme according to phone settings (Android 10).
* 25% smaller APK size and much smaller backup files. * 25% smaller APK size and much smaller backup files.

@ -29,6 +29,8 @@ import org.isoron.uhabits.utils.*;
import org.junit.*; import org.junit.*;
import org.junit.runner.*; import org.junit.runner.*;
import java.util.*;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@MediumTest @MediumTest
public class ScoreChartTest extends BaseViewTest public class ScoreChartTest extends BaseViewTest
@ -80,7 +82,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withMonthlyBucket() throws Throwable public void testRender_withMonthlyBucket() throws Throwable
{ {
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.MONTH)); view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.MONTH, Calendar.SUNDAY));
view.setBucketSize(30); view.setBucketSize(30);
view.invalidate(); view.invalidate();
@ -97,7 +99,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withYearlyBucket() throws Throwable public void testRender_withYearlyBucket() throws Throwable
{ {
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.YEAR)); view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.YEAR, Calendar.SUNDAY));
view.setBucketSize(365); view.setBucketSize(365);
view.invalidate(); view.invalidate();

@ -28,6 +28,8 @@ import org.isoron.uhabits.core.models.*;
import org.junit.*; import org.junit.*;
import org.junit.runner.*; import org.junit.runner.*;
import java.util.*;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@MediumTest @MediumTest
public class FrequencyWidgetTest extends BaseViewTest public class FrequencyWidgetTest extends BaseViewTest
@ -45,7 +47,7 @@ public class FrequencyWidgetTest extends BaseViewTest
setTheme(R.style.WidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit); FrequencyWidget widget = new FrequencyWidget(targetContext, 0, habit, Calendar.SUNDAY);
view = convertToView(widget, 400, 400); view = convertToView(widget, 400, 400);
} }

@ -28,6 +28,8 @@ import org.isoron.uhabits.core.models.*;
import org.junit.*; import org.junit.*;
import org.junit.runner.*; import org.junit.runner.*;
import java.util.*;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@MediumTest @MediumTest
public class HistoryWidgetTest extends BaseViewTest public class HistoryWidgetTest extends BaseViewTest
@ -45,7 +47,7 @@ public class HistoryWidgetTest extends BaseViewTest
setTheme(R.style.WidgetTheme); setTheme(R.style.WidgetTheme);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
HistoryWidget widget = new HistoryWidget(targetContext, 0, habit); HistoryWidget widget = new HistoryWidget(targetContext, 0, habit, Calendar.SUNDAY);
view = convertToView(widget, 400, 400); view = convertToView(widget, 400, 400);
} }

@ -30,6 +30,7 @@ import android.util.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
@ -51,6 +52,8 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
private TaskRunner taskRunner; private TaskRunner taskRunner;
private Preferences prefs;
public HistoryEditorDialog() public HistoryEditorDialog()
{ {
this.controller = new Controller() {}; this.controller = new Controller() {};
@ -72,9 +75,11 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
(HabitsApplication) getActivity().getApplicationContext(); (HabitsApplication) getActivity().getApplicationContext();
habitList = app.getComponent().getHabitList(); habitList = app.getComponent().getHabitList();
taskRunner = app.getComponent().getTaskRunner(); taskRunner = app.getComponent().getTaskRunner();
prefs = app.getComponent().getPreferences();
historyChart = new HistoryChart(context); historyChart = new HistoryChart(context);
historyChart.setController(controller); historyChart.setController(controller);
historyChart.setFirstWeekday(prefs.getFirstWeekday());
if (savedInstanceState != null) if (savedInstanceState != null)
{ {

@ -29,6 +29,8 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.core.utils.*;
import java.util.*;
/** /**
* Dialog that allows the user to pick one or more days of the week. * Dialog that allows the user to pick one or more days of the week.
*/ */
@ -59,7 +61,8 @@ public class WeekdayPickerDialog extends AppCompatDialogFragment implements
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder builder
.setTitle(R.string.select_weekdays) .setTitle(R.string.select_weekdays)
.setMultiChoiceItems(DateUtils.getLongDayNames(), selectedDays, .setMultiChoiceItems(DateUtils.getLongWeekdayNames(Calendar.SATURDAY),
selectedDays,
this) this)
.setPositiveButton(android.R.string.yes, this) .setPositiveButton(android.R.string.yes, this)
.setNegativeButton(android.R.string.cancel, (dialog, which) -> { .setNegativeButton(android.R.string.cancel, (dialog, which) -> {

@ -69,8 +69,11 @@ public class FrequencyChart extends ScrollableChart
@NonNull @NonNull
private HashMap<Timestamp, Integer[]> frequency; private HashMap<Timestamp, Integer[]> frequency;
private int maxFreq; private int maxFreq;
private int firstWeekday = Calendar.SUNDAY;
public FrequencyChart(Context context) public FrequencyChart(Context context)
{ {
super(context); super(context);
@ -98,6 +101,12 @@ public class FrequencyChart extends ScrollableChart
postInvalidate(); postInvalidate();
} }
public void setFirstWeekday(int firstWeekday)
{
this.firstWeekday = firstWeekday;
postInvalidate();
}
private int getMaxFreq(HashMap<Timestamp, Integer[]> frequency) private int getMaxFreq(HashMap<Timestamp, Integer[]> frequency)
{ {
int maxValue = 1; int maxValue = 1;
@ -144,7 +153,6 @@ public class FrequencyChart extends ScrollableChart
prevRect.setEmpty(); prevRect.setEmpty();
GregorianCalendar currentDate = DateUtils.getStartOfTodayCalendar(); GregorianCalendar currentDate = DateUtils.getStartOfTodayCalendar();
currentDate.set(Calendar.DAY_OF_MONTH, 1); currentDate.set(Calendar.DAY_OF_MONTH, 1);
currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset()); currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset());
@ -193,11 +201,11 @@ public class FrequencyChart extends ScrollableChart
private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date) private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date)
{ {
Integer values[] = frequency.get(new Timestamp(date)); Integer[] values = frequency.get(new Timestamp(date));
float rowHeight = rect.height() / 8.0f; float rowHeight = rect.height() / 8.0f;
prevRect.set(rect); prevRect.set(rect);
Integer[] localeWeekdayList = DateUtils.getLocaleWeekdayList(); int[] localeWeekdayList = DateUtils.getWeekdaySequence(firstWeekday);
for (int j = 0; j < localeWeekdayList.length; j++) for (int j = 0; j < localeWeekdayList.length; j++)
{ {
rect.set(0, 0, baseSize, baseSize); rect.set(0, 0, baseSize, baseSize);
@ -233,7 +241,7 @@ public class FrequencyChart extends ScrollableChart
pText.setColor(textColor); pText.setColor(textColor);
pGrid.setColor(gridColor); pGrid.setColor(gridColor);
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT)) for (String day : DateUtils.getShortWeekdayNames(firstWeekday))
{ {
canvas.drawText(day, rGrid.right - columnWidth, canvas.drawText(day, rGrid.right - columnWidth,
rGrid.top + rowHeight / 2 + 0.25f * em, pText); rGrid.top + rowHeight / 2 + 0.25f * em, pText);

@ -93,6 +93,8 @@ public class HistoryChart extends ScrollableChart
private boolean isNumerical = false; private boolean isNumerical = false;
private int firstWeekday = Calendar.SUNDAY;
@NonNull @NonNull
private Controller controller; private Controller controller;
@ -210,6 +212,12 @@ public class HistoryChart extends ScrollableChart
postInvalidate(); postInvalidate();
} }
public void setFirstWeekday(int firstWeekday)
{
this.firstWeekday = firstWeekday;
postInvalidate();
}
protected void initPaints() protected void initPaints()
{ {
pTextHeader = new Paint(); pTextHeader = new Paint();
@ -293,7 +301,7 @@ public class HistoryChart extends ScrollableChart
{ {
float verticalOffset = pTextHeader.getFontSpacing() * 0.4f; float verticalOffset = pTextHeader.getFontSpacing() * 0.4f;
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT)) for (String day : DateUtils.getShortWeekdayNames(firstWeekday))
{ {
location.offset(0, columnWidth); location.offset(0, columnWidth);
canvas.drawText(day, location.left + headerTextOffset, canvas.drawText(day, location.left + headerTextOffset,
@ -375,7 +383,7 @@ public class HistoryChart extends ScrollableChart
{ {
float width = 0; float width = 0;
for (String w : DateUtils.getLocaleDayNames(Calendar.SHORT)) for (String w : DateUtils.getShortWeekdayNames(firstWeekday))
width = Math.max(width, pSquareFg.measureText(w)); width = Math.max(width, pSquareFg.measureText(w));
return width; return width;
@ -473,7 +481,7 @@ public class HistoryChart extends ScrollableChart
int realWeekday = int realWeekday =
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK); DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
todayPositionInColumn = todayPositionInColumn =
(7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7; (7 + realWeekday - firstWeekday) % 7;
baseDate.add(Calendar.DAY_OF_YEAR, -nDays); baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn); baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);

@ -28,6 +28,7 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
@ -56,6 +57,9 @@ public class BarCard extends HabitCard
private int bucketSize; private int bucketSize;
@Nullable
private Preferences prefs;
public BarCard(Context context) public BarCard(Context context)
{ {
super(context); super(context);
@ -84,6 +88,12 @@ public class BarCard extends HabitCard
private void init() private void init()
{ {
Context appContext = getContext().getApplicationContext();
if (appContext instanceof HabitsApplication)
{
HabitsApplication app = (HabitsApplication) appContext;
prefs = app.getComponent().getPreferences();
}
inflate(getContext(), R.layout.show_habit_bar, this); inflate(getContext(), R.layout.show_habit_bar, this);
ButterKnife.bind(this); ButterKnife.bind(this);
boolSpinner.setSelection(1); boolSpinner.setSelection(1);
@ -120,8 +130,11 @@ public class BarCard extends HabitCard
{ {
if (isCanceled()) return; if (isCanceled()) return;
List<Checkmark> checkmarks; List<Checkmark> checkmarks;
int firstWeekday = Calendar.SATURDAY;
if (prefs != null) firstWeekday = prefs.getFirstWeekday();
if (bucketSize == 1) checkmarks = habit.getCheckmarks().getAll(); if (bucketSize == 1) checkmarks = habit.getCheckmarks().getAll();
else checkmarks = habit.getCheckmarks().groupBy(getTruncateField(bucketSize)); else checkmarks = habit.getCheckmarks().groupBy(getTruncateField(bucketSize),
firstWeekday);
chart.setCheckmarks(checkmarks); chart.setCheckmarks(checkmarks);
chart.setBucketSize(bucketSize); chart.setBucketSize(bucketSize);
} }

@ -28,6 +28,7 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
@ -43,6 +44,9 @@ public class FrequencyCard extends HabitCard
@BindView(R.id.frequencyChart) @BindView(R.id.frequencyChart)
FrequencyChart chart; FrequencyChart chart;
@Nullable
private Preferences prefs;
public FrequencyCard(Context context) public FrequencyCard(Context context)
{ {
super(context); super(context);
@ -63,6 +67,12 @@ public class FrequencyCard extends HabitCard
private void init() private void init()
{ {
Context appContext = getContext().getApplicationContext();
if (appContext instanceof HabitsApplication)
{
HabitsApplication app = (HabitsApplication) appContext;
prefs = app.getComponent().getPreferences();
}
inflate(getContext(), R.layout.show_habit_frequency, this); inflate(getContext(), R.layout.show_habit_frequency, this);
ButterKnife.bind(this); ButterKnife.bind(this);
if (isInEditMode()) initEditMode(); if (isInEditMode()) initEditMode();
@ -84,6 +94,7 @@ public class FrequencyCard extends HabitCard
if (isCanceled()) return; if (isCanceled()) return;
RepetitionList reps = getHabit().getRepetitions(); RepetitionList reps = getHabit().getRepetitions();
HashMap<Timestamp, Integer[]> frequency = reps.getWeekdayFrequency(); HashMap<Timestamp, Integer[]> frequency = reps.getWeekdayFrequency();
if(prefs != null) chart.setFirstWeekday(prefs.getFirstWeekday());
chart.setFrequency(frequency); chart.setFrequency(frequency);
} }

@ -28,6 +28,7 @@ import org.isoron.uhabits.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.tasks.*; import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
@ -41,9 +42,12 @@ public class HistoryCard extends HabitCard
@BindView(R.id.title) @BindView(R.id.title)
TextView title; TextView title;
@NonNull @Nullable
private Controller controller; private Controller controller;
@Nullable
private Preferences prefs;
public HistoryCard(Context context) public HistoryCard(Context context)
{ {
super(context); super(context);
@ -59,16 +63,23 @@ public class HistoryCard extends HabitCard
@OnClick(R.id.edit) @OnClick(R.id.edit)
public void onClickEditButton() public void onClickEditButton()
{ {
controller.onEditHistoryButtonClick(); if(controller != null) controller.onEditHistoryButtonClick();
} }
public void setController(@NonNull Controller controller) public void setController(@Nullable Controller controller)
{ {
this.controller = controller; this.controller = controller;
} }
private void init() private void init()
{ {
Context appContext = getContext().getApplicationContext();
if (appContext instanceof HabitsApplication)
{
HabitsApplication app = (HabitsApplication) appContext;
prefs = app.getComponent().getPreferences();
}
inflate(getContext(), R.layout.show_habit_history, this); inflate(getContext(), R.layout.show_habit_history, this);
ButterKnife.bind(this); ButterKnife.bind(this);
controller = new Controller() {}; controller = new Controller() {};
@ -107,7 +118,8 @@ public class HistoryCard extends HabitCard
public void doInBackground() public void doInBackground()
{ {
if (isCanceled()) return; if (isCanceled()) return;
int checkmarks[] = habit.getCheckmarks().getAllValues(); int[] checkmarks = habit.getCheckmarks().getAllValues();
if(prefs != null) chart.setFirstWeekday(prefs.getFirstWeekday());
chart.setCheckmarks(checkmarks); chart.setCheckmarks(checkmarks);
} }

@ -143,9 +143,12 @@ public class ScoreCard extends HabitCard
if (isCanceled()) return; if (isCanceled()) return;
List<Score> scores; List<Score> scores;
ScoreList scoreList = getHabit().getScores(); ScoreList scoreList = getHabit().getScores();
int firstWeekday = Calendar.SATURDAY;
if (prefs != null) firstWeekday = prefs.getFirstWeekday();
Log.d("ScoreCard", "firstWeekday="+firstWeekday);
if (bucketSize == 1) scores = scoreList.toList(); if (bucketSize == 1) scores = scoreList.toList();
else scores = scoreList.groupBy(getTruncateField(bucketSize)); else scores = scoreList.groupBy(getTruncateField(bucketSize), firstWeekday);
chart.setScores(scores); chart.setScores(scores);
chart.setBucketSize(bucketSize); chart.setBucketSize(bucketSize);

@ -32,9 +32,12 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.*; import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.notifications.*; import org.isoron.uhabits.notifications.*;
import org.isoron.uhabits.widgets.*; import org.isoron.uhabits.widgets.*;
import java.util.*;
import static android.media.RingtoneManager.*; import static android.media.RingtoneManager.*;
import static android.os.Build.VERSION.*; import static android.os.Build.VERSION.*;
import static org.isoron.uhabits.activities.habits.list.ListHabitsScreenKt.*; import static org.isoron.uhabits.activities.habits.list.ListHabitsScreenKt.*;
@ -143,6 +146,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
devCategory.setVisible(false); devCategory.setVisible(false);
} }
updateWeekdayPreference();
if (SDK_INT < Build.VERSION_CODES.O) if (SDK_INT < Build.VERSION_CODES.O)
findPreference("reminderCustomize").setVisible(false); findPreference("reminderCustomize").setVisible(false);
else else
@ -154,6 +159,19 @@ public class SettingsFragment extends PreferenceFragmentCompat
updateSync(); updateSync();
} }
private void updateWeekdayPreference()
{
if (prefs == null) return;
ListPreference weekdayPref = (ListPreference) findPreference("pref_first_weekday");
int currentFirstWeekday = prefs.getFirstWeekday();
String[] dayNames = DateUtils.getLongWeekdayNames(Calendar.SATURDAY);
String[] dayValues = {"7", "1", "2", "3", "4", "5", "6"};
weekdayPref.setEntries(dayNames);
weekdayPref.setEntryValues(dayValues);
weekdayPref.setDefaultValue(Integer.toString(currentFirstWeekday));
weekdayPref.setSummary(dayNames[currentFirstWeekday % 7]);
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) String key)
@ -163,6 +181,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
Log.d("SettingsFragment", "updating widgets"); Log.d("SettingsFragment", "updating widgets");
widgetUpdater.updateWidgets(); widgetUpdater.updateWidgets();
} }
if (key.equals("pref_first_weekday")) updateWeekdayPreference();
BackupManager.dataChanged("org.isoron.uhabits"); BackupManager.dataChanged("org.isoron.uhabits");
updateSync(); updateSync();
} }

@ -41,8 +41,8 @@ public class AndroidDateUtils
public static String formatWeekdayList(Context context, boolean weekday[]) public static String formatWeekdayList(Context context, boolean weekday[])
{ {
String shortDayNames[] = org.isoron.uhabits.core.utils.DateUtils.getShortDayNames(); String shortDayNames[] = org.isoron.uhabits.core.utils.DateUtils.getShortWeekdayNames(Calendar.SATURDAY);
String longDayNames[] = org.isoron.uhabits.core.utils.DateUtils.getLongDayNames(); String longDayNames[] = org.isoron.uhabits.core.utils.DateUtils.getLongWeekdayNames(Calendar.SATURDAY);
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
int count = 0; int count = 0;

@ -40,6 +40,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
private HabitList habits; private HabitList habits;
private Preferences preferences; private Preferences preferences;
private WidgetPreferences widgetPrefs; private WidgetPreferences widgetPrefs;
public static void updateAppWidget(@NonNull AppWidgetManager manager, public static void updateAppWidget(@NonNull AppWidgetManager manager,
@ -195,4 +196,9 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
preferences = app.getComponent().getPreferences(); preferences = app.getComponent().getPreferences();
widgetPrefs = app.getComponent().getWidgetPreferences(); widgetPrefs = app.getComponent().getWidgetPreferences();
} }
public Preferences getPreferences()
{
return preferences;
}
} }

@ -29,7 +29,8 @@ import org.isoron.uhabits.widgets.views.*
class FrequencyWidget( class FrequencyWidget(
context: Context, context: Context,
widgetId: Int, widgetId: Int,
private val habit: Habit private val habit: Habit,
private val firstWeekday: Int
) : BaseWidget(context, widgetId) { ) : BaseWidget(context, widgetId) {
override fun getOnClickPendingIntent(context: Context) = override fun getOnClickPendingIntent(context: Context) =
@ -40,6 +41,7 @@ class FrequencyWidget(
widgetView.setTitle(habit.name) widgetView.setTitle(habit.name)
widgetView.setBackgroundAlpha(preferedBackgroundAlpha) widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as FrequencyChart).apply { (widgetView.dataView as FrequencyChart).apply {
setFirstWeekday(firstWeekday)
setColor(PaletteUtils.getColor(context, habit.color)) setColor(PaletteUtils.getColor(context, habit.color))
setFrequency(habit.repetitions.weekdayFrequency) setFrequency(habit.repetitions.weekdayFrequency)
} }

@ -24,7 +24,10 @@ import android.content.*
class FrequencyWidgetProvider : BaseWidgetProvider() { class FrequencyWidgetProvider : BaseWidgetProvider() {
override fun getWidgetFromId(context: Context, id: Int): BaseWidget { override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
val habits = getHabitsFromWidgetId(id) val habits = getHabitsFromWidgetId(id)
if (habits.size == 1) return FrequencyWidget(context, id, habits[0]) if (habits.size == 1) return FrequencyWidget(context,
id,
habits[0],
preferences.firstWeekday)
else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits) else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits)
} }
} }

@ -30,7 +30,8 @@ import org.isoron.uhabits.widgets.views.*
class HistoryWidget( class HistoryWidget(
context: Context, context: Context,
id: Int, id: Int,
private val habit: Habit private val habit: Habit,
private val firstWeekday: Int
) : BaseWidget(context, id) { ) : BaseWidget(context, id) {
override fun getOnClickPendingIntent(context: Context): PendingIntent { override fun getOnClickPendingIntent(context: Context): PendingIntent {
@ -41,6 +42,7 @@ class HistoryWidget(
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView
widgetView.setBackgroundAlpha(preferedBackgroundAlpha) widgetView.setBackgroundAlpha(preferedBackgroundAlpha)
(widgetView.dataView as HistoryChart).apply { (widgetView.dataView as HistoryChart).apply {
setFirstWeekday(firstWeekday)
setColor(PaletteUtils.getColor(context, habit.color)) setColor(PaletteUtils.getColor(context, habit.color))
setCheckmarks(habit.checkmarks.allValues) setCheckmarks(habit.checkmarks.allValues)
} }

@ -23,7 +23,10 @@ import android.content.*
class HistoryWidgetProvider : BaseWidgetProvider() { class HistoryWidgetProvider : BaseWidgetProvider() {
override fun getWidgetFromId(context: Context, id: Int): BaseWidget { override fun getWidgetFromId(context: Context, id: Int): BaseWidget {
val habits = getHabitsFromWidgetId(id) val habits = getHabitsFromWidgetId(id)
if (habits.size == 1) return HistoryWidget(context, id, habits[0]) if (habits.size == 1) return HistoryWidget(context,
id,
habits[0],
preferences.firstWeekday)
else return StackWidget(context, id, StackWidgetType.HISTORY, habits) else return StackWidget(context, id, StackWidgetType.HISTORY, habits)
} }
} }

@ -40,7 +40,8 @@ class ScoreWidget(
val size = ScoreCard.BUCKET_SIZES[prefs.defaultScoreSpinnerPosition] val size = ScoreCard.BUCKET_SIZES[prefs.defaultScoreSpinnerPosition]
val scores = when(size) { val scores = when(size) {
1 -> habit.scores.toList() 1 -> habit.scores.toList()
else -> habit.scores.groupBy(ScoreCard.getTruncateField(size)) else -> habit.scores.groupBy(ScoreCard.getTruncateField(size),
prefs.firstWeekday)
} }
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView

@ -9,6 +9,7 @@ import android.widget.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.core.utils.*;
import java.util.*; import java.util.*;
@ -87,18 +88,19 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
} }
@NonNull @NonNull
private BaseWidget constructWidget(@NonNull Habit habit) private BaseWidget constructWidget(@NonNull Habit habit,
@NonNull Preferences prefs)
{ {
switch (widgetType) switch (widgetType)
{ {
case CHECKMARK: case CHECKMARK:
return new CheckmarkWidget(context, widgetId, habit); return new CheckmarkWidget(context, widgetId, habit);
case FREQUENCY: case FREQUENCY:
return new FrequencyWidget(context, widgetId, habit); return new FrequencyWidget(context, widgetId, habit, prefs.getFirstWeekday());
case SCORE: case SCORE:
return new ScoreWidget(context, widgetId, habit); return new ScoreWidget(context, widgetId, habit);
case HISTORY: case HISTORY:
return new HistoryWidget(context, widgetId, habit); return new HistoryWidget(context, widgetId, habit, prefs.getFirstWeekday());
case STREAKS: case STREAKS:
return new StreakWidget(context, widgetId, habit); return new StreakWidget(context, widgetId, habit);
} }
@ -136,6 +138,7 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
Log.i("StackRemoteViewsFactory", "onDataSetChanged started"); Log.i("StackRemoteViewsFactory", "onDataSetChanged started");
HabitsApplication app = (HabitsApplication) context.getApplicationContext(); HabitsApplication app = (HabitsApplication) context.getApplicationContext();
Preferences prefs = app.getComponent().getPreferences();
HabitList habitList = app.getComponent().getHabitList(); HabitList habitList = app.getComponent().getHabitList();
Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId); Bundle options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId);
ArrayList<RemoteViews> newRemoteViews = new ArrayList<>(); ArrayList<RemoteViews> newRemoteViews = new ArrayList<>();
@ -147,7 +150,7 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
Habit h = habitList.getById(id); Habit h = habitList.getById(id);
if (h == null) throw new HabitNotFoundException(); if (h == null) throw new HabitNotFoundException();
BaseWidget widget = constructWidget(h); BaseWidget widget = constructWidget(h, prefs);
widget.setDimensions(getDimensionsFromOptions(context, options)); widget.setDimensions(getDimensionsFromOptions(context, options));
RemoteViews landscapeViews = widget.getLandscapeRemoteViews(); RemoteViews landscapeViews = widget.getLandscapeRemoteViews();

@ -242,5 +242,6 @@
<string name="database">Database</string> <string name="database">Database</string>
<string name="widget_opacity_title">Widget opacity</string> <string name="widget_opacity_title">Widget opacity</string>
<string name="widget_opacity_description">Makes widgets more transparent or more opaque in your home screen.</string> <string name="widget_opacity_description">Makes widgets more transparent or more opaque in your home screen.</string>
<string name="first_day_of_the_week">First day of the week</string>
</resources> </resources>

@ -55,6 +55,11 @@
android:title="@string/widget_opacity_title" android:title="@string/widget_opacity_title"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<ListPreference
android:key="pref_first_weekday"
android:title="@string/first_day_of_the_week"
app:iconSpaceReserved="false" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

@ -412,7 +412,7 @@ public abstract class CheckmarkList
} }
@NonNull @NonNull
public List<Checkmark> groupBy(DateUtils.TruncateField field) public List<Checkmark> groupBy(DateUtils.TruncateField field, int firstWeekday)
{ {
List<Checkmark> checks = getAll(); List<Checkmark> checks = getAll();
@ -422,7 +422,7 @@ public abstract class CheckmarkList
for (Checkmark rep : checks) for (Checkmark rep : checks)
{ {
Timestamp tt = rep.getTimestamp().truncate(field); Timestamp tt = rep.getTimestamp().truncate(field, firstWeekday);
if (count == 0 || !truncatedTimestamps[count - 1].equals(tt)) if (count == 0 || !truncatedTimestamps[count - 1].equals(tt))
truncatedTimestamps[count++] = tt; truncatedTimestamps[count++] = tt;

@ -129,10 +129,10 @@ public abstract class ScoreList implements Iterable<Score>
return values; return values;
} }
public List<Score> groupBy(DateUtils.TruncateField field) public List<Score> groupBy(DateUtils.TruncateField field, int firstWeekday)
{ {
computeAll(); computeAll();
HashMap<Timestamp, ArrayList<Double>> groups = getGroupedValues(field); HashMap<Timestamp, ArrayList<Double>> groups = getGroupedValues(field, firstWeekday);
List<Score> scores = groupsToAvgScores(groups); List<Score> scores = groupsToAvgScores(groups);
Collections.sort(scores, (s1, s2) -> s2.compareNewer(s1)); Collections.sort(scores, (s1, s2) -> s2.compareNewer(s1));
return scores; return scores;
@ -293,14 +293,18 @@ public abstract class ScoreList implements Iterable<Score>
} }
@NonNull @NonNull
private HashMap<Timestamp, ArrayList<Double>> getGroupedValues(DateUtils.TruncateField field) private HashMap<Timestamp, ArrayList<Double>> getGroupedValues(DateUtils.TruncateField field,
int firstWeekday)
{ {
HashMap<Timestamp, ArrayList<Double>> groups = new HashMap<>(); HashMap<Timestamp, ArrayList<Double>> groups = new HashMap<>();
for (Score s : this) for (Score s : this)
{ {
Timestamp groupTimestamp = new Timestamp( Timestamp groupTimestamp = new Timestamp(
DateUtils.truncate(field, s.getTimestamp().getUnixTime())); DateUtils.truncate(
field,
s.getTimestamp().getUnixTime(),
firstWeekday));
if (!groups.containsKey(groupTimestamp)) if (!groups.containsKey(groupTimestamp))
groups.put(groupTimestamp, new ArrayList<>()); groups.put(groupTimestamp, new ArrayList<>());

@ -143,13 +143,17 @@ public final class Timestamp
return DateFormats.getCSVDateFormat().format(new Date(unixTime)); return DateFormats.getCSVDateFormat().format(new Date(unixTime));
} }
/**
* Returns an integer corresponding to the day of the week. Saturday maps
* to 0, Sunday maps to 1, and so on.
*/
public int getWeekday() public int getWeekday()
{ {
return toCalendar().get(DAY_OF_WEEK) % 7; return toCalendar().get(DAY_OF_WEEK) % 7;
} }
public Timestamp truncate(DateUtils.TruncateField field) Timestamp truncate(DateUtils.TruncateField field, int firstWeekday)
{ {
return new Timestamp(DateUtils.truncate(field, unixTime)); return new Timestamp(DateUtils.truncate(field, unixTime, firstWeekday));
} }
} }

@ -333,6 +333,19 @@ public class Preferences
return Integer.parseInt(storage.getString("pref_widget_opacity", "102")); return Integer.parseInt(storage.getString("pref_widget_opacity", "102"));
} }
/**
* @return An integer representing the first day of the week. Sunday
* corresponds to 1, Monday to 2, and so on, until Saturday, which is
* represented by 7. By default, this is based on the current system locale,
* unless the user changed this in the settings.
*/
public int getFirstWeekday()
{
String weekday = storage.getString("pref_first_weekday", "");
if (weekday.isEmpty()) return DateUtils.getFirstWeekdayNumberAccordingToLocale();
return Integer.parseInt(weekday);
}
public interface Listener public interface Listener
{ {
default void onCheckmarkSequenceChanged() default void onCheckmarkSequenceChanged()

@ -22,6 +22,7 @@ package org.isoron.uhabits.core.utils;
import android.support.annotation.*; import android.support.annotation.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.jetbrains.annotations.*;
import java.util.*; import java.util.*;
@ -73,23 +74,6 @@ public abstract class DateUtils
return day; return day;
} }
private static String[] getDayNames(int format)
{
String[] wdays = new String[7];
Calendar day = new GregorianCalendar();
day.set(DAY_OF_WEEK, Calendar.SATURDAY);
for (int i = 0; i < wdays.length; i++)
{
wdays[i] =
day.getDisplayName(DAY_OF_WEEK, format, getLocale());
day.add(DAY_OF_MONTH, 1);
}
return wdays;
}
public static long getLocalTime() public static long getLocalTime()
{ {
if (fixedLocalTime != null) return fixedLocalTime; if (fixedLocalTime != null) return fixedLocalTime;
@ -100,17 +84,23 @@ public abstract class DateUtils
} }
/** /**
* @return array with weekday names starting according to locale settings, * Returns an array of strings with the names for each day of the week,
* e.g. [Mo,Di,Mi,Do,Fr,Sa,So] in Germany * in either SHORT or LONG format. The first entry corresponds to the
* first day of the week, according to the provided argument.
*
* @param format Either GregorianCalendar.SHORT or LONG
* @param firstWeekday An integer representing the first day of the week,
* following java.util.Calendar conventions. That is,
* Saturday corresponds to 7, and Sunday corresponds
* to 1.
*/ */
public static String[] getLocaleDayNames(int format) @NotNull
private static String[] getWeekdayNames(int format, int firstWeekday)
{ {
String[] days = new String[7]; String[] days = new String[7];
Calendar calendar = new GregorianCalendar(); Calendar calendar = new GregorianCalendar();
calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek()); calendar.set(DAY_OF_WEEK, firstWeekday);
for (int i = 0; i < days.length; i++) for (int i = 0; i < days.length; i++) {
{
days[i] = calendar.getDisplayName(DAY_OF_WEEK, format, days[i] = calendar.getDisplayName(DAY_OF_WEEK, format,
getLocale()); getLocale());
calendar.add(DAY_OF_MONTH, 1); calendar.add(DAY_OF_MONTH, 1);
@ -120,30 +110,63 @@ public abstract class DateUtils
} }
/** /**
* @return array with week days numbers starting according to locale * Returns a vector of exactly seven integers, where the first integer is
* settings, e.g. [2,3,4,5,6,7,1] in Europe * the provided firstWeekday number, and each subsequent number is the
* previous number plus 1, wrapping back to 1 after 7. For example,
* providing 3 as firstWeekday returns {3,4,5,6,7,1,2}
*
* This function is supposed to be used to construct a sequence of weekday
* number following java.util.Calendar conventions.
*/ */
public static Integer[] getLocaleWeekdayList() public static int[] getWeekdaySequence(int firstWeekday)
{ {
Integer[] dayNumbers = new Integer[7]; return new int[]
Calendar calendar = new GregorianCalendar();
calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek());
for (int i = 0; i < dayNumbers.length; i++)
{ {
dayNumbers[i] = calendar.get(DAY_OF_WEEK); (firstWeekday - 1) % 7 + 1,
calendar.add(DAY_OF_MONTH, 1); (firstWeekday) % 7 + 1,
(firstWeekday + 1) % 7 + 1,
(firstWeekday + 2) % 7 + 1,
(firstWeekday + 3) % 7 + 1,
(firstWeekday + 4) % 7 + 1,
(firstWeekday + 5) % 7 + 1,
};
} }
return dayNumbers;
/**
* @return An integer representing the first day of the week, according to
* the current locale. Sunday corresponds to 1, Monday to 2, and so on,
* until Saturday, which is represented by 7. This is consistent
* with java.util.Calendar constants.
*/
public static int getFirstWeekdayNumberAccordingToLocale()
{
return new GregorianCalendar().getFirstDayOfWeek();
} }
public static String[] getLongDayNames() /**
* @return A vector of strings with the long names for the week days,
* according to the current locale. The first entry corresponds to Saturday,
* the second entry corresponds to Monday, and so on.
*
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
* weekdays defined in this class.
*/
public static String[] getLongWeekdayNames(int firstWeekday)
{ {
return getDayNames(GregorianCalendar.LONG); return getWeekdayNames(GregorianCalendar.LONG, firstWeekday);
} }
public static String[] getShortDayNames() /**
* Returns a vector of strings with the short names for the week days,
* according to the current locale. The first entry corresponds to Saturday,
* the second entry corresponds to Monday, and so on.
*
* @param firstWeekday Either Calendar.SATURDAY, Calendar.MONDAY, or other
* weekdays defined in this class.
*/
public static String[] getShortWeekdayNames(int firstWeekday)
{ {
return getDayNames(SHORT); return getWeekdayNames(GregorianCalendar.SHORT, firstWeekday);
} }
@NonNull @NonNull
@ -206,10 +229,13 @@ public abstract class DateUtils
return Locale.getDefault(); return Locale.getDefault();
} }
public static Long truncate(TruncateField field, long timestamp) public static Long truncate(TruncateField field,
long timestamp,
int firstWeekday)
{ {
GregorianCalendar cal = DateUtils.getCalendar(timestamp); GregorianCalendar cal = DateUtils.getCalendar(timestamp);
switch (field) switch (field)
{ {
case MONTH: case MONTH:
@ -217,7 +243,6 @@ public abstract class DateUtils
return cal.getTimeInMillis(); return cal.getTimeInMillis();
case WEEK_NUMBER: case WEEK_NUMBER:
int firstWeekday = cal.getFirstDayOfWeek();
int weekday = cal.get(DAY_OF_WEEK); int weekday = cal.get(DAY_OF_WEEK);
int delta = weekday - firstWeekday; int delta = weekday - firstWeekday;
if (delta < 0) delta += 7; if (delta < 0) delta += 7;

@ -388,20 +388,20 @@ public class CheckmarkListTest extends BaseUnitTest
Habit habit = fixtures.createLongNumericalHabit(timestamp(2014, JUNE, 1)); Habit habit = fixtures.createLongNumericalHabit(timestamp(2014, JUNE, 1));
CheckmarkList checkmarks = habit.getCheckmarks(); CheckmarkList checkmarks = habit.getCheckmarks();
List<Checkmark> byMonth = checkmarks.groupBy(MONTH); List<Checkmark> byMonth = checkmarks.groupBy(MONTH, Calendar.SATURDAY);
assertThat(byMonth.size(), equalTo(25)); // from 2013-01-01 to 2015-01-01 assertThat(byMonth.size(), equalTo(25)); // from 2013-01-01 to 2015-01-01
assertThat(byMonth.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0))); assertThat(byMonth.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0)));
assertThat(byMonth.get(6), equalTo(new Checkmark(timestamp(2014, JULY, 1), 0))); assertThat(byMonth.get(6), equalTo(new Checkmark(timestamp(2014, JULY, 1), 0)));
assertThat(byMonth.get(12), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 1706))); assertThat(byMonth.get(12), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 1706)));
assertThat(byMonth.get(18), equalTo(new Checkmark(timestamp(2013, JULY, 1), 1379))); assertThat(byMonth.get(18), equalTo(new Checkmark(timestamp(2013, JULY, 1), 1379)));
List<Checkmark> byQuarter = checkmarks.groupBy(QUARTER); List<Checkmark> byQuarter = checkmarks.groupBy(QUARTER, Calendar.SATURDAY);
assertThat(byQuarter.size(), equalTo(9)); // from 2013-Q1 to 2015-Q1 assertThat(byQuarter.size(), equalTo(9)); // from 2013-Q1 to 2015-Q1
assertThat(byQuarter.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0))); assertThat(byQuarter.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0)));
assertThat(byQuarter.get(4), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 4964))); assertThat(byQuarter.get(4), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 4964)));
assertThat(byQuarter.get(8), equalTo(new Checkmark(timestamp(2013, JANUARY, 1), 4975))); assertThat(byQuarter.get(8), equalTo(new Checkmark(timestamp(2013, JANUARY, 1), 4975)));
List<Checkmark> byYear = checkmarks.groupBy(YEAR); List<Checkmark> byYear = checkmarks.groupBy(YEAR, Calendar.SATURDAY);
assertThat(byYear.size(), equalTo(3)); // from 2013 to 2015 assertThat(byYear.size(), equalTo(3)); // from 2013 to 2015
assertThat(byYear.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0))); assertThat(byYear.get(0), equalTo(new Checkmark(timestamp(2015, JANUARY, 1), 0)));
assertThat(byYear.get(1), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 8227))); assertThat(byYear.get(1), equalTo(new Checkmark(timestamp(2014, JANUARY, 1), 8227)));

@ -150,7 +150,7 @@ public class ScoreListTest extends BaseUnitTest
{ {
Habit habit = fixtures.createLongHabit(); Habit habit = fixtures.createLongHabit();
List<Score> list = List<Score> list =
habit.getScores().groupBy(DateUtils.TruncateField.MONTH); habit.getScores().groupBy(DateUtils.TruncateField.MONTH, Calendar.SATURDAY);
assertThat(list.size(), equalTo(5)); assertThat(list.size(), equalTo(5));
assertThat(list.get(0).getValue(), closeTo(0.653659, E)); assertThat(list.get(0).getValue(), closeTo(0.653659, E));

@ -34,6 +34,9 @@ import static org.isoron.uhabits.core.utils.DateUtils.removeTimezone;
public class DateUtilsTest extends BaseUnitTest public class DateUtilsTest extends BaseUnitTest
{ {
int firstWeekday = SUNDAY;
@Before @Before
@Override @Override
public void setUp() throws Exception public void setUp() throws Exception
@ -61,18 +64,29 @@ public class DateUtilsTest extends BaseUnitTest
long t1 = unixTime(2015, Calendar.JANUARY, 16); long t1 = unixTime(2015, Calendar.JANUARY, 16);
long t2 = unixTime(2015, Calendar.JANUARY, 17); long t2 = unixTime(2015, Calendar.JANUARY, 17);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2015, Calendar.JANUARY, 18); expected = unixTime(2015, Calendar.JANUARY, 18);
t0 = unixTime(2015, Calendar.JANUARY, 18); t0 = unixTime(2015, Calendar.JANUARY, 18);
t1 = unixTime(2015, Calendar.JANUARY, 19); t1 = unixTime(2015, Calendar.JANUARY, 19);
t2 = unixTime(2015, Calendar.JANUARY, 24); t2 = unixTime(2015, Calendar.JANUARY, 24);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
firstWeekday = WEDNESDAY;
expected = unixTime(2015, Calendar.JANUARY, 7);
t0 = unixTime(2015, Calendar.JANUARY, 7);
t1 = unixTime(2015, Calendar.JANUARY, 9);
t2 = unixTime(2015, Calendar.JANUARY, 13);
assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
} }
@Test @Test
@ -85,18 +99,18 @@ public class DateUtilsTest extends BaseUnitTest
DateUtils.TruncateField field = DateUtils.TruncateField.MONTH; DateUtils.TruncateField field = DateUtils.TruncateField.MONTH;
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2016, DECEMBER, 1); expected = unixTime(2016, DECEMBER, 1);
t0 = unixTime(2016, DECEMBER, 1); t0 = unixTime(2016, DECEMBER, 1);
t1 = unixTime(2016, DECEMBER, 15); t1 = unixTime(2016, DECEMBER, 15);
t2 = unixTime(2016, DECEMBER, 31); t2 = unixTime(2016, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
} }
@Test @Test
@ -109,18 +123,18 @@ public class DateUtilsTest extends BaseUnitTest
long t1 = unixTime(2016, FEBRUARY, 15); long t1 = unixTime(2016, FEBRUARY, 15);
long t2 = unixTime(2016, MARCH, 30); long t2 = unixTime(2016, MARCH, 30);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2016, APRIL, 1); expected = unixTime(2016, APRIL, 1);
t0 = unixTime(2016, APRIL, 1); t0 = unixTime(2016, APRIL, 1);
t1 = unixTime(2016, MAY, 30); t1 = unixTime(2016, MAY, 30);
t2 = unixTime(2016, JUNE, 20); t2 = unixTime(2016, JUNE, 20);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
} }
@Test @Test
@ -133,18 +147,18 @@ public class DateUtilsTest extends BaseUnitTest
long t1 = unixTime(2016, FEBRUARY, 25); long t1 = unixTime(2016, FEBRUARY, 25);
long t2 = unixTime(2016, DECEMBER, 31); long t2 = unixTime(2016, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
expected = unixTime(2017, JANUARY, 1); expected = unixTime(2017, JANUARY, 1);
t0 = unixTime(2017, JANUARY, 1); t0 = unixTime(2017, JANUARY, 1);
t1 = unixTime(2017, MAY, 30); t1 = unixTime(2017, MAY, 30);
t2 = unixTime(2017, DECEMBER, 31); t2 = unixTime(2017, DECEMBER, 31);
assertThat(DateUtils.truncate(field, t0), equalTo(expected)); assertThat(DateUtils.truncate(field, t0, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t1), equalTo(expected)); assertThat(DateUtils.truncate(field, t1, firstWeekday), equalTo(expected));
assertThat(DateUtils.truncate(field, t2), equalTo(expected)); assertThat(DateUtils.truncate(field, t2, firstWeekday), equalTo(expected));
} }
@Test @Test

Loading…
Cancel
Save