Reformat and reorganize some code

pull/145/head
Alinson S. Xavier 9 years ago
parent 3d3d5b9b96
commit 6484b96e5a

@ -161,7 +161,7 @@ public class BaseSystem
Environment.getExternalStorageState());
}
private String getLogcat() throws IOException
public String getLogcat() throws IOException
{
int maxLineCount = 250;
StringBuilder builder = new StringBuilder();

@ -306,7 +306,7 @@ public class HabitCardListController implements DragSortListView.DropListener,
protected void notifyListener()
{
if (habitListener == null) return;
if(selectionListener == null) return;
if (activeMode == SELECTION_MODE)
selectionListener.onSelectionChange();

@ -68,8 +68,8 @@ public class CheckmarkButtonView extends FrameLayout
public void toggle()
{
value = (value == Checkmark.CHECKED_EXPLICITLY ? Checkmark.UNCHECKED :
Checkmark.CHECKED_EXPLICITLY);
// value = (value == Checkmark.CHECKED_EXPLICITLY ? Checkmark.UNCHECKED :
// Checkmark.CHECKED_EXPLICITLY);
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
postInvalidate();

@ -111,13 +111,6 @@ public class HabitCardListView extends DragSortListView
});
}
public void toggleShowArchived()
{
// showArchived = !showArchived;
// cache.setIncludeArchived(showArchived);
// cache.refreshAllHabits(true);
}
@Override
protected void onAttachedToWindow()
{

@ -33,7 +33,7 @@ import javax.inject.*;
/**
* Activity that allows the user to see more information about a single habit.
*
* <p>
* Shows all the metadata for the habit, in addition to several charts.
*/
public class ShowHabitActivity extends BaseActivity
@ -43,19 +43,9 @@ public class ShowHabitActivity extends BaseActivity
@Inject
HabitList habitList;
@Override
protected void onCreate(Bundle savedInstanceState)
public Habit getHabit()
{
super.onCreate(savedInstanceState);
HabitsApplication.getComponent().inject(this);
Uri data = getIntent().getData();
habit = habitList.getById(ContentUris.parseId(data));
setContentView(R.layout.show_habit_activity);
BaseScreen.setupActionBarColor(this, ColorUtils.getColor(this, habit.getColor()));
setupHabitActionBar();
return habit;
}
public void setupHabitActionBar()
@ -68,8 +58,19 @@ public class ShowHabitActivity extends BaseActivity
actionBar.setTitle(habit.getName());
}
public Habit getHabit()
@Override
protected void onCreate(Bundle savedInstanceState)
{
return habit;
super.onCreate(savedInstanceState);
HabitsApplication.getComponent().inject(this);
Uri data = getIntent().getData();
habit = habitList.getById(ContentUris.parseId(data));
setContentView(R.layout.show_habit_activity);
BaseScreen.setupActionBarColor(this,
ColorUtils.getColor(this, habit.getColor()));
setupHabitActionBar();
}
}

@ -195,16 +195,11 @@ public class ShowHabitFragment extends Fragment
public void onModelChange()
{
refreshData();
activity.runOnUiThread(new Runnable()
{
@Override
public void run()
{
activity.runOnUiThread(() -> {
helper.updateColors();
helper.updateMainHeader(getView());
helper.updateCardHeaders(getView());
if (activity != null) activity.setupHabitActionBar();
}
});
}

@ -19,16 +19,14 @@
package org.isoron.uhabits.ui.habits.show;
import android.content.res.Resources;
import android.view.View;
import android.widget.TextView;
import android.content.res.*;
import android.view.*;
import android.widget.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.ui.habits.show.views.RingView;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.utils.*;
public class ShowHabitHelper
{
@ -63,44 +61,33 @@ public class ShowHabitHelper
resources.getString(R.string.days));
}
void updateScore(View view)
void updateCardHeaders(View view)
{
if (fragment.habit == null) return;
if (view == null) return;
updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvOverview);
updateColor(view, R.id.tvStrength);
updateColor(view, R.id.tvStreaks);
updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel);
}
float todayPercentage = fragment.todayScore / Score.MAX_VALUE;
float monthDiff =
todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE);
float yearDiff =
todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
void updateColor(View view, int viewId)
{
if (fragment.habit == null || fragment.activity == null) return;
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
TextView textView = (TextView) view.findViewById(viewId);
int androidColor =
ColorUtils.getColor(fragment.getActivity(),
fragment.habit.getColor());
scoreRing.setColor(androidColor);
scoreRing.setPercentage(todayPercentage);
TextView scoreLabel = (TextView) view.findViewById(R.id.scoreLabel);
TextView monthDiffLabel =
(TextView) view.findViewById(R.id.monthDiffLabel);
TextView yearDiffLabel =
(TextView) view.findViewById(R.id.yearDiffLabel);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
String minus = "\u2212";
monthDiffLabel.setText(
String.format("%s%.0f%%", (monthDiff >= 0 ? "+" : minus),
Math.abs(monthDiff) * 100));
yearDiffLabel.setText(
String.format("%s%.0f%%", (yearDiff >= 0 ? "+" : minus),
Math.abs(yearDiff) * 100));
ColorUtils.getColor(fragment.activity, fragment.habit.getColor());
textView.setTextColor(androidColor);
}
monthDiffLabel.setTextColor(
monthDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
yearDiffLabel.setTextColor(
yearDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
void updateColors()
{
fragment.activeColor = ColorUtils.getColor(fragment.getContext(),
fragment.habit.getColor());
fragment.inactiveColor =
InterfaceUtils.getStyledColor(fragment.getContext(),
R.attr.mediumContrastTextColor);
}
void updateMainHeader(View view)
@ -129,33 +116,42 @@ public class ShowHabitHelper
questionLabel.setVisibility(View.GONE);
}
void updateCardHeaders(View view)
{
updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvOverview);
updateColor(view, R.id.tvStrength);
updateColor(view, R.id.tvStreaks);
updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel);
}
void updateColor(View view, int viewId)
void updateScore(View view)
{
if (fragment.habit == null || fragment.activity == null) return;
if (fragment.habit == null) return;
if (view == null) return;
TextView textView = (TextView) view.findViewById(viewId);
int androidColor =
ColorUtils.getColor(fragment.activity, fragment.habit.getColor());
textView.setTextColor(androidColor);
}
float todayPercentage = fragment.todayScore / Score.MAX_VALUE;
float monthDiff =
todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE);
float yearDiff =
todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
void updateColors()
{
fragment.activeColor =
ColorUtils.getColor(fragment.getContext(),
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
int androidColor = ColorUtils.getColor(fragment.getActivity(),
fragment.habit.getColor());
fragment.inactiveColor =
InterfaceUtils.getStyledColor(fragment.getContext(),
R.attr.mediumContrastTextColor);
scoreRing.setColor(androidColor);
scoreRing.setPercentage(todayPercentage);
TextView scoreLabel = (TextView) view.findViewById(R.id.scoreLabel);
TextView monthDiffLabel =
(TextView) view.findViewById(R.id.monthDiffLabel);
TextView yearDiffLabel =
(TextView) view.findViewById(R.id.yearDiffLabel);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
String minus = "\u2212";
monthDiffLabel.setText(
String.format("%s%.0f%%", (monthDiff >= 0 ? "+" : minus),
Math.abs(monthDiff) * 100));
yearDiffLabel.setText(
String.format("%s%.0f%%", (yearDiff >= 0 ? "+" : minus),
Math.abs(yearDiff) * 100));
monthDiffLabel.setTextColor(
monthDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
yearDiffLabel.setTextColor(
yearDiff >= 0 ? fragment.activeColor : fragment.inactiveColor);
}
}

@ -19,48 +19,53 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Random;
public class HabitFrequencyView extends ScrollableDataView implements HabitDataView, ModelObservable.Listener
import android.content.*;
import android.graphics.*;
import android.util.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class HabitFrequencyView extends ScrollableDataView
implements HabitDataView, ModelObservable.Listener
{
private Paint pGrid;
private float em;
private Habit habit;
private SimpleDateFormat dfMonth;
private SimpleDateFormat dfYear;
private Paint pText, pGraph;
private RectF rect, prevRect;
private int baseSize;
private int paddingTop;
private float columnWidth;
private int columnHeight;
private int nColumns;
private int textColor;
private int gridColor;
private int[] colors;
private int primaryColor;
private boolean isBackgroundTransparent;
private HashMap<Long, Integer[]> frequency;
@ -79,40 +84,34 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
init();
}
public void setHabit(Habit habit)
@Override
public void onModelChange()
{
this.habit = habit;
createColors();
refreshData();
}
private void init()
public void refreshData()
{
createPaints();
if (isInEditMode()) generateRandomData();
else if (habit != null)
{
frequency = habit.getRepetitions().getWeekdayFrequency();
createColors();
}
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
rect = new RectF();
prevRect = new RectF();
postInvalidate();
}
private void createColors()
{
if(habit != null)
public void setHabit(Habit habit)
{
this.primaryColor = ColorUtils.getColor(getContext(),
habit.getColor());
this.habit = habit;
createColors();
}
textColor = InterfaceUtils.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(), R.attr.lowContrastTextColor);
colors = new int[4];
colors[0] = gridColor;
colors[3] = primaryColor;
colors[1] = ColorUtils.mixColors(colors[0], colors[3], 0.66f);
colors[2] = ColorUtils.mixColors(colors[0], colors[3], 0.33f);
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
}
protected void createPaints()
@ -129,78 +128,27 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
{
if(height < 9) height = 200;
baseSize = height / 8;
setScrollerBucketSize(baseSize);
pText.setTextSize(baseSize * 0.4f);
pGraph.setTextSize(baseSize * 0.4f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(baseSize * 0.05f);
em = pText.getFontSpacing();
columnWidth = baseSize;
columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f);
columnHeight = 8 * baseSize;
nColumns = (int) (width / columnWidth);
paddingTop = 0;
}
private float getMaxMonthWidth()
{
float maxMonthWidth = 0;
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
for(int i = 0; i < 12; i++)
protected void onAttachedToWindow()
{
day.set(Calendar.MONTH, i);
float monthWidth = pText.measureText(dfMonth.format(day.getTime()));
maxMonthWidth = Math.max(maxMonthWidth, monthWidth);
}
return maxMonthWidth;
}
public void refreshData()
super.onAttachedToWindow();
new BaseTask()
{
if(isInEditMode()) generateRandomData();
else if(habit != null)
@Override
protected void doInBackground()
{
frequency = habit.getRepetitions().getWeekdayFrequency();
createColors();
refreshData();
}
postInvalidate();
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
private void generateRandomData()
{
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
date.set(Calendar.DAY_OF_MONTH, 1);
Random rand = new Random();
frequency.clear();
for(int i = 0; i < 40; i++)
@Override
protected void onDetachedFromWindow()
{
Integer values[] = new Integer[7];
for(int j = 0; j < 7; j++)
values[j] = rand.nextInt(5);
frequency.put(date.getTimeInMillis(), values);
date.add(Calendar.MONTH, -1);
}
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
@ -233,6 +181,59 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
if (height < 9) height = 200;
baseSize = height / 8;
setScrollerBucketSize(baseSize);
pText.setTextSize(baseSize * 0.4f);
pGraph.setTextSize(baseSize * 0.4f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(baseSize * 0.05f);
em = pText.getFontSpacing();
columnWidth = baseSize;
columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f);
columnHeight = 8 * baseSize;
nColumns = (int) (width / columnWidth);
paddingTop = 0;
}
private void createColors()
{
if (habit != null)
{
this.primaryColor =
ColorUtils.getColor(getContext(), habit.getColor());
}
textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.lowContrastTextColor);
colors = new int[4];
colors[0] = gridColor;
colors[3] = primaryColor;
colors[1] = ColorUtils.mixColors(colors[0], colors[3], 0.66f);
colors[2] = ColorUtils.mixColors(colors[0], colors[3], 0.33f);
}
private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date)
{
Integer values[] = frequency.get(date.getTimeInMillis());
@ -246,8 +247,7 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
rect.offset(prevRect.left, prevRect.top + baseSize * j);
int i = DateUtils.javaWeekdayToLoopWeekday(localeWeekdayList[j]);
if(values != null)
drawMarker(canvas, rect, values[i]);
if (values != null) drawMarker(canvas, rect, values[i]);
rect.offset(0, rowHeight);
}
@ -259,19 +259,12 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
{
Date time = date.getTime();
canvas.drawText(dfMonth.format(time), rect.centerX(), rect.centerY() - 0.1f * em, pText);
canvas.drawText(dfMonth.format(time), rect.centerX(),
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);
}
private void drawMarker(Canvas canvas, RectF rect, Integer value)
{
float padding = rect.height() * 0.2f;
float radius = (rect.height() - 2 * padding) / 2.0f / 4.0f * Math.min(value, 4);
pGraph.setColor(colors[Math.min(3, Math.max(0, value - 1))]);
canvas.drawCircle(rect.centerX(), rect.centerY(), radius, pGraph);
canvas.drawText(dfYear.format(time), rect.centerX(),
rect.centerY() + 0.9f * em, pText);
}
private void drawGrid(Canvas canvas, RectF rGrid)
@ -283,12 +276,14 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
pText.setColor(textColor);
pGrid.setColor(gridColor);
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT)) {
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
{
canvas.drawText(day, rGrid.right - columnWidth,
rGrid.top + rowHeight / 2 + 0.25f * em, pText);
pGrid.setStrokeWidth(1f);
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top,
pGrid);
rGrid.offset(0, rowHeight);
}
@ -296,40 +291,58 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
private void drawMarker(Canvas canvas, RectF rect, Integer value)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
}
float padding = rect.height() * 0.2f;
float radius =
(rect.height() - 2 * padding) / 2.0f / 4.0f * Math.min(value, 4);
pGraph.setColor(colors[Math.min(3, Math.max(0, value - 1))]);
canvas.drawCircle(rect.centerX(), rect.centerY(), radius, pGraph);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
private void generateRandomData()
{
@Override
protected void doInBackground()
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
date.set(Calendar.DAY_OF_MONTH, 1);
Random rand = new Random();
frequency.clear();
for (int i = 0; i < 40; i++)
{
refreshData();
Integer values[] = new Integer[7];
for (int j = 0; j < 7; j++)
values[j] = rand.nextInt(5);
frequency.put(date.getTimeInMillis(), values);
date.add(Calendar.MONTH, -1);
}
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
private float getMaxMonthWidth()
{
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
float maxMonthWidth = 0;
GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
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);
}
@Override
public void onModelChange()
return maxMonthWidth;
}
private void init()
{
refreshData();
createPaints();
createColors();
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
rect = new RectF();
prevRect = new RectF();
}
}

@ -19,61 +19,76 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.tasks.ToggleRepetitionTask;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Random;
public class HabitHistoryView extends ScrollableDataView implements HabitDataView,
ToggleRepetitionTask.Listener, ModelObservable.Listener
import android.content.*;
import android.graphics.*;
import android.graphics.Paint.*;
import android.util.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class HabitHistoryView extends ScrollableDataView implements
HabitDataView,
ToggleRepetitionTask.Listener,
ModelObservable.Listener
{
private Habit habit;
private int[] checkmarks;
private Paint pSquareBg, pSquareFg, pTextHeader;
private float squareSpacing;
private float squareTextOffset;
private float headerTextOffset;
private float columnWidth;
private float columnHeight;
private int nColumns;
private SimpleDateFormat dfMonth;
private SimpleDateFormat dfYear;
private Calendar baseDate;
private int nDays;
/** 0-based-position of today in the column */
/**
* 0-based-position of today in the column
*/
private int todayPositionInColumn;
private int colors[];
private RectF baseLocation;
private int primaryColor;
private boolean isBackgroundTransparent;
private int textColor;
private int reverseTextColor;
private boolean isEditable;
private String previousMonth;
private String previousYear;
private float headerOverflow = 0;
public HabitHistoryView(Context context)
{
super(context);
@ -86,115 +101,89 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
init();
}
public void setHabit(Habit habit)
@Override
public void onLongPress(MotionEvent e)
{
this.habit = habit;
createColors();
onSingleTapUp(e);
}
private void init()
@Override
public void onModelChange()
{
createColors();
createPaints();
isEditable = false;
checkmarks = new int[0];
primaryColor = ColorUtils.getColor(getContext(), 7);
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
baseLocation = new RectF();
refreshData();
}
private void updateDate()
@Override
public boolean onSingleTapUp(MotionEvent e)
{
baseDate = DateUtils.getStartOfTodayCalendar();
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
if (!isEditable) return false;
nDays = (nColumns - 1) * 7;
int realWeekday = DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
todayPositionInColumn = (7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);
int pointerId = e.getPointerId(0);
float x = e.getX(pointerId);
float y = e.getY(pointerId);
final Long timestamp = positionToTimestamp(x, y);
if (timestamp == null) return false;
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
task.setListener(this);
task.execute();
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
public void onToggleRepetitionFinished()
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
protected void onPostExecute(Void aVoid)
{
if(height < 8) height = 200;
float baseSize = height / 8.0f;
setScrollerBucketSize((int) baseSize);
squareSpacing = InterfaceUtils.dpToPixels(getContext(), 1.0f);
float maxTextSize = getResources().getDimension(R.dimen.regularTextSize);
float textSize = height * 0.06f;
textSize = Math.min(textSize, maxTextSize);
pSquareFg.setTextSize(textSize);
pTextHeader.setTextSize(textSize);
squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
float rightLabelWidth = getWeekdayLabelWidth() + headerTextOffset;
float horizontalPadding = getPaddingRight() + getPaddingLeft();
columnWidth = baseSize;
columnHeight = 8 * baseSize;
nColumns = (int)((width - rightLabelWidth - horizontalPadding) / baseSize) + 1;
updateDate();
invalidate();
super.onPostExecute(null);
}
}.execute();
}
private float getWeekdayLabelWidth()
@Override
public void refreshData()
{
float width = 0;
for(String w : DateUtils.getLocaleDayNames(Calendar.SHORT))
width = Math.max(width, pSquareFg.measureText(w));
if (isInEditMode()) generateRandomData();
else
{
if (habit == null) return;
checkmarks = habit.getCheckmarks().getAllValues();
createColors();
}
return width;
updateDate();
postInvalidate();
}
private void createColors()
public void setHabit(Habit habit)
{
if(habit != null)
this.primaryColor = ColorUtils.getColor(getContext(),
habit.getColor());
if(isBackgroundTransparent)
primaryColor = ColorUtils.setMinValue(primaryColor, 0.75f);
int red = Color.red(primaryColor);
int green = Color.green(primaryColor);
int blue = Color.blue(primaryColor);
this.habit = habit;
createColors();
}
if(isBackgroundTransparent)
public void setIsBackgroundTransparent(boolean 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;
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
}
else
public void setIsEditable(boolean isEditable)
{
colors = new int[3];
colors[0] = InterfaceUtils.getStyledColor(getContext(), R.attr.lowContrastTextColor);
colors[1] = Color.argb(127, red, green, blue);
colors[2] = primaryColor;
textColor = InterfaceUtils.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
reverseTextColor = InterfaceUtils.getStyledColor(getContext(), R.attr.highContrastReverseTextColor);
}
this.isEditable = isEditable;
}
protected void createPaints()
@ -210,49 +199,37 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
pSquareFg.setTextAlign(Align.CENTER);
}
public void refreshData()
@Override
protected void onAttachedToWindow()
{
if(isInEditMode())
generateRandomData();
else
super.onAttachedToWindow();
new BaseTask()
{
if(habit == null) return;
checkmarks = habit.getCheckmarks().getAllValues();
createColors();
@Override
protected void doInBackground()
{
refreshData();
}
updateDate();
postInvalidate();
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
private void generateRandomData()
{
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++)
@Override
protected void onDetachedFromWindow()
{
int count = 0;
for (int j = 0; j < 7; j++)
if(checkmarks[i + j] != 0)
count++;
if(count >= 3) checkmarks[i] = Math.max(checkmarks[i], 1);
}
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
private String previousMonth;
private String previousYear;
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
baseLocation.set(0, 0, columnWidth - squareSpacing, columnWidth - squareSpacing);
baseLocation.set(0, 0, columnWidth - squareSpacing,
columnWidth - squareSpacing);
baseLocation.offset(getPaddingLeft(), getPaddingTop());
headerOverflow = 0;
@ -272,35 +249,80 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
drawAxis(canvas, baseLocation);
}
private void drawColumn(Canvas canvas, RectF location, GregorianCalendar date, int column)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
drawColumnHeader(canvas, location, date);
location.offset(0, columnWidth);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
for (int j = 0; j < 7; j++)
{
if (!(column == nColumns - 2 && getDataOffset() == 0 && j > todayPositionInColumn))
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
int checkmarkOffset = getDataOffset() * 7 + nDays - 7 * (column + 1) +
todayPositionInColumn - j;
drawSquare(canvas, location, date, checkmarkOffset);
}
if (height < 8) height = 200;
float baseSize = height / 8.0f;
setScrollerBucketSize((int) baseSize);
date.add(Calendar.DAY_OF_MONTH, 1);
location.offset(0, columnWidth);
}
squareSpacing = InterfaceUtils.dpToPixels(getContext(), 1.0f);
float maxTextSize =
getResources().getDimension(R.dimen.regularTextSize);
float textSize = height * 0.06f;
textSize = Math.min(textSize, maxTextSize);
pSquareFg.setTextSize(textSize);
pTextHeader.setTextSize(textSize);
squareTextOffset = pSquareFg.getFontSpacing() * 0.4f;
headerTextOffset = pTextHeader.getFontSpacing() * 0.3f;
float rightLabelWidth = getWeekdayLabelWidth() + headerTextOffset;
float horizontalPadding = getPaddingRight() + getPaddingLeft();
columnWidth = baseSize;
columnHeight = 8 * baseSize;
nColumns =
(int) ((width - rightLabelWidth - horizontalPadding) / baseSize) +
1;
updateDate();
}
private void drawSquare(Canvas canvas, RectF location, GregorianCalendar date,
int checkmarkOffset)
private void createColors()
{
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
else pSquareBg.setColor(colors[checkmarks[checkmarkOffset]]);
if (habit != null) this.primaryColor =
ColorUtils.getColor(getContext(), habit.getColor());
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);
if (isBackgroundTransparent)
primaryColor = ColorUtils.setMinValue(primaryColor, 0.75f);
int red = Color.red(primaryColor);
int green = Color.green(primaryColor);
int blue = Color.blue(primaryColor);
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
{
colors = new int[3];
colors[0] = InterfaceUtils.getStyledColor(getContext(),
R.attr.lowContrastTextColor);
colors[1] = Color.argb(127, red, green, blue);
colors[2] = primaryColor;
textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor);
reverseTextColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.highContrastReverseTextColor);
}
}
private void drawAxis(Canvas canvas, RectF location)
@ -315,59 +337,107 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
}
}
private float headerOverflow = 0;
private void drawColumn(Canvas canvas,
RectF location,
GregorianCalendar date,
int column)
{
drawColumnHeader(canvas, location, date);
location.offset(0, columnWidth);
for (int j = 0; j < 7; j++)
{
if (!(column == nColumns - 2 && getDataOffset() == 0 &&
j > todayPositionInColumn))
{
int checkmarkOffset =
getDataOffset() * 7 + nDays - 7 * (column + 1) +
todayPositionInColumn - j;
drawSquare(canvas, location, date, checkmarkOffset);
}
date.add(Calendar.DAY_OF_MONTH, 1);
location.offset(0, columnWidth);
}
}
private void drawColumnHeader(Canvas canvas, RectF location, GregorianCalendar date)
private void drawColumnHeader(Canvas canvas,
RectF location,
GregorianCalendar date)
{
String month = dfMonth.format(date.getTime());
String year = dfYear.format(date.getTime());
String text = null;
if (!month.equals(previousMonth))
text = previousMonth = month;
else if(!year.equals(previousYear))
text = previousYear = year;
if (!month.equals(previousMonth)) text = previousMonth = month;
else if (!year.equals(previousYear)) text = previousYear = year;
if (text != null)
{
canvas.drawText(text, location.left + headerOverflow, location.bottom - headerTextOffset, pTextHeader);
headerOverflow += pTextHeader.measureText(text) + columnWidth * 0.2f;
canvas.drawText(text, location.left + headerOverflow,
location.bottom - headerTextOffset, pTextHeader);
headerOverflow +=
pTextHeader.measureText(text) + columnWidth * 0.2f;
}
headerOverflow = Math.max(0, headerOverflow - columnWidth);
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
private void drawSquare(Canvas canvas,
RectF location,
GregorianCalendar date,
int checkmarkOffset)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
else pSquareBg.setColor(colors[checkmarks[checkmarkOffset]]);
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);
}
@Override
public void onLongPress(MotionEvent e)
private void generateRandomData()
{
onSingleTapUp(e);
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++)
{
int count = 0;
for (int j = 0; j < 7; j++)
if (checkmarks[i + j] != 0) count++;
if (count >= 3) checkmarks[i] = Math.max(checkmarks[i], 1);
}
}
@Override
public boolean onSingleTapUp(MotionEvent e)
private float getWeekdayLabelWidth()
{
if(!isEditable) return false;
float width = 0;
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
for (String w : DateUtils.getLocaleDayNames(Calendar.SHORT))
width = Math.max(width, pSquareFg.measureText(w));
int pointerId = e.getPointerId(0);
float x = e.getX(pointerId);
float y = e.getY(pointerId);
return width;
}
final Long timestamp = positionToTimestamp(x, y);
if(timestamp == null) return false;
private void init()
{
createColors();
createPaints();
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
task.setListener(this);
task.execute();
isEditable = false;
checkmarks = new int[0];
primaryColor = ColorUtils.getColor(getContext(), 7);
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
return true;
baseLocation = new RectF();
}
private Long positionToTimestamp(float x, float y)
@ -382,64 +452,24 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
Calendar date = (Calendar) baseDate.clone();
date.add(Calendar.DAY_OF_YEAR, offset);
if(DateUtils.getStartOfDay(date.getTimeInMillis()) > DateUtils.getStartOfToday())
return null;
if (DateUtils.getStartOfDay(date.getTimeInMillis()) >
DateUtils.getStartOfToday()) return null;
return date.getTimeInMillis();
}
public void setIsEditable(boolean isEditable)
{
this.isEditable = isEditable;
}
@Override
public void onToggleRepetitionFinished()
{
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
@Override
protected void onPostExecute(Void aVoid)
{
invalidate();
super.onPostExecute(null);
}
}.execute();
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
private void updateDate()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
baseDate = DateUtils.getStartOfTodayCalendar();
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
@Override
protected void onDetachedFromWindow()
{
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
nDays = (nColumns - 1) * 7;
int realWeekday =
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
todayPositionInColumn =
(7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
@Override
public void onModelChange()
{
refreshData();
baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);
}
}

@ -19,34 +19,18 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import android.content.*;
import android.graphics.*;
import android.support.annotation.*;
import android.util.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class HabitScoreView extends ScrollableDataView
implements HabitDataView, ModelObservable.Listener
@ -138,10 +122,8 @@ public class HabitScoreView extends ScrollableDataView
else
{
if (habit == null) return;
if (bucketSize == 1)
scores = habit.getScores().getAll();
else
scores = habit.getScores().groupBy(getTruncateField());
if (bucketSize == 1) scores = habit.getScores().getAll();
else scores = habit.getScores().groupBy(getTruncateField());
createColors();
}
@ -168,19 +150,6 @@ public class HabitScoreView extends ScrollableDataView
requestLayout();
}
private void createColors()
{
if (habit != null) this.primaryColor =
ColorUtils.getColor(getContext(), habit.getColor());
textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.lowContrastTextColor);
backgroundColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.cardBackgroundColor);
}
protected void createPaints()
{
pText = new Paint();
@ -194,6 +163,158 @@ public class HabitScoreView extends ScrollableDataView
pGrid.setAntiAlias(true);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getScores().getObservable().addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getScores().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Canvas activeCanvas;
if (isTransparencyEnabled)
{
if (drawingCache == null) initCache(getWidth(), getHeight());
activeCanvas = cacheCanvas;
drawingCache.eraseColor(Color.TRANSPARENT);
}
else
{
activeCanvas = canvas;
}
if (habit == null || scores == null) return;
rect.set(0, 0, nColumns * columnWidth, columnHeight);
rect.offset(0, paddingTop);
drawGrid(activeCanvas, rect);
pText.setColor(textColor);
pGraph.setColor(primaryColor);
prevRect.setEmpty();
previousMonthText = "";
previousYearText = "";
skipYear = 0;
long currentDate = DateUtils.getStartOfToday();
for (int k = 0; k < nColumns + getDataOffset() - 1; k++)
currentDate -= bucketSize * DateUtils.millisecondsInOneDay;
for (int k = 0; k < nColumns; k++)
{
int score = 0;
int offset = nColumns - k - 1 + getDataOffset();
if (offset < scores.size()) score = scores.get(offset).getValue();
double relativeScore = ((double) score) / Score.MAX_VALUE;
int height = (int) (columnHeight * relativeScore);
rect.set(0, 0, baseSize, baseSize);
rect.offset(k * columnWidth + (columnWidth - baseSize) / 2,
paddingTop + columnHeight - height - baseSize / 2);
if (!prevRect.isEmpty())
{
drawLine(activeCanvas, prevRect, rect);
drawMarker(activeCanvas, prevRect);
}
if (k == nColumns - 1) drawMarker(activeCanvas, rect);
prevRect.set(rect);
rect.set(0, 0, columnWidth, columnHeight);
rect.offset(k * columnWidth, paddingTop);
drawFooter(activeCanvas, rect, currentDate);
currentDate += bucketSize * DateUtils.millisecondsInOneDay;
}
if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
if (height < 9) height = 200;
float maxTextSize = getResources().getDimension(R.dimen.tinyTextSize);
float textSize = height * 0.06f;
pText.setTextSize(Math.min(textSize, maxTextSize));
em = pText.getFontSpacing();
footerHeight = (int) (3 * em);
paddingTop = (int) (em);
baseSize = (height - footerHeight - paddingTop) / 8;
setScrollerBucketSize(baseSize);
columnWidth = baseSize;
columnWidth = Math.max(columnWidth, getMaxDayWidth() * 1.5f);
columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f);
nColumns = (int) (width / columnWidth);
columnWidth = (float) width / nColumns;
columnHeight = 8 * baseSize;
float minStrokeWidth = InterfaceUtils.dpToPixels(getContext(), 1);
pGraph.setTextSize(baseSize * 0.5f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(Math.min(minStrokeWidth, baseSize * 0.05f));
if (isTransparencyEnabled) initCache(width, height);
}
private void createColors()
{
if (habit != null) this.primaryColor =
ColorUtils.getColor(getContext(), habit.getColor());
textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.lowContrastTextColor);
backgroundColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.cardBackgroundColor);
}
private void drawFooter(Canvas canvas, RectF rect, long currentDate)
{
String yearText = dfYear.format(currentDate);
@ -393,145 +514,6 @@ public class HabitScoreView extends ScrollableDataView
cacheCanvas = new Canvas(drawingCache);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getScores().getObservable().addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getScores().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
Canvas activeCanvas;
if (isTransparencyEnabled)
{
if (drawingCache == null) initCache(getWidth(), getHeight());
activeCanvas = cacheCanvas;
drawingCache.eraseColor(Color.TRANSPARENT);
}
else
{
activeCanvas = canvas;
}
if (habit == null || scores == null) return;
rect.set(0, 0, nColumns * columnWidth, columnHeight);
rect.offset(0, paddingTop);
drawGrid(activeCanvas, rect);
pText.setColor(textColor);
pGraph.setColor(primaryColor);
prevRect.setEmpty();
previousMonthText = "";
previousYearText = "";
skipYear = 0;
long currentDate = DateUtils.getStartOfToday();
for (int k = 0; k < nColumns + getDataOffset() - 1; k++)
currentDate -= bucketSize * DateUtils.millisecondsInOneDay;
for (int k = 0; k < nColumns; k++)
{
int score = 0;
int offset = nColumns - k - 1 + getDataOffset();
if (offset < scores.size()) score = scores.get(offset).getValue();
double relativeScore = ((double) score) / Score.MAX_VALUE;
int height = (int) (columnHeight * relativeScore);
rect.set(0, 0, baseSize, baseSize);
rect.offset(k * columnWidth + (columnWidth - baseSize) / 2,
paddingTop + columnHeight - height - baseSize / 2);
if (!prevRect.isEmpty())
{
drawLine(activeCanvas, prevRect, rect);
drawMarker(activeCanvas, prevRect);
}
if (k == nColumns - 1) drawMarker(activeCanvas, rect);
prevRect.set(rect);
rect.set(0, 0, columnWidth, columnHeight);
rect.offset(k * columnWidth, paddingTop);
drawFooter(activeCanvas, rect, currentDate);
currentDate += bucketSize * DateUtils.millisecondsInOneDay;
}
if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
if (height < 9) height = 200;
float maxTextSize = getResources().getDimension(R.dimen.tinyTextSize);
float textSize = height * 0.06f;
pText.setTextSize(Math.min(textSize, maxTextSize));
em = pText.getFontSpacing();
footerHeight = (int) (3 * em);
paddingTop = (int) (em);
baseSize = (height - footerHeight - paddingTop) / 8;
setScrollerBucketSize(baseSize);
columnWidth = baseSize;
columnWidth = Math.max(columnWidth, getMaxDayWidth() * 1.5f);
columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f);
nColumns = (int) (width / columnWidth);
columnWidth = (float) width / nColumns;
columnHeight = 8 * baseSize;
float minStrokeWidth = InterfaceUtils.dpToPixels(getContext(), 1);
pGraph.setTextSize(baseSize * 0.5f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(Math.min(minStrokeWidth, baseSize * 0.05f));
if (isTransparencyEnabled) initCache(width, height);
}
private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color)
{
if (isTransparencyEnabled) p.setXfermode(mode);

@ -19,27 +19,18 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.models.Streak;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.text.DateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import android.content.*;
import android.graphics.*;
import android.util.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class HabitStreakView extends View
implements HabitDataView, ModelObservable.Listener
@ -124,6 +115,82 @@ public class HabitStreakView extends View
createColors();
}
protected void createPaints()
{
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getStreaks().getObservable().addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getStreaks().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (streaks.size() == 0) return;
rect.set(0, 0, width, baseSize);
for (Streak s : streaks)
{
drawRow(canvas, s, rect);
rect.offset(0, baseSize);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
maxStreakCount = height / baseSize;
this.width = width;
float minTextSize = getResources().getDimension(R.dimen.tinyTextSize);
float maxTextSize =
getResources().getDimension(R.dimen.regularTextSize);
float textSize = baseSize * 0.5f;
paint.setTextSize(
Math.max(Math.min(textSize, maxTextSize), minTextSize));
em = paint.getFontSpacing();
textMargin = 0.5f * em;
updateMaxMin();
}
private void createColors()
{
if (habit != null) this.primaryColor =
@ -145,13 +212,6 @@ public class HabitStreakView extends View
R.attr.highContrastReverseTextColor);
}
protected void createPaints()
{
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
}
private void drawRow(Canvas canvas, Streak streak, RectF rect)
{
if (maxLength == 0) return;
@ -208,75 +268,6 @@ public class HabitStreakView extends View
baseSize = getResources().getDimensionPixelSize(R.dimen.baseSize);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getStreaks().getObservable().addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getStreaks().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (streaks.size() == 0) return;
rect.set(0, 0, width, baseSize);
for (Streak s : streaks)
{
drawRow(canvas, s, rect);
rect.offset(0, baseSize);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int width,
int height,
int oldWidth,
int oldHeight)
{
maxStreakCount = height / baseSize;
this.width = width;
float minTextSize = getResources().getDimension(R.dimen.tinyTextSize);
float maxTextSize =
getResources().getDimension(R.dimen.regularTextSize);
float textSize = baseSize * 0.5f;
paint.setTextSize(
Math.max(Math.min(textSize, maxTextSize), minTextSize));
em = paint.getFontSpacing();
textMargin = 0.5f * em;
updateMaxMin();
}
private int percentageToColor(float percentage)
{
if (percentage >= 1.0f) return colors[3];

@ -19,22 +19,17 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import org.isoron.uhabits.R;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
import android.content.*;
import android.graphics.*;
import android.support.annotation.*;
import android.text.*;
import android.util.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
public class RingView extends View
{
@ -42,24 +37,34 @@ public class RingView extends View
new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
private int color;
private float precision;
private float percentage;
private int diameter;
private float thickness;
private RectF rect;
private TextPaint pRing;
private Integer backgroundColor;
private Integer inactiveColor;
private float em;
private String text;
private float textSize;
private boolean enableFontAwesome;
@Nullable
private Bitmap drawingCache;
private Canvas cacheCanvas;
private boolean isTransparencyEnabled;
@ -71,54 +76,56 @@ public class RingView extends View
percentage = 0.0f;
precision = 0.01f;
color = ColorUtils.getAndroidTestColor(0);
thickness = InterfaceUtils.dpToPixels(getContext(), 2);
thickness = dpToPixels(getContext(), 2);
text = "";
textSize = context.getResources().getDimension(R.dimen.smallTextSize);
init();
}
public RingView(Context context, AttributeSet attrs)
public RingView(Context ctx, AttributeSet attrs)
{
super(context, attrs);
super(ctx, attrs);
percentage = InterfaceUtils.getFloatAttribute(context, attrs, "percentage", 0);
precision = InterfaceUtils.getFloatAttribute(context, attrs, "precision", 0.01f);
percentage = getFloatAttribute(ctx, attrs, "percentage", 0);
precision = getFloatAttribute(ctx, attrs, "precision", 0.01f);
color = InterfaceUtils.getColorAttribute(context, attrs, "color", 0);
backgroundColor = InterfaceUtils.getColorAttribute(context, attrs, "backgroundColor", null);
inactiveColor = InterfaceUtils.getColorAttribute(context, attrs, "inactiveColor", null);
color = getColorAttribute(ctx, attrs, "color", 0);
backgroundColor =
getColorAttribute(ctx, attrs, "backgroundColor", null);
inactiveColor = getColorAttribute(ctx, attrs, "inactiveColor", null);
thickness = InterfaceUtils.getFloatAttribute(context, attrs, "thickness", 0);
thickness = InterfaceUtils.dpToPixels(context, thickness);
thickness = getFloatAttribute(ctx, attrs, "thickness", 0);
thickness = dpToPixels(ctx, thickness);
float defaultTextSize = context.getResources().getDimension(R.dimen.smallTextSize);
textSize = InterfaceUtils.getFloatAttribute(context, attrs, "textSize", defaultTextSize);
textSize = InterfaceUtils.spToPixels(context, textSize);
float defaultTextSize =
ctx.getResources().getDimension(R.dimen.smallTextSize);
textSize = getFloatAttribute(ctx, attrs, "textSize", defaultTextSize);
textSize = spToPixels(ctx, textSize);
text = getAttribute(ctx, attrs, "text", "");
text = InterfaceUtils.getAttribute(context, attrs, "text", "");
enableFontAwesome = InterfaceUtils.getBooleanAttribute(context, attrs, "enableFontAwesome", false);
enableFontAwesome =
getBooleanAttribute(ctx, attrs, "enableFontAwesome", false);
init();
}
public void setColor(int color)
@Override
public void setBackgroundColor(int backgroundColor)
{
this.color = color;
this.backgroundColor = backgroundColor;
postInvalidate();
}
public void setTextSize(float textSize)
public void setColor(int color)
{
this.textSize = textSize;
this.color = color;
postInvalidate();
}
@Override
public void setBackgroundColor(int backgroundColor)
public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
{
this.backgroundColor = backgroundColor;
postInvalidate();
this.isTransparencyEnabled = isTransparencyEnabled;
}
public void setPercentage(float percentage)
@ -133,64 +140,21 @@ public class RingView extends View
postInvalidate();
}
public void setThickness(float thickness)
{
this.thickness = thickness;
postInvalidate();
}
public void setText(String text)
{
this.text = text;
postInvalidate();
}
private void init()
{
pRing = new TextPaint();
pRing.setAntiAlias(true);
pRing.setColor(color);
pRing.setTextAlign(Paint.Align.CENTER);
if(backgroundColor == null)
backgroundColor = InterfaceUtils.getStyledColor(getContext(), R.attr.cardBackgroundColor);
if(inactiveColor == null)
inactiveColor = InterfaceUtils.getStyledColor(getContext(), R.attr.highContrastTextColor);
inactiveColor = ColorUtils.setAlpha(inactiveColor, 0.1f);
rect = new RectF();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
diameter = Math.min(height, width);
pRing.setTextSize(textSize);
em = pRing.measureText("M");
setMeasuredDimension(diameter, diameter);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
public void setTextSize(float textSize)
{
super.onSizeChanged(w, h, oldw, oldh);
if(isTransparencyEnabled) reallocateCache();
this.textSize = textSize;
}
private void reallocateCache()
public void setThickness(float thickness)
{
if (drawingCache != null) drawingCache.recycle();
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(drawingCache);
this.thickness = thickness;
postInvalidate();
}
@Override
@ -222,10 +186,8 @@ public class RingView extends View
if (thickness > 0)
{
if(isTransparencyEnabled)
pRing.setXfermode(XFERMODE_CLEAR);
else
pRing.setColor(backgroundColor);
if (isTransparencyEnabled) pRing.setXfermode(XFERMODE_CLEAR);
else pRing.setColor(backgroundColor);
rect.inset(thickness, thickness);
activeCanvas.drawArc(rect, 0, 360, true, pRing);
@ -233,16 +195,63 @@ public class RingView extends View
pRing.setColor(color);
pRing.setTextSize(textSize);
if(enableFontAwesome) pRing.setTypeface(InterfaceUtils.getFontAwesome(getContext()));
activeCanvas.drawText(text, rect.centerX(), rect.centerY() + 0.4f * em, pRing);
if (enableFontAwesome)
pRing.setTypeface(getFontAwesome(getContext()));
activeCanvas.drawText(text, rect.centerX(),
rect.centerY() + 0.4f * em, pRing);
}
if(activeCanvas != canvas)
canvas.drawBitmap(drawingCache, 0, 0, null);
if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null);
}
public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
this.isTransparencyEnabled = isTransparencyEnabled;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
diameter = Math.min(height, width);
pRing.setTextSize(textSize);
em = pRing.measureText("M");
setMeasuredDimension(diameter, diameter);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
if (isTransparencyEnabled) reallocateCache();
}
private void init()
{
pRing = new TextPaint();
pRing.setAntiAlias(true);
pRing.setColor(color);
pRing.setTextAlign(Paint.Align.CENTER);
if (backgroundColor == null) backgroundColor =
InterfaceUtils.getStyledColor(getContext(),
R.attr.cardBackgroundColor);
if (inactiveColor == null) inactiveColor =
InterfaceUtils.getStyledColor(getContext(),
R.attr.highContrastTextColor);
inactiveColor = ColorUtils.setAlpha(inactiveColor, 0.1f);
rect = new RectF();
}
private void reallocateCache()
{
if (drawingCache != null) drawingCache.recycle();
drawingCache =
Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(drawingCache);
}
}

@ -19,14 +19,11 @@
package org.isoron.uhabits.ui.habits.show.views;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.widget.Scroller;
import android.animation.*;
import android.content.*;
import android.util.*;
import android.view.*;
import android.widget.*;
public abstract class ScrollableDataView extends View
implements GestureDetector.OnGestureListener,

@ -20,6 +20,9 @@
package org.isoron.uhabits.ui.settings;
import android.os.*;
import android.support.annotation.*;
import android.support.v4.app.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.ui.*;

@ -31,7 +31,6 @@ import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.HabitWidgetView;
import org.isoron.uhabits.ui.habits.show.views.RingView;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;

@ -28,7 +28,6 @@ import android.widget.TextView;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.HabitWidgetView;
public class GraphWidgetView extends HabitWidgetView implements HabitDataView
{

@ -17,27 +17,26 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.utils.InterfaceUtils;
import java.util.Arrays;
public abstract class HabitWidgetView extends FrameLayout implements HabitDataView
package org.isoron.uhabits.widgets.views;
import android.content.*;
import android.graphics.*;
import android.graphics.drawable.*;
import android.graphics.drawable.shapes.*;
import android.support.annotation.*;
import android.util.*;
import android.view.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
public abstract class HabitWidgetView extends FrameLayout
implements HabitDataView
{
@Nullable
protected InsetDrawable background;
@ -47,12 +46,8 @@ public abstract class HabitWidgetView extends FrameLayout implements HabitDataV
@Nullable
protected Habit habit;
protected ViewGroup frame;
public void setShadowAlpha(int shadowAlpha)
{
this.shadowAlpha = shadowAlpha;
}
protected ViewGroup frame;
private int shadowAlpha;
@ -68,21 +63,28 @@ public abstract class HabitWidgetView extends FrameLayout implements HabitDataV
init();
}
private void init()
@Override
public void setHabit(@NonNull Habit habit)
{
inflate(getContext(), getInnerLayoutId(), this);
shadowAlpha = (int) (255 * InterfaceUtils.getStyledFloat(getContext(), R.attr.widgetShadowAlpha));
rebuildBackground();
this.habit = habit;
}
protected abstract @NonNull Integer getInnerLayoutId();
public void setShadowAlpha(int shadowAlpha)
{
this.shadowAlpha = shadowAlpha;
}
protected abstract
@NonNull
Integer getInnerLayoutId();
protected void rebuildBackground()
{
Context context = getContext();
int backgroundAlpha =
(int) (255 * InterfaceUtils.getStyledFloat(context, R.attr.widgetBackgroundAlpha));
int backgroundAlpha = (int) (255 *
InterfaceUtils.getStyledFloat(context,
R.attr.widgetBackgroundAlpha));
int shadowRadius = (int) InterfaceUtils.dpToPixels(context, 2);
int shadowOffset = (int) InterfaceUtils.dpToPixels(context, 1);
@ -98,20 +100,25 @@ public abstract class HabitWidgetView extends FrameLayout implements HabitDataV
int insetLeftTop = Math.max(shadowRadius - shadowOffset, 0);
int insetRightBottom = shadowRadius + shadowOffset;
background = new InsetDrawable(innerDrawable, insetLeftTop, insetLeftTop, insetRightBottom,
insetRightBottom);
background =
new InsetDrawable(innerDrawable, insetLeftTop, insetLeftTop,
insetRightBottom, insetRightBottom);
backgroundPaint = innerDrawable.getPaint();
backgroundPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, shadowColor);
backgroundPaint.setColor(InterfaceUtils.getStyledColor(context, R.attr.cardBackgroundColor));
backgroundPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset,
shadowColor);
backgroundPaint.setColor(
InterfaceUtils.getStyledColor(context, R.attr.cardBackgroundColor));
backgroundPaint.setAlpha(backgroundAlpha);
frame = (ViewGroup) findViewById(R.id.frame);
if (frame != null) frame.setBackgroundDrawable(background);
}
@Override
public void setHabit(@NonNull Habit habit)
private void init()
{
this.habit = habit;
inflate(getContext(), getInnerLayoutId(), this);
shadowAlpha = (int) (255 * InterfaceUtils.getStyledFloat(getContext(),
R.attr.widgetShadowAlpha));
rebuildBackground();
}
}
Loading…
Cancel
Save