HistoryChart: Customizable first day of week

pull/707/head
Alinson S. Xavier 5 years ago
parent de3668db96
commit e2d2b5b4b3

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

@ -50,7 +50,7 @@ public class ScoreChartTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
presenter = new ScoreCardPresenter(); presenter = new ScoreCardPresenter();
ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 0); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekdayInt(), 0);
view = new ScoreChart(targetContext); view = new ScoreChart(targetContext);
view.setScores(model.getScores()); view.setScores(model.getScores());
@ -84,7 +84,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withMonthlyBucket() throws Throwable public void testRender_withMonthlyBucket() throws Throwable
{ {
ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 2); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekdayInt(), 2);
view.setScores(model.getScores()); view.setScores(model.getScores());
view.setBucketSize(model.getBucketSize()); view.setBucketSize(model.getBucketSize());
view.invalidate(); view.invalidate();
@ -102,7 +102,7 @@ public class ScoreChartTest extends BaseViewTest
@Test @Test
public void testRender_withYearlyBucket() throws Throwable public void testRender_withYearlyBucket() throws Throwable
{ {
ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekday(), 4); ScoreCardViewModel model = presenter.present(habit, prefs.getFirstWeekdayInt(), 4);
view.setScores(model.getScores()); view.setScores(model.getScores());
view.setBucketSize(model.getBucketSize()); view.setBucketSize(model.getBucketSize());
view.invalidate(); view.invalidate();

@ -22,6 +22,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.platform.time.DayOfWeek.SUNDAY
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
@ -47,7 +48,7 @@ class HistoryCardViewTest : BaseViewTest() {
view.update( view.update(
HistoryCardPresenter().present( HistoryCardPresenter().present(
habit = habit, habit = habit,
firstWeekday = 1, firstWeekday = SUNDAY,
isSkipEnabled = false, isSkipEnabled = false,
theme = LightTheme(), theme = LightTheme(),
) )

@ -29,8 +29,6 @@ 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
@ -49,7 +47,7 @@ public class HistoryWidgetTest extends BaseViewTest
prefs.setWidgetOpacity(255); prefs.setWidgetOpacity(255);
habit = fixtures.createVeryLongHabit(); habit = fixtures.createVeryLongHabit();
HistoryWidget widget = new HistoryWidget(targetContext, 0, habit, Calendar.SUNDAY); HistoryWidget widget = new HistoryWidget(targetContext, 0, habit);
view = convertToView(widget, 400, 400); view = convertToView(widget, 400, 400);
} }

@ -22,12 +22,12 @@ package org.isoron.uhabits.activities.common.dialogs;
import android.app.*; import android.app.*;
import android.content.*; import android.content.*;
import android.os.*; import android.os.*;
import android.util.*;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.*;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.*; import androidx.appcompat.app.*;
import android.util.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.core.commands.*; import org.isoron.uhabits.core.commands.*;

@ -47,15 +47,12 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont
today = data.today, today = data.today,
paletteColor = data.color, paletteColor = data.color,
theme = data.theme, theme = data.theme,
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()) dateFormatter = JavaLocalDateFormatter(Locale.getDefault()),
).apply { series = data.series,
series = data.series firstWeekday = data.firstWeekday,
} )
// binding.historyChart.setFirstWeekday(data.firstWeekday)
// binding.historyChart.setSkipEnabled(data.isSkipEnabled) // binding.historyChart.setSkipEnabled(data.isSkipEnabled)
// binding.historyChart.setEntries(data.entries)
// binding.historyChart.setColor(androidColor)
// if (data.isNumerical) { // if (data.isNumerical) {
// binding.historyChart.setNumerical(true) // binding.historyChart.setNumerical(true)
// } // }

@ -177,7 +177,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
private void updateWeekdayPreference() private void updateWeekdayPreference()
{ {
ListPreference weekdayPref = (ListPreference) findPreference("pref_first_weekday"); ListPreference weekdayPref = (ListPreference) findPreference("pref_first_weekday");
int currentFirstWeekday = prefs.getFirstWeekday(); int currentFirstWeekday = prefs.getFirstWeekday().getDaysSinceSunday() + 1;
String[] dayNames = DateUtils.getLongWeekdayNames(Calendar.SATURDAY); String[] dayNames = DateUtils.getLongWeekdayNames(Calendar.SATURDAY);
String[] dayValues = {"7", "1", "2", "3", "4", "5", "6"}; String[] dayValues = {"7", "1", "2", "3", "4", "5", "6"};
weekdayPref.setEntries(dayNames); weekdayPref.setEntries(dayNames);

@ -28,7 +28,7 @@ class FrequencyWidgetProvider : BaseWidgetProvider() {
context, context,
id, id,
habits[0], habits[0],
preferences.firstWeekday preferences.firstWeekdayInt
) )
else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits) else return StackWidget(context, id, StackWidgetType.FREQUENCY, habits)
} }

@ -35,8 +35,7 @@ import java.util.Locale
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 {
@ -66,7 +65,9 @@ class HistoryWidget(
today = DateUtils.getTodayWithOffset().toLocalDate(), today = DateUtils.getTodayWithOffset().toLocalDate(),
paletteColor = habit.color, paletteColor = habit.color,
theme = WidgetTheme(), theme = WidgetTheme(),
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()) dateFormatter = JavaLocalDateFormatter(Locale.getDefault()),
firstWeekday = prefs.firstWeekday,
series = listOf(),
) )
} }
).apply { ).apply {

@ -26,8 +26,7 @@ class HistoryWidgetProvider : BaseWidgetProvider() {
if (habits.size == 1) return HistoryWidget( if (habits.size == 1) return HistoryWidget(
context, context,
id, id,
habits[0], habits[0]
preferences.firstWeekday
) )
else return StackWidget(context, id, StackWidgetType.HISTORY, habits) else return StackWidget(context, id, StackWidgetType.HISTORY, habits)
} }

@ -40,7 +40,7 @@ class ScoreWidget(
val presenter = ScoreCardPresenter() val presenter = ScoreCardPresenter()
val viewModel = presenter.present( val viewModel = presenter.present(
habit = habit, habit = habit,
firstWeekday = prefs.firstWeekday, firstWeekday = prefs.firstWeekdayInt,
spinnerPosition = prefs.scoreCardSpinnerPosition spinnerPosition = prefs.scoreCardSpinnerPosition
) )
val widgetView = view as GraphWidgetView val widgetView = view as GraphWidgetView

@ -97,11 +97,11 @@ class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory
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, prefs.getFirstWeekday()); return new FrequencyWidget(context, widgetId, habit, prefs.getFirstWeekdayInt());
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, prefs.getFirstWeekday()); return new HistoryWidget(context, widgetId, habit);
case STREAKS: case STREAKS:
return new StreakWidget(context, widgetId, habit); return new StreakWidget(context, widgetId, habit);
} }

@ -46,7 +46,7 @@ class TargetWidget(
if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f) if (preferedBackgroundAlpha >= 255) widgetView.setShadowAlpha(0x4f)
val chart = (widgetView.dataView as TargetChart) val chart = (widgetView.dataView as TargetChart)
val presenter = TargetCardPresenter() val presenter = TargetCardPresenter()
val data = presenter.present(habit, prefs.firstWeekday) val data = presenter.present(habit, prefs.firstWeekdayInt)
chart.setColor(data.color.toThemedAndroidColor(context)) chart.setColor(data.color.toThemedAndroidColor(context))
chart.setTargets(data.targets) chart.setTargets(data.targets)
chart.setLabels(data.intervals.map { intervalToLabel(context.resources, it) }) chart.setLabels(data.intervals.map { intervalToLabel(context.resources, it) })

@ -23,7 +23,7 @@ import org.isoron.uhabits.core.models.Timestamp
import kotlin.math.abs import kotlin.math.abs
import kotlin.math.ceil import kotlin.math.ceil
enum class DayOfWeek(val index: Int) { enum class DayOfWeek(val daysSinceSunday: Int) {
SUNDAY(0), SUNDAY(0),
MONDAY(1), MONDAY(1),
TUESDAY(2), TUESDAY(2),

@ -21,6 +21,7 @@ package org.isoron.uhabits.core.preferences;
import androidx.annotation.*; import androidx.annotation.*;
import org.isoron.platform.time.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.ui.*; import org.isoron.uhabits.core.ui.*;
import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.core.utils.*;
@ -360,13 +361,30 @@ public class Preferences
* represented by 7. By default, this is based on the current system locale, * represented by 7. By default, this is based on the current system locale,
* unless the user changed this in the settings. * unless the user changed this in the settings.
*/ */
public int getFirstWeekday() @Deprecated()
public int getFirstWeekdayInt()
{ {
String weekday = storage.getString("pref_first_weekday", ""); String weekday = storage.getString("pref_first_weekday", "");
if (weekday.isEmpty()) return DateUtils.getFirstWeekdayNumberAccordingToLocale(); if (weekday.isEmpty()) return DateUtils.getFirstWeekdayNumberAccordingToLocale();
return Integer.parseInt(weekday); return Integer.parseInt(weekday);
} }
public DayOfWeek getFirstWeekday()
{
int weekday = Integer.parseInt(storage.getString("pref_first_weekday", "-1"));
if (weekday < 0) weekday = DateUtils.getFirstWeekdayNumberAccordingToLocale();
switch (weekday) {
case 1: return DayOfWeek.SUNDAY;
case 2: return DayOfWeek.MONDAY;
case 3: return DayOfWeek.TUESDAY;
case 4: return DayOfWeek.WEDNESDAY;
case 5: return DayOfWeek.THURSDAY;
case 6: return DayOfWeek.FRIDAY;
case 7: return DayOfWeek.SATURDAY;
default: throw new IllegalArgumentException();
}
}
public interface Listener public interface Listener
{ {
default void onCheckmarkSequenceChanged() default void onCheckmarkSequenceChanged()

@ -78,7 +78,7 @@ class ShowHabitPresenter {
), ),
target = TargetCardPresenter().present( target = TargetCardPresenter().present(
habit = habit, habit = habit,
firstWeekday = preferences.firstWeekday, firstWeekday = preferences.firstWeekdayInt,
), ),
streaks = StreakCartPresenter().present( streaks = StreakCartPresenter().present(
habit = habit, habit = habit,
@ -86,11 +86,11 @@ class ShowHabitPresenter {
scores = ScoreCardPresenter().present( scores = ScoreCardPresenter().present(
spinnerPosition = preferences.scoreCardSpinnerPosition, spinnerPosition = preferences.scoreCardSpinnerPosition,
habit = habit, habit = habit,
firstWeekday = preferences.firstWeekday, firstWeekday = preferences.firstWeekdayInt,
), ),
frequency = FrequencyCardPresenter().present( frequency = FrequencyCardPresenter().present(
habit = habit, habit = habit,
firstWeekday = preferences.firstWeekday, firstWeekday = preferences.firstWeekdayInt,
), ),
history = HistoryCardPresenter().present( history = HistoryCardPresenter().present(
habit = habit, habit = habit,
@ -100,7 +100,7 @@ class ShowHabitPresenter {
), ),
bar = BarCardPresenter().present( bar = BarCardPresenter().present(
habit = habit, habit = habit,
firstWeekday = preferences.firstWeekday, firstWeekday = preferences.firstWeekdayInt,
boolSpinnerPosition = preferences.barCardBoolSpinnerPosition, boolSpinnerPosition = preferences.barCardBoolSpinnerPosition,
numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition, numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition,
theme = theme, theme = theme,

@ -19,6 +19,7 @@
package org.isoron.uhabits.core.ui.screens.habits.show.views package org.isoron.uhabits.core.ui.screens.habits.show.views
import org.isoron.platform.time.DayOfWeek
import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.core.models.Entry.Companion.SKIP import org.isoron.uhabits.core.models.Entry.Companion.SKIP
@ -33,7 +34,7 @@ import kotlin.math.max
data class HistoryCardViewModel( data class HistoryCardViewModel(
val color: PaletteColor, val color: PaletteColor,
val firstWeekday: Int, val firstWeekday: DayOfWeek,
val series: List<HistoryChart.Square>, val series: List<HistoryChart.Square>,
val theme: Theme, val theme: Theme,
val today: LocalDate, val today: LocalDate,
@ -42,7 +43,7 @@ data class HistoryCardViewModel(
class HistoryCardPresenter { class HistoryCardPresenter {
fun present( fun present(
habit: Habit, habit: Habit,
firstWeekday: Int, firstWeekday: DayOfWeek,
isSkipEnabled: Boolean, isSkipEnabled: Boolean,
theme: Theme, theme: Theme,
): HistoryCardViewModel { ): HistoryCardViewModel {

@ -23,6 +23,7 @@ import org.isoron.platform.gui.Canvas
import org.isoron.platform.gui.Color import org.isoron.platform.gui.Color
import org.isoron.platform.gui.DataView import org.isoron.platform.gui.DataView
import org.isoron.platform.gui.TextAlign import org.isoron.platform.gui.TextAlign
import org.isoron.platform.time.DayOfWeek
import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDate
import org.isoron.platform.time.LocalDateFormatter import org.isoron.platform.time.LocalDateFormatter
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
@ -34,6 +35,8 @@ class HistoryChart(
var paletteColor: PaletteColor, var paletteColor: PaletteColor,
var theme: Theme, var theme: Theme,
var dateFormatter: LocalDateFormatter, var dateFormatter: LocalDateFormatter,
var firstWeekday: DayOfWeek,
var series: List<Square>,
) : DataView { ) : DataView {
enum class Square { enum class Square {
@ -43,9 +46,6 @@ class HistoryChart(
HATCHED, HATCHED,
} }
// Data
var series = listOf<Square>()
// Style // Style
var padding = 0.0 var padding = 0.0
var squareSpacing = 1.0 var squareSpacing = 1.0
@ -69,8 +69,11 @@ class HistoryChart(
canvas.setFontSize(height * 0.06) canvas.setFontSize(height * 0.06)
val nColumns = floor((width - 2 * padding) / squareSize).toInt() - 2 val nColumns = floor((width - 2 * padding) / squareSize).toInt() - 2
val todayWeekday = today.dayOfWeek val firstWeekdayOffset = (
val topLeftOffset = (nColumns - 1 + dataOffset) * 7 + todayWeekday.index today.dayOfWeek.daysSinceSunday -
firstWeekday.daysSinceSunday + 7
) % 7
val topLeftOffset = (nColumns - 1 + dataOffset) * 7 + firstWeekdayOffset
val topLeftDate = today.minus(topLeftOffset) val topLeftDate = today.minus(topLeftOffset)
lastPrintedYear = "" lastPrintedYear = ""

@ -114,4 +114,4 @@ class WidgetTheme : LightTheme() {
override val highContrastTextColor = Color.WHITE override val highContrastTextColor = Color.WHITE
override val mediumContrastTextColor = Color.WHITE.withAlpha(0.50) override val mediumContrastTextColor = Color.WHITE.withAlpha(0.50)
override val lowContrastTextColor = Color.WHITE.withAlpha(0.10) override val lowContrastTextColor = Color.WHITE.withAlpha(0.10)
} }

@ -21,6 +21,8 @@ package org.isoron.uhabits.components
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.isoron.platform.gui.assertRenders import org.isoron.platform.gui.assertRenders
import org.isoron.platform.time.DayOfWeek
import org.isoron.platform.time.DayOfWeek.SUNDAY
import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.platform.time.JavaLocalDateFormatter
import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDate
import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.PaletteColor
@ -37,14 +39,13 @@ import java.util.Locale
class HistoryChartTest { class HistoryChartTest {
val base = "views/HistoryChart" val base = "views/HistoryChart"
val fmt = JavaLocalDateFormatter(Locale.US)
val theme = LightTheme()
val view = HistoryChart( val view = HistoryChart(
LocalDate(2015, 1, 25), today = LocalDate(2015, 1, 25),
PaletteColor(7), paletteColor = PaletteColor(7),
theme, theme = LightTheme(),
fmt, dateFormatter = JavaLocalDateFormatter(Locale.US),
).apply { firstWeekday = SUNDAY,
series = listOf( series = listOf(
2, // today 2, // today
2, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2,
@ -68,19 +69,24 @@ class HistoryChartTest {
else -> OFF else -> OFF
} }
} }
} )
// TODO: Label overflow // TODO: Label overflow
// TODO: onClick // TODO: onClick
// TODO: HistoryEditorDialog // TODO: HistoryEditorDialog
// TODO: Remove excessive padding on widgets // TODO: Remove excessive padding on widgets
// TODO: First day of the week
@Test @Test
fun testDraw() = runBlocking { fun testDraw() = runBlocking {
assertRenders(400, 200, "$base/base.png", view) assertRenders(400, 200, "$base/base.png", view)
} }
@Test
fun testDrawWeekDay() = runBlocking {
view.firstWeekday = DayOfWeek.MONDAY
assertRenders(400, 200, "$base/weekday.png", view)
}
@Test @Test
fun testDrawDifferentSize() = runBlocking { fun testDrawDifferentSize() = runBlocking {
assertRenders(200, 200, "$base/small.png", view) assertRenders(200, 200, "$base/small.png", view)

Loading…
Cancel
Save