After Width: | Height: | Size: 40 KiB |
@ -1,233 +1,233 @@
|
|||||||
package org.isoron.uhabits.views;
|
package org.isoron.uhabits.views;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
|
||||||
import org.isoron.helpers.DateHelper;
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
import org.isoron.uhabits.models.Habit;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Align;
|
import android.graphics.Paint.Align;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.Typeface;
|
|
||||||
import android.support.v4.view.MotionEventCompat;
|
import android.support.v4.view.MotionEventCompat;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
public class HabitHistoryView extends View
|
public class HabitHistoryView extends View
|
||||||
{
|
{
|
||||||
|
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
private int reps[];
|
private int reps[];
|
||||||
|
|
||||||
private Context context;
|
private Context context;
|
||||||
private Paint pSquareBg, pSquareFg, pTextHeader;
|
private Paint pSquareBg, pSquareFg, pTextHeader;
|
||||||
|
|
||||||
private int squareSize, squareSpacing;
|
private int squareSize, squareSpacing;
|
||||||
private int nColumns, offsetWeeks;
|
private int nColumns, offsetWeeks;
|
||||||
|
|
||||||
private int colorPrimary, colorPrimaryBrighter, grey;
|
private int colorPrimary, colorPrimaryBrighter, grey;
|
||||||
|
private Float prevX, prevY;
|
||||||
public HabitHistoryView(Context context, Habit habit, int squareSize)
|
|
||||||
{
|
public HabitHistoryView(Context context, Habit habit, int squareSize)
|
||||||
super(context);
|
{
|
||||||
this.habit = habit;
|
super(context);
|
||||||
this.context = context;
|
this.habit = habit;
|
||||||
this.squareSize = squareSize;
|
this.context = context;
|
||||||
|
this.squareSize = squareSize;
|
||||||
Typeface fontawesome = Typeface.createFromAsset(context.getAssets(),
|
|
||||||
"fontawesome-webfont.ttf");
|
colorPrimary = habit.color;
|
||||||
|
colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f);
|
||||||
colorPrimary = habit.color;
|
grey = Color.rgb(230, 230, 230);
|
||||||
colorPrimaryBrighter = ColorHelper.mixColors(colorPrimary, Color.WHITE, 0.5f);
|
squareSpacing = 2;
|
||||||
grey = Color.rgb(230, 230, 230);
|
|
||||||
squareSpacing = 2;
|
pTextHeader = new Paint();
|
||||||
|
pTextHeader.setColor(Color.LTGRAY);
|
||||||
pTextHeader = new Paint();
|
pTextHeader.setTextAlign(Align.LEFT);
|
||||||
pTextHeader.setColor(Color.LTGRAY);
|
pTextHeader.setTextSize(squareSize * 0.5f);
|
||||||
pTextHeader.setTextAlign(Align.LEFT);
|
pTextHeader.setAntiAlias(true);
|
||||||
pTextHeader.setTextSize(squareSize * 0.5f);
|
|
||||||
pTextHeader.setAntiAlias(true);
|
pSquareBg = new Paint();
|
||||||
|
pSquareBg.setColor(habit.color);
|
||||||
pSquareBg = new Paint();
|
|
||||||
pSquareBg.setColor(habit.color);
|
pSquareFg = new Paint();
|
||||||
|
pSquareFg.setColor(Color.WHITE);
|
||||||
pSquareFg = new Paint();
|
pSquareFg.setAntiAlias(true);
|
||||||
pSquareFg.setColor(Color.WHITE);
|
pSquareFg.setTextSize(squareSize * 0.5f);
|
||||||
pSquareFg.setAntiAlias(true);
|
pSquareFg.setTextAlign(Align.CENTER);
|
||||||
// pSquareFg.setTypeface(fontawesome);
|
}
|
||||||
pSquareFg.setTextSize(squareSize * 0.5f);
|
|
||||||
pSquareFg.setTextAlign(Align.CENTER);
|
@Override
|
||||||
}
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
|
{
|
||||||
@Override
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
setMeasuredDimension(getMeasuredWidth(), 8 * squareSize);
|
||||||
{
|
}
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
setMeasuredDimension(getMeasuredWidth(), 8 * squareSize);
|
@Override
|
||||||
}
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
|
{
|
||||||
@Override
|
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
|
||||||
{
|
|
||||||
nColumns = (w / squareSize) - 1;
|
nColumns = (w / squareSize) - 1;
|
||||||
fetchReps();
|
fetchReps();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchReps()
|
private void fetchReps()
|
||||||
{
|
{
|
||||||
Calendar currentDate = new GregorianCalendar();
|
Calendar currentDate = new GregorianCalendar();
|
||||||
currentDate.add(Calendar.DAY_OF_YEAR, -offsetWeeks * 7);
|
currentDate.add(Calendar.DAY_OF_YEAR, -offsetWeeks * 7);
|
||||||
int dayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK) % 7;
|
int dayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK) % 7;
|
||||||
|
|
||||||
long dateTo = DateHelper.getStartOfToday();
|
long dateTo = DateHelper.getStartOfToday();
|
||||||
for (int i = 0; i < 7 - dayOfWeek; i++)
|
for (int i = 0; i < 7 - dayOfWeek; i++)
|
||||||
dateTo += DateHelper.millisecondsInOneDay;
|
dateTo += DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
for (int i = 0; i < offsetWeeks * 7; i++)
|
for (int i = 0; i < offsetWeeks * 7; i++)
|
||||||
dateTo -= DateHelper.millisecondsInOneDay;
|
dateTo -= DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
long dateFrom = dateTo;
|
long dateFrom = dateTo;
|
||||||
for (int i = 0; i < nColumns * 7; i++)
|
for (int i = 0; i < nColumns * 7; i++)
|
||||||
dateFrom -= DateHelper.millisecondsInOneDay;
|
dateFrom -= DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
reps = habit.getReps(dateFrom, dateTo);
|
reps = habit.getReps(dateFrom, dateTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas)
|
protected void onDraw(Canvas canvas)
|
||||||
{
|
{
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
|
|
||||||
Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing);
|
Rect square = new Rect(0, 0, squareSize - squareSpacing, squareSize - squareSpacing);
|
||||||
|
|
||||||
Calendar currentDate = new GregorianCalendar();
|
Calendar currentDate = new GregorianCalendar();
|
||||||
currentDate.add(Calendar.DAY_OF_YEAR, -(offsetWeeks-1) * 7);
|
currentDate.add(Calendar.DAY_OF_YEAR, - (offsetWeeks - 1) * 7);
|
||||||
|
|
||||||
int nDays = nColumns * 7;
|
int nDays = nColumns * 7;
|
||||||
int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7;
|
int todayWeekday = new GregorianCalendar().get(Calendar.DAY_OF_WEEK) % 7;
|
||||||
|
|
||||||
currentDate.add(Calendar.DAY_OF_YEAR, -nDays);
|
currentDate.add(Calendar.DAY_OF_YEAR, -nDays);
|
||||||
|
currentDate.add(Calendar.DAY_OF_YEAR, -todayWeekday);
|
||||||
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
|
||||||
SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
|
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
||||||
|
SimpleDateFormat dfYear = new SimpleDateFormat("yyyy");
|
||||||
String previousMonth = "";
|
|
||||||
String previousYear = "";
|
String previousMonth = "";
|
||||||
|
String previousYear = "";
|
||||||
int colors[] = { grey, colorPrimaryBrighter, colorPrimary };
|
|
||||||
String markers[] = { context.getString(R.string.fa_times),
|
int colors[] = {grey, colorPrimaryBrighter, colorPrimary};
|
||||||
context.getString(R.string.fa_check), context.getString(R.string.fa_check) };
|
String markers[] =
|
||||||
|
{context.getString(R.string.fa_times), context.getString(R.string.fa_check),
|
||||||
float squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
|
context.getString(R.string.fa_check)};
|
||||||
float headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
|
|
||||||
boolean justPrintedYear = false;
|
float squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
|
||||||
|
float headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
|
||||||
int k = nDays;
|
boolean justPrintedYear = false;
|
||||||
for (int i = 0; i < nColumns; i++)
|
|
||||||
{
|
int k = nDays;
|
||||||
String month = dfMonth.format(currentDate.getTime());
|
for (int i = 0; i < nColumns; i++)
|
||||||
String year = dfYear.format(currentDate.getTime());
|
{
|
||||||
|
String month = dfMonth.format(currentDate.getTime());
|
||||||
if(!month.equals(previousMonth))
|
String year = dfYear.format(currentDate.getTime());
|
||||||
{
|
|
||||||
int offset = 0;
|
if (!month.equals(previousMonth))
|
||||||
if(justPrintedYear)
|
{
|
||||||
offset += squareSize;
|
int offset = 0;
|
||||||
|
if (justPrintedYear) offset += squareSize;
|
||||||
canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset,
|
|
||||||
pTextHeader);
|
canvas.drawText(month, square.left + offset, square.bottom - headerTextOffset,
|
||||||
previousMonth = month;
|
pTextHeader);
|
||||||
justPrintedYear = false;
|
previousMonth = month;
|
||||||
}
|
justPrintedYear = false;
|
||||||
else if(!year.equals(previousYear))
|
} else if (!year.equals(previousYear))
|
||||||
{
|
{
|
||||||
canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader);
|
canvas.drawText(year, square.left, square.bottom - headerTextOffset, pTextHeader);
|
||||||
previousYear = year;
|
previousYear = year;
|
||||||
justPrintedYear = true;
|
justPrintedYear = true;
|
||||||
}
|
} else
|
||||||
else
|
{
|
||||||
{
|
justPrintedYear = false;
|
||||||
justPrintedYear = false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
square.offset(0, squareSize);
|
||||||
square.offset(0, squareSize);
|
|
||||||
|
for (int j = 0; j < 7; j++)
|
||||||
for (int j = 0; j < 7; j++)
|
{
|
||||||
{
|
if (!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday))
|
||||||
if(!(i == nColumns - 1 && offsetWeeks == 0 && j > todayWeekday))
|
{
|
||||||
{
|
pSquareBg.setColor(colors[reps[k]]);
|
||||||
pSquareBg.setColor(colors[reps[k]]);
|
canvas.drawRect(square, pSquareBg);
|
||||||
canvas.drawRect(square, pSquareBg);
|
canvas.drawText(Integer.toString(currentDate.get(Calendar.DAY_OF_MONTH)),
|
||||||
// canvas.drawText(markers[reps[k]], square.centerX(), square.centerY()
|
square.centerX(), square.centerY() + squareTextOffset, pSquareFg);
|
||||||
// + squareTextOffset, pSquareFg);
|
}
|
||||||
canvas.drawText(Integer.toString(currentDate.get(Calendar.DAY_OF_MONTH)),
|
|
||||||
square.centerX(), square.centerY() + squareTextOffset, pSquareFg);
|
currentDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||||
}
|
square.offset(0, squareSize);
|
||||||
|
k--;
|
||||||
currentDate.add(Calendar.DAY_OF_MONTH, 1);
|
}
|
||||||
square.offset(0, squareSize);
|
|
||||||
k--;
|
square.offset(squareSize, -8 * squareSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
square.offset(squareSize, -8 * squareSize);
|
String wdays[] = {"Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri"};
|
||||||
}
|
|
||||||
|
for (int i = 0; i < 7; i++)
|
||||||
String wdays[] = { "Sat", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri" };
|
{
|
||||||
|
square.offset(0, squareSize);
|
||||||
for (int i = 0; i < 7; i++)
|
canvas.drawText(wdays[i], square.left + headerTextOffset,
|
||||||
{
|
square.bottom - headerTextOffset, pTextHeader);
|
||||||
square.offset(0, squareSize);
|
}
|
||||||
canvas.drawText(wdays[i], square.left + headerTextOffset, square.bottom
|
}
|
||||||
- headerTextOffset, pTextHeader);
|
|
||||||
}
|
@Override
|
||||||
}
|
public boolean onTouchEvent(MotionEvent event)
|
||||||
|
{
|
||||||
private Float prevX, prevY;
|
int action = event.getAction();
|
||||||
|
|
||||||
@Override
|
int pointerIndex = MotionEventCompat.getActionIndex(event);
|
||||||
public boolean onTouchEvent(MotionEvent event)
|
final float x = MotionEventCompat.getX(event, pointerIndex);
|
||||||
{
|
final float y = MotionEventCompat.getY(event, pointerIndex);
|
||||||
int action = event.getAction();
|
|
||||||
|
if (action == MotionEvent.ACTION_DOWN)
|
||||||
int pointerIndex = MotionEventCompat.getActionIndex(event);
|
{
|
||||||
final float x = MotionEventCompat.getX(event, pointerIndex);
|
prevX = x;
|
||||||
final float y = MotionEventCompat.getY(event, pointerIndex);
|
prevY = y;
|
||||||
|
}
|
||||||
if(action == MotionEvent.ACTION_DOWN)
|
|
||||||
{
|
if (action == MotionEvent.ACTION_MOVE)
|
||||||
prevX = x;
|
{
|
||||||
prevY = y;
|
float dx = x - prevX;
|
||||||
}
|
float dy = y - prevY;
|
||||||
|
|
||||||
if(action == MotionEvent.ACTION_MOVE)
|
if (Math.abs(dy) > Math.abs(dx)) return false;
|
||||||
{
|
getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
float dx = x - prevX;
|
if(move(dx))
|
||||||
float dy = y - prevY;
|
{
|
||||||
|
prevX = x;
|
||||||
int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize);
|
prevY = y;
|
||||||
newOffsetWeeks = Math.max(0, newOffsetWeeks);
|
}
|
||||||
|
}
|
||||||
if(newOffsetWeeks != offsetWeeks)
|
|
||||||
{
|
return true;
|
||||||
prevX = x;
|
}
|
||||||
prevY = y;
|
|
||||||
offsetWeeks = newOffsetWeeks;
|
private boolean move(float dx)
|
||||||
|
{
|
||||||
fetchReps();
|
int newOffsetWeeks = offsetWeeks + (int) (dx / squareSize);
|
||||||
invalidate();
|
newOffsetWeeks = Math.max(0, newOffsetWeeks);
|
||||||
}
|
|
||||||
|
if (newOffsetWeeks != offsetWeeks)
|
||||||
}
|
{
|
||||||
return true;
|
offsetWeeks = newOffsetWeeks;
|
||||||
}
|
fetchReps();
|
||||||
|
invalidate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,252 @@
|
|||||||
|
package org.isoron.uhabits.views;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.support.v4.view.MotionEventCompat;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
import org.isoron.uhabits.models.Score;
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class HabitScoreView extends View
|
||||||
|
{
|
||||||
|
public static final int BUCKET_SIZE = 7;
|
||||||
|
|
||||||
|
private final Paint pGrid;
|
||||||
|
private final float em;
|
||||||
|
private Habit habit;
|
||||||
|
private int columnWidth, columnHeight, nColumns;
|
||||||
|
|
||||||
|
private Paint pText, pGraph;
|
||||||
|
private int dataOffset;
|
||||||
|
|
||||||
|
private int barHeaderHeight;
|
||||||
|
|
||||||
|
private int[] colors;
|
||||||
|
private float prevX;
|
||||||
|
private float prevY;
|
||||||
|
private List<Score> scores;
|
||||||
|
|
||||||
|
public HabitScoreView(Context context, Habit habit, int columnWidth)
|
||||||
|
{
|
||||||
|
super(context);
|
||||||
|
this.habit = habit;
|
||||||
|
this.columnWidth = columnWidth;
|
||||||
|
|
||||||
|
pText = new Paint();
|
||||||
|
pText.setColor(Color.LTGRAY);
|
||||||
|
pText.setTextAlign(Paint.Align.LEFT);
|
||||||
|
pText.setTextSize(columnWidth * 0.5f);
|
||||||
|
pText.setAntiAlias(true);
|
||||||
|
|
||||||
|
pGraph = new Paint();
|
||||||
|
pGraph.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pGraph.setTextSize(columnWidth * 0.5f);
|
||||||
|
pGraph.setAntiAlias(true);
|
||||||
|
pGraph.setStrokeWidth(columnWidth * 0.1f);
|
||||||
|
|
||||||
|
pGrid = new Paint();
|
||||||
|
pGrid.setColor(Color.LTGRAY);
|
||||||
|
pGrid.setAntiAlias(true);
|
||||||
|
pGrid.setStrokeWidth(columnWidth * 0.05f);
|
||||||
|
|
||||||
|
columnHeight = 8 * columnWidth;
|
||||||
|
barHeaderHeight = columnWidth;
|
||||||
|
em = pText.getFontSpacing();
|
||||||
|
|
||||||
|
colors = new int[4];
|
||||||
|
|
||||||
|
colors[0] = Color.rgb(230, 230, 230);
|
||||||
|
colors[3] = habit.color;
|
||||||
|
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
||||||
|
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchScores()
|
||||||
|
{
|
||||||
|
|
||||||
|
long toTimestamp = DateHelper.getStartOfToday();
|
||||||
|
for (int i = 0; i < dataOffset * BUCKET_SIZE; i++)
|
||||||
|
toTimestamp -= DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
|
long fromTimestamp = toTimestamp;
|
||||||
|
for (int i = 0; i < nColumns * BUCKET_SIZE; i++)
|
||||||
|
fromTimestamp -= DateHelper.millisecondsInOneDay;
|
||||||
|
|
||||||
|
scores = habit.getScores(fromTimestamp, toTimestamp, BUCKET_SIZE * DateHelper.millisecondsInOneDay,
|
||||||
|
toTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||||
|
{
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
setMeasuredDimension(getMeasuredWidth(), columnHeight + 2 * barHeaderHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||||
|
{
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
nColumns = w / columnWidth;
|
||||||
|
fetchScores();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
float lineHeight = pText.getFontSpacing();
|
||||||
|
float barHeaderOffset = lineHeight * 0.4f;
|
||||||
|
|
||||||
|
RectF rGrid = new RectF(0, 0, nColumns * columnWidth, columnHeight);
|
||||||
|
rGrid.offset(0, barHeaderHeight);
|
||||||
|
drawGrid(canvas, rGrid);
|
||||||
|
|
||||||
|
SimpleDateFormat dfMonth = new SimpleDateFormat("MMM");
|
||||||
|
SimpleDateFormat dfDay = new SimpleDateFormat("d");
|
||||||
|
|
||||||
|
String previousMonth = "";
|
||||||
|
|
||||||
|
pGraph.setColor(habit.color);
|
||||||
|
RectF prevR = null;
|
||||||
|
|
||||||
|
for (int offset = nColumns - scores.size(); offset < nColumns; offset++)
|
||||||
|
{
|
||||||
|
Score score = scores.get(offset - nColumns + scores.size());
|
||||||
|
String month = dfMonth.format(score.timestamp);
|
||||||
|
String day = dfDay.format(score.timestamp);
|
||||||
|
|
||||||
|
long s = score.score;
|
||||||
|
double sRelative = ((double) s) / Habit.MAX_SCORE;
|
||||||
|
|
||||||
|
int height = (int) (columnHeight * sRelative);
|
||||||
|
|
||||||
|
RectF r = new RectF(0, 0, columnWidth, columnWidth);
|
||||||
|
r.offset(offset * columnWidth,
|
||||||
|
barHeaderHeight + columnHeight - height - columnWidth / 2);
|
||||||
|
|
||||||
|
if (prevR != null)
|
||||||
|
{
|
||||||
|
drawLine(canvas, prevR, r);
|
||||||
|
drawMarker(canvas, prevR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset == nColumns - 1) drawMarker(canvas, r);
|
||||||
|
|
||||||
|
prevR = r;
|
||||||
|
|
||||||
|
r = new RectF(0, 0, columnWidth, columnHeight);
|
||||||
|
r.offset(offset * columnWidth, barHeaderHeight);
|
||||||
|
if (!month.equals(previousMonth))
|
||||||
|
{
|
||||||
|
canvas.drawText(month, r.centerX(), r.bottom + lineHeight * 1.2f, pText);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
canvas.drawText(day, r.centerX(), r.bottom + lineHeight * 1.2f, pText);
|
||||||
|
}
|
||||||
|
|
||||||
|
previousMonth = month;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawGrid(Canvas canvas, RectF rGrid)
|
||||||
|
{
|
||||||
|
// pGrid.setColor(Color.rgb(230, 230, 230));
|
||||||
|
// pGrid.setStyle(Paint.Style.STROKE);
|
||||||
|
// canvas.drawRect(rGrid, pGrid);
|
||||||
|
|
||||||
|
int nRows = 5;
|
||||||
|
float rowHeight = rGrid.height() / nRows;
|
||||||
|
|
||||||
|
pGrid.setColor(Color.rgb(240, 240, 240));
|
||||||
|
for (int i = 0; i < nRows; i++)
|
||||||
|
{
|
||||||
|
canvas.drawText(String.format("%d%%", (100 - i * 100 / nRows)), rGrid.left + 0.5f * em,
|
||||||
|
rGrid.top + 1f * em, pText);
|
||||||
|
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
|
||||||
|
rGrid.offset(0, rowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawLine(Canvas canvas, RectF rectFrom, RectF rectTo)
|
||||||
|
{
|
||||||
|
pGraph.setColor(habit.color);
|
||||||
|
canvas.drawLine(rectFrom.centerX(), rectFrom.centerY(), rectTo.centerX(), rectTo.centerY(),
|
||||||
|
pGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawMarker(Canvas canvas, RectF rect)
|
||||||
|
{
|
||||||
|
rect.inset(columnWidth * 0.15f, columnWidth * 0.15f);
|
||||||
|
pGraph.setColor(Color.WHITE);
|
||||||
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
|
pGraph.setColor(habit.color);
|
||||||
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
|
pGraph.setColor(Color.WHITE);
|
||||||
|
canvas.drawOval(rect, pGraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event)
|
||||||
|
{
|
||||||
|
int action = event.getAction();
|
||||||
|
|
||||||
|
int pointerIndex = MotionEventCompat.getActionIndex(event);
|
||||||
|
final float x = MotionEventCompat.getX(event, pointerIndex);
|
||||||
|
final float y = MotionEventCompat.getY(event, pointerIndex);
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_DOWN)
|
||||||
|
{
|
||||||
|
prevX = x;
|
||||||
|
prevY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == MotionEvent.ACTION_MOVE)
|
||||||
|
{
|
||||||
|
float dx = x - prevX;
|
||||||
|
float dy = y - prevY;
|
||||||
|
|
||||||
|
if (Math.abs(dy) > Math.abs(dx)) return false;
|
||||||
|
getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
if (move(dx))
|
||||||
|
{
|
||||||
|
prevX = x;
|
||||||
|
prevY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean move(float dx)
|
||||||
|
{
|
||||||
|
int newDataOffset = dataOffset + (int) (dx / columnWidth);
|
||||||
|
newDataOffset = Math.max(0, newDataOffset);
|
||||||
|
|
||||||
|
if (newDataOffset != dataOffset)
|
||||||
|
{
|
||||||
|
dataOffset = newDataOffset;
|
||||||
|
fetchScores();
|
||||||
|
invalidate();
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
}
|
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 344 B |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 11 KiB |
@ -1,20 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="habitsListHeaderStyle">
|
<style name="habitsListHeaderStyle" parent="habitsListHeaderBasicStyle">
|
||||||
<item name="android:layout_width">match_parent</item>
|
|
||||||
<item name="android:layout_height">wrap_content</item>
|
|
||||||
<item name="android:layout_alignParentTop">true</item>
|
|
||||||
<item name="android:background">#f0f0f0</item>
|
<item name="android:background">#f0f0f0</item>
|
||||||
<item name="android:elevation">2dp</item>
|
<item name="android:elevation">2dp</item>
|
||||||
<item name="android:paddingRight">4dp</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="habitsListCheckStyle">
|
<style name="habitsListCheckStyle" parent="habitsListCheckBasicStyle">
|
||||||
<item name="android:focusable">false</item>
|
|
||||||
<item name="android:minHeight">42dp</item>
|
|
||||||
<item name="android:minWidth">42dp</item>
|
|
||||||
<item name="android:gravity">center</item>
|
|
||||||
<item name="android:background">@drawable/ripple_background</item>
|
<item name="android:background">@drawable/ripple_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="DragSortListView">
|
||||||
|
<attr name="collapsed_height" format="dimension"/>
|
||||||
|
<attr name="drag_scroll_start" format="float"/>
|
||||||
|
<attr name="max_drag_scroll_speed" format="float"/>
|
||||||
|
<attr name="float_background_color" format="color"/>
|
||||||
|
<attr name="remove_mode">
|
||||||
|
<enum name="clickRemove" value="0"/>
|
||||||
|
<enum name="flingRemove" value="1"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="track_drag_sort" format="boolean"/>
|
||||||
|
<attr name="float_alpha" format="float"/>
|
||||||
|
<attr name="slide_shuffle_speed" format="float"/>
|
||||||
|
<attr name="remove_animation_duration" format="integer"/>
|
||||||
|
<attr name="drop_animation_duration" format="integer"/>
|
||||||
|
<attr name="drag_enabled" format="boolean"/>
|
||||||
|
<attr name="sort_enabled" format="boolean"/>
|
||||||
|
<attr name="remove_enabled" format="boolean"/>
|
||||||
|
<attr name="drag_start_mode">
|
||||||
|
<enum name="onDown" value="0"/>
|
||||||
|
<enum name="onMove" value="1"/>
|
||||||
|
<enum name="onLongPress" value="2"/>
|
||||||
|
</attr>
|
||||||
|
<attr name="drag_handle_id" format="integer"/>
|
||||||
|
<attr name="fling_handle_id" format="integer"/>
|
||||||
|
<attr name="click_remove_id" format="integer"/>
|
||||||
|
<attr name="use_default_controller" format="boolean"/>
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
@ -1,54 +1,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
<dimen name="small_square_size">20dp</dimen>
|
||||||
<dimen name="square_size">20dp</dimen>
|
<dimen name="check_square_size">42dp</dimen>
|
||||||
|
|
||||||
<!-- Color picker -->
|
|
||||||
<dimen name="color_swatch_large">64dip</dimen>
|
|
||||||
<dimen name="color_swatch_small">48dip</dimen>
|
|
||||||
<dimen name="color_swatch_margins_large">8dip</dimen>
|
|
||||||
<dimen name="color_swatch_margins_small">4dip</dimen>
|
|
||||||
|
|
||||||
<!-- Date and time picker -->
|
|
||||||
<item name="circle_radius_multiplier" format="float" type="string">0.82</item>
|
|
||||||
<item name="circle_radius_multiplier_24HourMode" format="float" type="string">0.85</item>
|
|
||||||
<item name="selection_radius_multiplier" format="float" type="string">0.16</item>
|
|
||||||
<item name="ampm_circle_radius_multiplier" format="float" type="string">0.19</item>
|
|
||||||
<item name="numbers_radius_multiplier_normal" format="float" type="string">0.81</item>
|
|
||||||
<item name="numbers_radius_multiplier_inner" format="float" type="string">0.60</item>
|
|
||||||
<item name="numbers_radius_multiplier_outer" format="float" type="string">0.83</item>
|
|
||||||
<item name="text_size_multiplier_normal" format="float" type="string">0.17</item>
|
|
||||||
<item name="text_size_multiplier_inner" format="float" type="string">0.14</item>
|
|
||||||
<item name="text_size_multiplier_outer" format="float" type="string">0.11</item>
|
|
||||||
<dimen name="time_label_size">60sp</dimen>
|
|
||||||
<dimen name="extra_time_label_margin">-30dp</dimen>
|
|
||||||
<dimen name="ampm_label_size">16sp</dimen>
|
|
||||||
<dimen name="done_label_size">14sp</dimen>
|
|
||||||
<dimen name="ampm_left_padding">6dip</dimen>
|
|
||||||
<dimen name="separator_padding">4dip</dimen>
|
|
||||||
<dimen name="header_height">96dip</dimen>
|
|
||||||
<dimen name="footer_height">48dip</dimen>
|
|
||||||
<dimen name="minimum_margin_sides">48dip</dimen>
|
|
||||||
<dimen name="minimum_margin_top_bottom">24dip</dimen>
|
|
||||||
<dimen name="picker_dimen">270dip</dimen>
|
|
||||||
<dimen name="date_picker_component_width">270dp</dimen>
|
|
||||||
<dimen name="date_picker_header_height">30dp</dimen>
|
|
||||||
<dimen name="selected_calendar_layout_height">155dp</dimen>
|
|
||||||
<dimen name="date_picker_view_animator_height">270dp</dimen>
|
|
||||||
<dimen name="done_button_height">42dp</dimen>
|
|
||||||
<dimen name="month_list_item_header_height">50dp</dimen>
|
|
||||||
<dimen name="month_day_label_text_size">10sp</dimen>
|
|
||||||
<dimen name="day_number_select_circle_radius">16dp</dimen>
|
|
||||||
<dimen name="month_select_circle_radius">45dp</dimen>
|
|
||||||
<dimen name="selected_date_year_size">30dp</dimen>
|
|
||||||
<dimen name="selected_date_day_size">75dp</dimen>
|
|
||||||
<dimen name="selected_date_month_size">30dp</dimen>
|
|
||||||
<dimen name="date_picker_header_text_size">14dp</dimen>
|
|
||||||
<dimen name="month_label_size">16sp</dimen>
|
|
||||||
<dimen name="day_number_size">16sp</dimen>
|
|
||||||
<dimen name="year_label_height">64dp</dimen>
|
|
||||||
<dimen name="year_label_text_size">22dp</dimen>
|
|
||||||
</resources>
|
</resources>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="color_swatch_large">64dip</dimen>
|
||||||
|
<dimen name="color_swatch_small">48dip</dimen>
|
||||||
|
<dimen name="color_swatch_margins_large">8dip</dimen>
|
||||||
|
<dimen name="color_swatch_margins_small">4dip</dimen>
|
||||||
|
</resources>
|
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<item name="circle_radius_multiplier" format="float" type="string">0.82</item>
|
||||||
|
<item name="circle_radius_multiplier_24HourMode" format="float" type="string">0.85</item>
|
||||||
|
<item name="selection_radius_multiplier" format="float" type="string">0.16</item>
|
||||||
|
<item name="ampm_circle_radius_multiplier" format="float" type="string">0.19</item>
|
||||||
|
<item name="numbers_radius_multiplier_normal" format="float" type="string">0.81</item>
|
||||||
|
<item name="numbers_radius_multiplier_inner" format="float" type="string">0.60</item>
|
||||||
|
<item name="numbers_radius_multiplier_outer" format="float" type="string">0.83</item>
|
||||||
|
<item name="text_size_multiplier_normal" format="float" type="string">0.17</item>
|
||||||
|
<item name="text_size_multiplier_inner" format="float" type="string">0.14</item>
|
||||||
|
<item name="text_size_multiplier_outer" format="float" type="string">0.11</item>
|
||||||
|
|
||||||
|
<dimen name="time_label_size">60sp</dimen>
|
||||||
|
<dimen name="extra_time_label_margin">-30dp</dimen>
|
||||||
|
<dimen name="ampm_label_size">16sp</dimen>
|
||||||
|
<dimen name="done_label_size">14sp</dimen>
|
||||||
|
<dimen name="ampm_left_padding">6dip</dimen>
|
||||||
|
<dimen name="separator_padding">4dip</dimen>
|
||||||
|
<dimen name="header_height">96dip</dimen>
|
||||||
|
<dimen name="footer_height">48dip</dimen>
|
||||||
|
<dimen name="minimum_margin_sides">48dip</dimen>
|
||||||
|
<dimen name="minimum_margin_top_bottom">24dip</dimen>
|
||||||
|
<dimen name="picker_dimen">270dip</dimen>
|
||||||
|
<dimen name="date_picker_component_width">270dp</dimen>
|
||||||
|
<dimen name="date_picker_header_height">30dp</dimen>
|
||||||
|
<dimen name="selected_calendar_layout_height">155dp</dimen>
|
||||||
|
<dimen name="date_picker_view_animator_height">270dp</dimen>
|
||||||
|
<dimen name="done_button_height">42dp</dimen>
|
||||||
|
<dimen name="month_list_item_header_height">50dp</dimen>
|
||||||
|
<dimen name="month_day_label_text_size">10sp</dimen>
|
||||||
|
<dimen name="day_number_select_circle_radius">16dp</dimen>
|
||||||
|
<dimen name="month_select_circle_radius">45dp</dimen>
|
||||||
|
<dimen name="selected_date_year_size">30dp</dimen>
|
||||||
|
<dimen name="selected_date_day_size">75dp</dimen>
|
||||||
|
<dimen name="selected_date_month_size">30dp</dimen>
|
||||||
|
<dimen name="date_picker_header_text_size">14dp</dimen>
|
||||||
|
<dimen name="month_label_size">16sp</dimen>
|
||||||
|
<dimen name="day_number_size">16sp</dimen>
|
||||||
|
<dimen name="year_label_height">64dp</dimen>
|
||||||
|
<dimen name="year_label_text_size">22dp</dimen>
|
||||||
|
</resources>
|