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

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

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

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