implemented custom weekday feature in frequency and history charts

pull/349/head
Name 8 years ago
parent d0d1db6513
commit 39e7da81bc

@ -27,14 +27,14 @@ import android.util.*;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.Preferences;
import org.isoron.uhabits.core.utils.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class FrequencyChart extends ScrollableChart
{
public class FrequencyChart extends ScrollableChart {
private Paint pGrid;
private float em;
@ -67,39 +67,36 @@ public class FrequencyChart extends ScrollableChart
private boolean isBackgroundTransparent;
private int firstWeekDay;
@NonNull
private HashMap<Timestamp, Integer[]> frequency;
private int maxFreq;
public FrequencyChart(Context context)
{
public FrequencyChart(Context context) {
super(context);
init();
}
public FrequencyChart(Context context, AttributeSet attrs)
{
public FrequencyChart(Context context, AttributeSet attrs) {
super(context, attrs);
this.frequency = new HashMap<>();
init();
}
public void setColor(int color)
{
public void setColor(int color) {
this.primaryColor = color;
initColors();
postInvalidate();
}
public void setFrequency(HashMap<Timestamp, Integer[]> frequency)
{
public void setFrequency(HashMap<Timestamp, Integer[]> frequency) {
this.frequency = frequency;
maxFreq = getMaxFreq(frequency);
postInvalidate();
}
private int getMaxFreq(HashMap<Timestamp, Integer[]> frequency)
{
private int getMaxFreq(HashMap<Timestamp, Integer[]> frequency) {
int maxValue = 1;
for (Integer[] values : frequency.values())
@ -109,14 +106,12 @@ public class FrequencyChart extends ScrollableChart
return maxValue;
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
public void setIsBackgroundTransparent(boolean isBackgroundTransparent) {
this.isBackgroundTransparent = isBackgroundTransparent;
initColors();
}
protected void initPaints()
{
protected void initPaints() {
pText = new Paint();
pText.setAntiAlias(true);
@ -129,8 +124,7 @@ public class FrequencyChart extends ScrollableChart
}
@Override
protected void onDraw(Canvas canvas)
{
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
rect.set(0, 0, nColumns * columnWidth, columnHeight);
@ -148,8 +142,7 @@ public class FrequencyChart extends ScrollableChart
currentDate.set(Calendar.DAY_OF_MONTH, 1);
currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset());
for (int i = 0; i < nColumns - 1; i++)
{
for (int i = 0; i < nColumns - 1; i++) {
rect.set(0, 0, columnWidth, columnHeight);
rect.offset(i * columnWidth, 0);
@ -159,8 +152,7 @@ public class FrequencyChart extends ScrollableChart
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
@ -170,8 +162,7 @@ public class FrequencyChart extends ScrollableChart
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
int oldHeight) {
if (height < 9) height = 200;
baseSize = height / 8;
@ -191,15 +182,14 @@ public class FrequencyChart extends ScrollableChart
paddingTop = 0;
}
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));
float rowHeight = rect.height() / 8.0f;
prevRect.set(rect);
Integer[] localeWeekdayList = DateUtils.getLocaleWeekdayList();
for (int j = 0; j < localeWeekdayList.length; j++)
{
for (int j = 0; j < localeWeekdayList.length; j++) {
rect.set(0, 0, baseSize, baseSize);
rect.offset(prevRect.left, prevRect.top + baseSize * j);
@ -212,20 +202,18 @@ public class FrequencyChart extends ScrollableChart
drawFooter(canvas, rect, date);
}
private void drawFooter(Canvas canvas, RectF rect, GregorianCalendar date)
{
private void drawFooter(Canvas canvas, RectF rect, GregorianCalendar date) {
Date time = date.getTime();
canvas.drawText(dfMonth.format(time), rect.centerX(),
rect.centerY() - 0.1f * em, pText);
rect.centerY() - 0.1f * em, pText);
if (date.get(Calendar.MONTH) == 1)
canvas.drawText(dfYear.format(time), rect.centerX(),
rect.centerY() + 0.9f * em, pText);
rect.centerY() + 0.9f * em, pText);
}
private void drawGrid(Canvas canvas, RectF rGrid)
{
private void drawGrid(Canvas canvas, RectF rGrid) {
int nRows = 7;
float rowHeight = rGrid.height() / (nRows + 1);
@ -233,14 +221,13 @@ public class FrequencyChart extends ScrollableChart
pText.setColor(textColor);
pGrid.setColor(gridColor);
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
{
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT, firstWeekDay)) {
canvas.drawText(day, rGrid.right - columnWidth,
rGrid.top + rowHeight / 2 + 0.25f * em, pText);
rGrid.top + rowHeight / 2 + 0.25f * em, pText);
pGrid.setStrokeWidth(1f);
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top,
pGrid);
pGrid);
rGrid.offset(0, rowHeight);
}
@ -248,13 +235,12 @@ public class FrequencyChart extends ScrollableChart
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
}
private void drawMarker(Canvas canvas, RectF rect, Integer value)
{
private void drawMarker(Canvas canvas, RectF rect, Integer value) {
float padding = rect.height() * 0.2f;
// maximal allowed mark radius
float maxRadius = (rect.height() - 2 * padding) / 2.0f;
// the real mark radius is scaled down by a factor depending on the maximal frequency
float scale = 1.0f/maxFreq * value;
float scale = 1.0f / maxFreq * value;
float radius = maxRadius * scale;
int colorIndex = Math.min(colors.length - 1, Math.round((colors.length - 1) * scale));
@ -262,13 +248,11 @@ public class FrequencyChart extends ScrollableChart
canvas.drawCircle(rect.centerX(), rect.centerY(), radius, pGraph);
}
private float getMaxMonthWidth()
{
private float getMaxMonthWidth() {
float maxMonthWidth = 0;
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
for (int i = 0; i < 12; i++)
{
for (int i = 0; i < 12; i++) {
day.set(Calendar.MONTH, i);
float monthWidth = pText.measureText(dfMonth.format(day.getTime()));
maxMonthWidth = Math.max(maxMonthWidth, monthWidth);
@ -277,16 +261,22 @@ public class FrequencyChart extends ScrollableChart
return maxMonthWidth;
}
private void init()
{
private void init() {
initPaints();
initColors();
initDateFormats();
initRects();
initFirstWeekDay();
}
private void initFirstWeekDay() {
HabitsApplication app = (HabitsApplication) getContext().getApplicationContext();
Preferences prefs = app.getComponent().getPreferences();
firstWeekDay = prefs.getFirstWeekDay();
}
private void initColors()
{
private void initColors() {
StyledResources res = new StyledResources(getContext());
textColor = res.getColor(R.attr.mediumContrastTextColor);
gridColor = res.getColor(R.attr.lowContrastTextColor);
@ -298,27 +288,23 @@ public class FrequencyChart extends ScrollableChart
colors[2] = ColorUtils.mixColors(colors[0], colors[3], 0.33f);
}
private void initDateFormats()
{
private void initDateFormats() {
dfMonth = AndroidDateFormats.fromSkeleton("MMM");
dfYear = AndroidDateFormats.fromSkeleton("yyyy");
}
private void initRects()
{
private void initRects() {
rect = new RectF();
prevRect = new RectF();
}
public void populateWithRandomData()
{
public void populateWithRandomData() {
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
date.set(Calendar.DAY_OF_MONTH, 1);
Random rand = new Random();
frequency.clear();
for (int i = 0; i < 40; i++)
{
for (int i = 0; i < 40; i++) {
Integer values[] = new Integer[7];
for (int j = 0; j < 7; j++)
values[j] = rand.nextInt(5);

@ -39,8 +39,7 @@ import java.util.*;
import static org.isoron.androidbase.utils.InterfaceUtils.*;
import static org.isoron.uhabits.core.models.Checkmark.*;
public class HistoryChart extends ScrollableChart
{
public class HistoryChart extends ScrollableChart {
private int[] checkmarks;
private int target;
@ -97,42 +96,35 @@ public class HistoryChart extends ScrollableChart
@NonNull
private Controller controller;
private int weekFirstDay;
private int firstWeekDay;
public HistoryChart(Context context)
{
public HistoryChart(Context context) {
super(context);
init();
}
public HistoryChart(Context context, AttributeSet attrs)
{
public HistoryChart(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
@Override
public void onLongPress(MotionEvent e)
{
public void onLongPress(MotionEvent e) {
onSingleTapUp(e);
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
public boolean onSingleTapUp(MotionEvent e) {
if (!isEditable) return false;
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
float x, y;
try
{
try {
int pointerId = e.getPointerId(0);
x = e.getX(pointerId);
y = e.getY(pointerId);
}
catch (RuntimeException ex)
{
} catch (RuntimeException ex) {
// Android often throws IllegalArgumentException here. Apparently,
// the pointer id may become invalid shortly after calling
// e.getPointerId.
@ -144,8 +136,7 @@ public class HistoryChart extends ScrollableChart
Timestamp today = DateUtils.getToday();
int offset = timestamp.daysUntil(today);
if (offset < checkmarks.length)
{
if (offset < checkmarks.length) {
boolean isChecked = checkmarks[offset] == CHECKED_EXPLICITLY;
checkmarks[offset] = (isChecked ? UNCHECKED : CHECKED_EXPLICITLY);
}
@ -155,16 +146,14 @@ public class HistoryChart extends ScrollableChart
return true;
}
public void populateWithRandomData()
{
public void populateWithRandomData() {
Random random = new Random();
checkmarks = new int[100];
for (int i = 0; i < 100; i++)
if (random.nextFloat() < 0.3) checkmarks[i] = 2;
for (int i = 0; i < 100 - 7; i++)
{
for (int i = 0; i < 100 - 7; i++) {
int count = 0;
for (int j = 0; j < 7; j++)
if (checkmarks[i + j] != 0) count++;
@ -173,48 +162,40 @@ public class HistoryChart extends ScrollableChart
}
}
public void setCheckmarks(int[] checkmarks)
{
public void setCheckmarks(int[] checkmarks) {
this.checkmarks = checkmarks;
postInvalidate();
}
public void setColor(int color)
{
public void setColor(int color) {
this.primaryColor = color;
initColors();
postInvalidate();
}
public void setController(@NonNull Controller controller)
{
public void setController(@NonNull Controller controller) {
this.controller = controller;
}
public void setNumerical(boolean numerical)
{
public void setNumerical(boolean numerical) {
isNumerical = numerical;
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
public void setIsBackgroundTransparent(boolean isBackgroundTransparent) {
this.isBackgroundTransparent = isBackgroundTransparent;
initColors();
}
public void setIsEditable(boolean isEditable)
{
public void setIsEditable(boolean isEditable) {
this.isEditable = isEditable;
}
public void setTarget(int target)
{
public void setTarget(int target) {
this.target = target;
postInvalidate();
}
protected void initPaints()
{
protected void initPaints() {
pTextHeader = new Paint();
pTextHeader.setTextAlign(Align.LEFT);
pTextHeader.setAntiAlias(true);
@ -227,12 +208,11 @@ public class HistoryChart extends ScrollableChart
}
@Override
protected void onDraw(Canvas canvas)
{
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
baseLocation.set(0, 0, columnWidth - squareSpacing,
columnWidth - squareSpacing);
columnWidth - squareSpacing);
baseLocation.offset(getPaddingLeft(), getPaddingTop());
headerOverflow = 0;
@ -243,8 +223,7 @@ public class HistoryChart extends ScrollableChart
updateDate();
GregorianCalendar currentDate = (GregorianCalendar) baseDate.clone();
for (int column = 0; column < nColumns - 1; column++)
{
for (int column = 0; column < nColumns - 1; column++) {
drawColumn(canvas, baseLocation, currentDate, column);
baseLocation.offset(columnWidth, -columnHeight);
}
@ -253,8 +232,7 @@ public class HistoryChart extends ScrollableChart
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
@ -264,8 +242,7 @@ public class HistoryChart extends ScrollableChart
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
int oldHeight) {
if (height < 8) height = 200;
float baseSize = height / 8.0f;
setScrollerBucketSize((int) baseSize);
@ -286,40 +263,35 @@ public class HistoryChart extends ScrollableChart
columnWidth = baseSize;
columnHeight = 8 * baseSize;
nColumns =
(int) ((width - rightLabelWidth - horizontalPadding) / baseSize) +
1;
(int) ((width - rightLabelWidth - horizontalPadding) / baseSize) +
1;
updateDate();
}
private void drawAxis(Canvas canvas, RectF location)
{
private void drawAxis(Canvas canvas, RectF location) {
float verticalOffset = pTextHeader.getFontSpacing() * 0.4f;
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
{
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT, firstWeekDay)) {
location.offset(0, columnWidth);
canvas.drawText(day, location.left + headerTextOffset,
location.centerY() + verticalOffset, pTextHeader);
location.centerY() + verticalOffset, pTextHeader);
}
}
private void drawColumn(Canvas canvas,
RectF location,
GregorianCalendar date,
int column)
{
int column) {
drawColumnHeader(canvas, location, date);
location.offset(0, columnWidth);
for (int j = 0; j < 7; j++)
{
for (int j = 0; j < 7; j++) {
if (!(column == nColumns - 2 && getDataOffset() == 0 &&
j > todayPositionInColumn))
{
j > todayPositionInColumn)) {
int checkmarkOffset =
getDataOffset() * 7 + nDays - 7 * (column + 1) +
todayPositionInColumn - j;
getDataOffset() * 7 + nDays - 7 * (column + 1) +
todayPositionInColumn - j;
drawSquare(canvas, location, date, checkmarkOffset);
}
@ -330,8 +302,7 @@ public class HistoryChart extends ScrollableChart
private void drawColumnHeader(Canvas canvas,
RectF location,
GregorianCalendar date)
{
GregorianCalendar date) {
String month = dfMonth.format(date.getTime());
String year = dfYear.format(date.getTime());
@ -339,12 +310,11 @@ public class HistoryChart extends ScrollableChart
if (!month.equals(previousMonth)) text = previousMonth = month;
else if (!year.equals(previousYear)) text = previousYear = year;
if (text != null)
{
if (text != null) {
canvas.drawText(text, location.left + headerOverflow,
location.bottom - headerTextOffset, pTextHeader);
location.bottom - headerTextOffset, pTextHeader);
headerOverflow +=
pTextHeader.measureText(text) + columnWidth * 0.2f;
pTextHeader.measureText(text) + columnWidth * 0.2f;
}
headerOverflow = Math.max(0, headerOverflow - columnWidth);
@ -353,60 +323,54 @@ public class HistoryChart extends ScrollableChart
private void drawSquare(Canvas canvas,
RectF location,
GregorianCalendar date,
int checkmarkOffset)
{
int checkmarkOffset) {
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
else
{
else {
int checkmark = checkmarks[checkmarkOffset];
if(checkmark == 0) pSquareBg.setColor(colors[0]);
else if(checkmark < target)
{
if (checkmark == 0) pSquareBg.setColor(colors[0]);
else if (checkmark < target) {
pSquareBg.setColor(isNumerical ? textColor : colors[1]);
}
else pSquareBg.setColor(colors[2]);
} else pSquareBg.setColor(colors[2]);
}
pSquareFg.setColor(reverseTextColor);
canvas.drawRect(location, pSquareBg);
String text = Integer.toString(date.get(Calendar.DAY_OF_MONTH));
canvas.drawText(text, location.centerX(),
location.centerY() + squareTextOffset, pSquareFg);
location.centerY() + squareTextOffset, pSquareFg);
}
private float getWeekdayLabelWidth()
{
private float getWeekdayLabelWidth() {
float width = 0;
for (String w : DateUtils.getLocaleDayNames(Calendar.SHORT))
for (String w : DateUtils.getLocaleDayNames(Calendar.SHORT, firstWeekDay))
width = Math.max(width, pSquareFg.measureText(w));
return width;
}
private void init()
{
private void init() {
isEditable = false;
checkmarks = new int[0];
controller = new Controller() {};
controller = new Controller() {
};
target = 2;
initColors();
initPaints();
initDateFormats();
initRects();
initWeekFirstDay();
initFirstWeekDay();
}
private void initWeekFirstDay() {
private void initFirstWeekDay() {
HabitsApplication app = (HabitsApplication) getContext().getApplicationContext();
Preferences prefs = app.getComponent().getPreferences();
weekFirstDay = prefs.getWeekFirstDay();
firstWeekDay = prefs.getFirstWeekDay();
}
private void initColors()
{
private void initColors() {
StyledResources res = new StyledResources(getContext());
if (isBackgroundTransparent)
@ -416,41 +380,35 @@ public class HistoryChart extends ScrollableChart
int green = Color.green(primaryColor);
int blue = Color.blue(primaryColor);
if (isBackgroundTransparent)
{
if (isBackgroundTransparent) {
colors = new int[3];
colors[0] = Color.argb(16, 255, 255, 255);
colors[1] = Color.argb(128, red, green, blue);
colors[2] = primaryColor;
textColor = Color.WHITE;
reverseTextColor = Color.WHITE;
}
else
{
} else {
colors = new int[3];
colors[0] = res.getColor(R.attr.lowContrastTextColor);
colors[1] = Color.argb(127, red, green, blue);
colors[2] = primaryColor;
textColor = res.getColor(R.attr.mediumContrastTextColor);
reverseTextColor =
res.getColor(R.attr.highContrastReverseTextColor);
res.getColor(R.attr.highContrastReverseTextColor);
}
}
private void initDateFormats()
{
private void initDateFormats() {
dfMonth = AndroidDateFormats.fromSkeleton("MMM");
dfYear = AndroidDateFormats.fromSkeleton("yyyy");
}
private void initRects()
{
private void initRects() {
baseLocation = new RectF();
}
@Nullable
private Timestamp positionToTimestamp(float x, float y)
{
private Timestamp positionToTimestamp(float x, float y) {
int col = (int) (x / columnWidth);
int row = (int) (y / columnWidth);
@ -462,31 +420,30 @@ public class HistoryChart extends ScrollableChart
date.add(Calendar.DAY_OF_YEAR, offset);
if (DateUtils.getStartOfDay(date.getTimeInMillis()) >
DateUtils.getStartOfToday()) return null;
DateUtils.getStartOfToday()) return null;
return new Timestamp(date.getTimeInMillis());
}
private void updateDate()
{
private void updateDate() {
baseDate = DateUtils.getStartOfTodayCalendar();
baseDate.setFirstDayOfWeek(weekFirstDay);
baseDate.setFirstDayOfWeek(firstWeekDay);
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
nDays = (nColumns - 1) * 7;
int realWeekday =
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
todayPositionInColumn =
(7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
(7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);
}
public interface Controller
{
default void onToggleCheckmark(Timestamp timestamp) {}
public interface Controller {
default void onToggleCheckmark(Timestamp timestamp) {
}
}
}

@ -26,11 +26,10 @@ import org.isoron.uhabits.core.ui.*;
import java.util.*;
public class Preferences
{
public class Preferences {
public static final String DEFAULT_SYNC_SERVER =
"https://sync.loophabits.org";
"https://sync.loophabits.org";
@NonNull
private final Storage storage;
@ -41,51 +40,41 @@ public class Preferences
@Nullable
private Boolean shouldReverseCheckmarks = null;
public Preferences(@NonNull Storage storage)
{
public Preferences(@NonNull Storage storage) {
this.storage = storage;
listeners = new LinkedList<>();
storage.onAttached(this);
}
public void addListener(Listener listener)
{
public void addListener(Listener listener) {
listeners.add(listener);
}
public Integer getDefaultHabitColor(int fallbackColor)
{
public Integer getDefaultHabitColor(int fallbackColor) {
return storage.getInt("pref_default_habit_palette_color",
fallbackColor);
fallbackColor);
}
public HabitList.Order getDefaultOrder()
{
public HabitList.Order getDefaultOrder() {
String name = storage.getString("pref_default_order", "BY_POSITION");
try
{
try {
return HabitList.Order.valueOf(name);
}
catch (IllegalArgumentException e)
{
} catch (IllegalArgumentException e) {
setDefaultOrder(HabitList.Order.BY_POSITION);
return HabitList.Order.BY_POSITION;
}
}
public void setDefaultOrder(HabitList.Order order)
{
public void setDefaultOrder(HabitList.Order order) {
storage.putString("pref_default_order", order.name());
}
public int getDefaultScoreSpinnerPosition()
{
public int getDefaultScoreSpinnerPosition() {
int defaultScoreInterval =
storage.getInt("pref_score_view_interval", 1);
storage.getInt("pref_score_view_interval", 1);
if (defaultScoreInterval > 5 || defaultScoreInterval < 0)
{
if (defaultScoreInterval > 5 || defaultScoreInterval < 0) {
defaultScoreInterval = 1;
storage.putInt("pref_score_view_interval", 1);
}
@ -93,76 +82,62 @@ public class Preferences
return defaultScoreInterval;
}
public void setDefaultScoreSpinnerPosition(int position)
{
public void setDefaultScoreSpinnerPosition(int position) {
storage.putInt("pref_score_view_interval", position);
}
public int getLastHintNumber()
{
public int getLastHintNumber() {
return storage.getInt("last_hint_number", -1);
}
public Timestamp getLastHintTimestamp()
{
public Timestamp getLastHintTimestamp() {
long unixTime = storage.getLong("last_hint_timestamp", -1);
if (unixTime < 0) return null;
else return new Timestamp(unixTime);
}
public long getLastSync()
{
public long getLastSync() {
return storage.getLong("last_sync", 0);
}
public void setLastSync(long timestamp)
{
public void setLastSync(long timestamp) {
storage.putLong("last_sync", timestamp);
}
public boolean getShowArchived()
{
public boolean getShowArchived() {
return storage.getBoolean("pref_show_archived", false);
}
public void setShowArchived(boolean showArchived)
{
public void setShowArchived(boolean showArchived) {
storage.putBoolean("pref_show_archived", showArchived);
}
public boolean getShowCompleted()
{
public boolean getShowCompleted() {
return storage.getBoolean("pref_show_completed", true);
}
public void setShowCompleted(boolean showCompleted)
{
public void setShowCompleted(boolean showCompleted) {
storage.putBoolean("pref_show_completed", showCompleted);
}
public long getSnoozeInterval()
{
public long getSnoozeInterval() {
return Long.parseLong(storage.getString("pref_snooze_interval", "15"));
}
public int getWeekFirstDay()
{
public int getFirstWeekDay() {
return Integer.parseInt(storage.getString("pref_week_start", "7"));
}
public String getSyncAddress()
{
public String getSyncAddress() {
return storage.getString("pref_sync_address", DEFAULT_SYNC_SERVER);
}
public void setSyncAddress(String address)
{
public void setSyncAddress(String address) {
storage.putString("pref_sync_address", address);
for (Listener l : listeners) l.onSyncFeatureChanged();
}
public String getSyncClientId()
{
public String getSyncClientId() {
String id = storage.getString("pref_sync_client_id", "");
if (!id.isEmpty()) return id;
@ -172,182 +147,152 @@ public class Preferences
return id;
}
public String getSyncKey()
{
public String getSyncKey() {
return storage.getString("pref_sync_key", "");
}
public int getTheme()
{
public int getTheme() {
return storage.getInt("pref_theme", ThemeSwitcher.THEME_LIGHT);
}
public void setTheme(int theme)
{
public void setTheme(int theme) {
storage.putInt("pref_theme", theme);
}
public void incrementLaunchCount()
{
public void incrementLaunchCount() {
storage.putInt("launch_count", getLaunchCount() + 1);
}
public int getLaunchCount()
{
public int getLaunchCount() {
return storage.getInt("launch_count", 0);
}
public boolean isDeveloper()
{
public boolean isDeveloper() {
return storage.getBoolean("pref_developer", false);
}
public void setDeveloper(boolean isDeveloper)
{
public void setDeveloper(boolean isDeveloper) {
storage.putBoolean("pref_developer", isDeveloper);
}
public boolean isFirstRun()
{
public boolean isFirstRun() {
return storage.getBoolean("pref_first_run", true);
}
public void setFirstRun(boolean isFirstRun)
{
public void setFirstRun(boolean isFirstRun) {
storage.putBoolean("pref_first_run", isFirstRun);
}
public boolean isNumericalHabitsFeatureEnabled()
{
public boolean isNumericalHabitsFeatureEnabled() {
return storage.getBoolean("pref_feature_numerical_habits", false);
}
public boolean isPureBlackEnabled()
{
public boolean isPureBlackEnabled() {
return storage.getBoolean("pref_pure_black", false);
}
public boolean isShortToggleEnabled()
{
public boolean isShortToggleEnabled() {
return storage.getBoolean("pref_short_toggle", false);
}
public void setShortToggleEnabled(boolean enabled)
{
public void setShortToggleEnabled(boolean enabled) {
storage.putBoolean("pref_short_toggle", enabled);
}
public boolean isSyncEnabled()
{
public boolean isSyncEnabled() {
return storage.getBoolean("pref_feature_sync", false);
}
public void removeListener(Listener listener)
{
public void removeListener(Listener listener) {
listeners.remove(listener);
}
public void clear()
{
public void clear() {
storage.clear();
}
public void setDefaultHabitColor(int color)
{
public void setDefaultHabitColor(int color) {
storage.putInt("pref_default_habit_palette_color", color);
}
public void setLastAppVersion(int version)
{
public void setLastAppVersion(int version) {
storage.putInt("last_version", version);
}
public void setNotificationsSticky(boolean sticky)
{
public void setNotificationsSticky(boolean sticky) {
storage.putBoolean("pref_sticky_notifications", sticky);
for (Listener l : listeners) l.onNotificationsChanged();
}
public void setNotificationsLed(boolean enabled)
{
public void setNotificationsLed(boolean enabled) {
storage.putBoolean("pref_led_notifications", enabled);
for (Listener l : listeners) l.onNotificationsChanged();
}
public void setCheckmarkSequenceReversed(boolean reverse)
{
public void setCheckmarkSequenceReversed(boolean reverse) {
shouldReverseCheckmarks = reverse;
storage.putBoolean("pref_checkmark_reverse_order", reverse);
for (Listener l : listeners) l.onCheckmarkSequenceChanged();
}
public void setSyncEnabled(boolean isEnabled)
{
public void setSyncEnabled(boolean isEnabled) {
storage.putBoolean("pref_feature_sync", isEnabled);
for(Listener l : listeners) l.onSyncFeatureChanged();
for (Listener l : listeners) l.onSyncFeatureChanged();
}
public boolean shouldMakeNotificationsSticky()
{
public boolean shouldMakeNotificationsSticky() {
return storage.getBoolean("pref_sticky_notifications", false);
}
public boolean shouldMakeNotificationsLed()
{
public boolean shouldMakeNotificationsLed() {
return storage.getBoolean("pref_led_notifications", false);
}
public boolean isCheckmarkSequenceReversed()
{
public boolean isCheckmarkSequenceReversed() {
if (shouldReverseCheckmarks == null) shouldReverseCheckmarks =
storage.getBoolean("pref_checkmark_reverse_order", false);
storage.getBoolean("pref_checkmark_reverse_order", false);
return shouldReverseCheckmarks;
}
public void updateLastHint(int number, Timestamp timestamp)
{
public void updateLastHint(int number, Timestamp timestamp) {
storage.putInt("last_hint_number", number);
storage.putLong("last_hint_timestamp", timestamp.getUnixTime());
}
public void setSyncKey(String key)
{
public void setSyncKey(String key) {
storage.putString("pref_sync_key", key);
for(Listener l : listeners) l.onSyncFeatureChanged();
for (Listener l : listeners) l.onSyncFeatureChanged();
}
public void setPureBlackEnabled(boolean enabled)
{
public void setPureBlackEnabled(boolean enabled) {
storage.putBoolean("pref_pure_black", enabled);
}
public int getLastAppVersion()
{
public int getLastAppVersion() {
return storage.getInt("last_version", 0);
}
public void setSnoozeInterval(int interval)
{
public void setSnoozeInterval(int interval) {
storage.putString("pref_snooze_interval", String.valueOf(interval));
}
public void setNumericalHabitsFeatureEnabled(boolean enabled)
{
public void setNumericalHabitsFeatureEnabled(boolean enabled) {
storage.putBoolean("pref_feature_numerical_habits", enabled);
}
public interface Listener
{
default void onCheckmarkSequenceChanged() {}
public interface Listener {
default void onCheckmarkSequenceChanged() {
}
default void onNotificationsChanged() {}
default void onNotificationsChanged() {
}
default void onSyncFeatureChanged() {}
default void onSyncFeatureChanged() {
}
}
public interface Storage
{
public interface Storage {
void clear();
boolean getBoolean(String key, boolean defValue);

@ -27,8 +27,7 @@ import java.util.*;
import static java.util.Calendar.*;
public abstract class DateUtils
{
public abstract class DateUtils {
private static Long fixedLocalTime = null;
@ -39,7 +38,7 @@ public abstract class DateUtils
/**
* Time of the day when the new day starts.
*/
public static final int NEW_DAY_OFFSET = -9;
public static final int NEW_DAY_OFFSET = 3;
/**
* Number of milliseconds in one day.
@ -51,37 +50,32 @@ public abstract class DateUtils
*/
public static final long HOUR_LENGTH = 60 * 60 * 1000;
public static long applyTimezone(long localTimestamp)
{
public static long applyTimezone(long localTimestamp) {
TimeZone tz = getTimezone();
return localTimestamp - tz.getOffset(localTimestamp - tz.getOffset(localTimestamp));
}
public static String formatHeaderDate(GregorianCalendar day)
{
public static String formatHeaderDate(GregorianCalendar day) {
Locale locale = getLocale();
String dayOfMonth = Integer.toString(day.get(DAY_OF_MONTH));
String dayOfWeek = day.getDisplayName(DAY_OF_WEEK, SHORT, locale);
return dayOfWeek + "\n" + dayOfMonth;
}
private static GregorianCalendar getCalendar(long timestamp)
{
private static GregorianCalendar getCalendar(long timestamp) {
GregorianCalendar day =
new GregorianCalendar(TimeZone.getTimeZone("GMT"), getLocale());
day.setTimeInMillis(timestamp);
return day;
}
private static String[] getDayNames(int format)
{
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++)
{
for (int i = 0; i < wdays.length; i++) {
wdays[i] =
day.getDisplayName(DAY_OF_WEEK, format, getLocale());
day.add(DAY_OF_MONTH, 1);
@ -90,8 +84,7 @@ public abstract class DateUtils
return wdays;
}
public static long getLocalTime()
{
public static long getLocalTime() {
if (fixedLocalTime != null) return fixedLocalTime;
TimeZone tz = getTimezone();
@ -103,14 +96,12 @@ public abstract class DateUtils
* @return array with weekday names starting according to locale settings,
* e.g. [Mo,Di,Mi,Do,Fr,Sa,So] in Germany
*/
public static String[] getLocaleDayNames(int format)
{
public static String[] getLocaleDayNames(int format, int firstWeekDay) {
String[] days = new String[7];
Calendar calendar = new GregorianCalendar();
calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek());
for (int i = 0; i < days.length; i++)
{
calendar.set(DAY_OF_WEEK, firstWeekDay);
for (int i = 0; i < days.length; i++) {
days[i] = calendar.getDisplayName(DAY_OF_WEEK, format,
getLocale());
calendar.add(DAY_OF_MONTH, 1);
@ -123,95 +114,80 @@ public abstract class DateUtils
* @return array with week days numbers starting according to locale
* settings, e.g. [2,3,4,5,6,7,1] in Europe
*/
public static Integer[] getLocaleWeekdayList()
{
public static Integer[] getLocaleWeekdayList() {
Integer[] dayNumbers = new Integer[7];
Calendar calendar = new GregorianCalendar();
calendar.set(DAY_OF_WEEK, calendar.getFirstDayOfWeek());
for (int i = 0; i < dayNumbers.length; i++)
{
calendar.set(DAY_OF_WEEK, MONDAY); // NOT RESPONSIBLE
for (int i = 0; i < dayNumbers.length; i++) {
dayNumbers[i] = calendar.get(DAY_OF_WEEK);
calendar.add(DAY_OF_MONTH, 1);
}
return dayNumbers;
}
public static String[] getLongDayNames()
{
public static String[] getLongDayNames() {
return getDayNames(GregorianCalendar.LONG);
}
public static String[] getShortDayNames()
{
public static String[] getShortDayNames() {
return getDayNames(SHORT);
}
@NonNull
public static Timestamp getToday()
{
public static Timestamp getToday() {
return new Timestamp(getStartOfToday());
}
public static long getStartOfDay(long timestamp)
{
public static long getStartOfDay(long timestamp) {
return (timestamp / DAY_LENGTH) * DAY_LENGTH;
}
public static long getStartOfToday()
{
public static long getStartOfToday() {
return getStartOfDay(getLocalTime() - NEW_DAY_OFFSET * HOUR_LENGTH);
}
public static long millisecondsUntilTomorrow()
{
public static long millisecondsUntilTomorrow() {
return getStartOfToday() + DAY_LENGTH -
(getLocalTime() - NEW_DAY_OFFSET * HOUR_LENGTH);
}
public static GregorianCalendar getStartOfTodayCalendar()
{
public static GregorianCalendar getStartOfTodayCalendar() {
return getCalendar(getStartOfToday());
}
private static TimeZone getTimezone()
{
if(fixedTimeZone != null) return fixedTimeZone;
private static TimeZone getTimezone() {
if (fixedTimeZone != null) return fixedTimeZone;
return TimeZone.getDefault();
}
public static void setFixedTimeZone(TimeZone tz)
{
public static void setFixedTimeZone(TimeZone tz) {
fixedTimeZone = tz;
}
public static long removeTimezone(long timestamp)
{
public static long removeTimezone(long timestamp) {
TimeZone tz = getTimezone();
return timestamp + tz.getOffset(timestamp);
}
public static void setFixedLocalTime(Long timestamp)
{
public static void setFixedLocalTime(Long timestamp) {
fixedLocalTime = timestamp;
}
public static void setFixedLocale(Locale locale)
{
public static void setFixedLocale(Locale locale) {
fixedLocale = locale;
}
private static Locale getLocale()
{
if(fixedLocale != null) return fixedLocale;
private static Locale getLocale() {
if (fixedLocale != null) return fixedLocale;
return Locale.getDefault();
}
public static Long truncate(TruncateField field, long timestamp)
{
public static Long truncate(TruncateField field, long timestamp) {
GregorianCalendar cal = DateUtils.getCalendar(timestamp);
switch (field)
{
switch (field) {
case MONTH:
cal.set(DAY_OF_MONTH, 1);
return cal.getTimeInMillis();
@ -240,8 +216,7 @@ public abstract class DateUtils
}
}
public enum TruncateField
{
public enum TruncateField {
MONTH, WEEK_NUMBER, YEAR, QUARTER
}
}
Loading…
Cancel
Save