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()); Environment.getExternalStorageState());
} }
private String getLogcat() throws IOException public String getLogcat() throws IOException
{ {
int maxLineCount = 250; int maxLineCount = 250;
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();

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

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

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

@ -33,7 +33,7 @@ import javax.inject.*;
/** /**
* Activity that allows the user to see more information about a single habit. * 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. * Shows all the metadata for the habit, in addition to several charts.
*/ */
public class ShowHabitActivity extends BaseActivity public class ShowHabitActivity extends BaseActivity
@ -43,19 +43,9 @@ public class ShowHabitActivity extends BaseActivity
@Inject @Inject
HabitList habitList; HabitList habitList;
@Override public Habit getHabit()
protected void onCreate(Bundle savedInstanceState)
{ {
super.onCreate(savedInstanceState); return habit;
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();
} }
public void setupHabitActionBar() public void setupHabitActionBar()
@ -68,8 +58,19 @@ public class ShowHabitActivity extends BaseActivity
actionBar.setTitle(habit.getName()); 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() public void onModelChange()
{ {
refreshData(); refreshData();
activity.runOnUiThread(new Runnable() activity.runOnUiThread(() -> {
{
@Override
public void run()
{
helper.updateColors(); helper.updateColors();
helper.updateMainHeader(getView()); helper.updateMainHeader(getView());
helper.updateCardHeaders(getView()); helper.updateCardHeaders(getView());
if (activity != null) activity.setupHabitActionBar(); if (activity != null) activity.setupHabitActionBar();
}
}); });
} }

@ -19,16 +19,14 @@
package org.isoron.uhabits.ui.habits.show; package org.isoron.uhabits.ui.habits.show;
import android.content.res.Resources; import android.content.res.*;
import android.view.View; import android.view.*;
import android.widget.TextView; import android.widget.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Score; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.RingView; import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
public class ShowHabitHelper public class ShowHabitHelper
{ {
@ -63,44 +61,33 @@ public class ShowHabitHelper
resources.getString(R.string.days)); resources.getString(R.string.days));
} }
void updateScore(View view) void updateCardHeaders(View view)
{ {
if (fragment.habit == null) return; updateColor(view, R.id.tvHistory);
if (view == null) return; 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; void updateColor(View view, int viewId)
float monthDiff = {
todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE); if (fragment.habit == null || fragment.activity == null) return;
float yearDiff =
todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing); TextView textView = (TextView) view.findViewById(viewId);
int androidColor = int androidColor =
ColorUtils.getColor(fragment.getActivity(), ColorUtils.getColor(fragment.activity, fragment.habit.getColor());
fragment.habit.getColor()); textView.setTextColor(androidColor);
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( void updateColors()
monthDiff >= 0 ? fragment.activeColor : fragment.inactiveColor); {
yearDiffLabel.setTextColor( fragment.activeColor = ColorUtils.getColor(fragment.getContext(),
yearDiff >= 0 ? fragment.activeColor : fragment.inactiveColor); fragment.habit.getColor());
fragment.inactiveColor =
InterfaceUtils.getStyledColor(fragment.getContext(),
R.attr.mediumContrastTextColor);
} }
void updateMainHeader(View view) void updateMainHeader(View view)
@ -129,33 +116,42 @@ public class ShowHabitHelper
questionLabel.setVisibility(View.GONE); questionLabel.setVisibility(View.GONE);
} }
void updateCardHeaders(View view) void updateScore(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)
{ {
if (fragment.habit == null || fragment.activity == null) return; if (fragment.habit == null) return;
if (view == null) return;
TextView textView = (TextView) view.findViewById(viewId); float todayPercentage = fragment.todayScore / Score.MAX_VALUE;
int androidColor = float monthDiff =
ColorUtils.getColor(fragment.activity, fragment.habit.getColor()); todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE);
textView.setTextColor(androidColor); float yearDiff =
} todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
void updateColors() RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
{ int androidColor = ColorUtils.getColor(fragment.getActivity(),
fragment.activeColor =
ColorUtils.getColor(fragment.getContext(),
fragment.habit.getColor()); fragment.habit.getColor());
fragment.inactiveColor = scoreRing.setColor(androidColor);
InterfaceUtils.getStyledColor(fragment.getContext(), scoreRing.setPercentage(todayPercentage);
R.attr.mediumContrastTextColor);
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; package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context; import android.content.*;
import android.graphics.Canvas; import android.graphics.*;
import android.graphics.Paint; import android.util.*;
import android.graphics.RectF;
import android.util.AttributeSet; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.models.ModelObservable;
import org.isoron.uhabits.tasks.BaseTask; import java.text.*;
import org.isoron.uhabits.utils.ColorUtils; import java.util.*;
import org.isoron.uhabits.utils.DateUtils;
import org.isoron.uhabits.utils.InterfaceUtils; public class HabitFrequencyView extends ScrollableDataView
implements HabitDataView, ModelObservable.Listener
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
{ {
private Paint pGrid; private Paint pGrid;
private float em; private float em;
private Habit habit; private Habit habit;
private SimpleDateFormat dfMonth; private SimpleDateFormat dfMonth;
private SimpleDateFormat dfYear; private SimpleDateFormat dfYear;
private Paint pText, pGraph; private Paint pText, pGraph;
private RectF rect, prevRect; private RectF rect, prevRect;
private int baseSize; private int baseSize;
private int paddingTop; private int paddingTop;
private float columnWidth; private float columnWidth;
private int columnHeight; private int columnHeight;
private int nColumns; private int nColumns;
private int textColor; private int textColor;
private int gridColor; private int gridColor;
private int[] colors; private int[] colors;
private int primaryColor; private int primaryColor;
private boolean isBackgroundTransparent; private boolean isBackgroundTransparent;
private HashMap<Long, Integer[]> frequency; private HashMap<Long, Integer[]> frequency;
@ -79,40 +84,34 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
init(); init();
} }
public void setHabit(Habit habit) @Override
public void onModelChange()
{ {
this.habit = habit; refreshData();
createColors();
} }
private void init() public void refreshData()
{ {
createPaints(); if (isInEditMode()) generateRandomData();
else if (habit != null)
{
frequency = habit.getRepetitions().getWeekdayFrequency();
createColors(); createColors();
}
dfMonth = DateUtils.getDateFormat("MMM"); postInvalidate();
dfYear = DateUtils.getDateFormat("yyyy");
rect = new RectF();
prevRect = new RectF();
} }
private void createColors() public void setHabit(Habit habit)
{
if(habit != null)
{ {
this.primaryColor = ColorUtils.getColor(getContext(), this.habit = habit;
habit.getColor()); createColors();
} }
textColor = InterfaceUtils.getStyledColor(getContext(), R.attr.mediumContrastTextColor); public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
gridColor = InterfaceUtils.getStyledColor(getContext(), R.attr.lowContrastTextColor); {
this.isBackgroundTransparent = isBackgroundTransparent;
colors = new int[4]; createColors();
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);
} }
protected void createPaints() protected void createPaints()
@ -129,78 +128,27 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
} }
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) protected void onAttachedToWindow()
{
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++)
{ {
day.set(Calendar.MONTH, i); super.onAttachedToWindow();
float monthWidth = pText.measureText(dfMonth.format(day.getTime())); new BaseTask()
maxMonthWidth = Math.max(maxMonthWidth, monthWidth);
}
return maxMonthWidth;
}
public void refreshData()
{ {
if(isInEditMode()) generateRandomData(); @Override
else if(habit != null) protected void doInBackground()
{ {
frequency = habit.getRepetitions().getWeekdayFrequency(); refreshData();
createColors();
} }
}.execute();
postInvalidate(); habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
} }
private void generateRandomData() @Override
{ protected void onDetachedFromWindow()
GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
date.set(Calendar.DAY_OF_MONTH, 1);
Random rand = new Random();
frequency.clear();
for(int i = 0; i < 40; i++)
{ {
Integer values[] = new Integer[7]; habit.getCheckmarks().observable.removeListener(this);
for(int j = 0; j < 7; j++) habit.getObservable().removeListener(this);
values[j] = rand.nextInt(5); super.onDetachedFromWindow();
frequency.put(date.getTimeInMillis(), values);
date.add(Calendar.MONTH, -1);
}
} }
@Override @Override
@ -223,7 +171,7 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
currentDate.set(Calendar.DAY_OF_MONTH, 1); currentDate.set(Calendar.DAY_OF_MONTH, 1);
currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset()); currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset());
for(int i = 0; i < nColumns - 1; i++) for (int i = 0; i < nColumns - 1; i++)
{ {
rect.set(0, 0, columnWidth, columnHeight); rect.set(0, 0, columnWidth, columnHeight);
rect.offset(i * columnWidth, 0); rect.offset(i * columnWidth, 0);
@ -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) private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date)
{ {
Integer values[] = frequency.get(date.getTimeInMillis()); 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); rect.offset(prevRect.left, prevRect.top + baseSize * j);
int i = DateUtils.javaWeekdayToLoopWeekday(localeWeekdayList[j]); int i = DateUtils.javaWeekdayToLoopWeekday(localeWeekdayList[j]);
if(values != null) if (values != null) drawMarker(canvas, rect, values[i]);
drawMarker(canvas, rect, values[i]);
rect.offset(0, rowHeight); rect.offset(0, rowHeight);
} }
@ -259,19 +259,12 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
{ {
Date time = date.getTime(); 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))]); if (date.get(Calendar.MONTH) == 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) private void drawGrid(Canvas canvas, RectF rGrid)
@ -283,12 +276,14 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
pText.setColor(textColor); pText.setColor(textColor);
pGrid.setColor(gridColor); pGrid.setColor(gridColor);
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT)) { for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
{
canvas.drawText(day, rGrid.right - columnWidth, canvas.drawText(day, rGrid.right - columnWidth,
rGrid.top + rowHeight / 2 + 0.25f * em, pText); rGrid.top + rowHeight / 2 + 0.25f * em, pText);
pGrid.setStrokeWidth(1f); pGrid.setStrokeWidth(1f);
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid); canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top,
pGrid);
rGrid.offset(0, rowHeight); 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); 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; float padding = rect.height() * 0.2f;
createColors(); 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 private void generateRandomData()
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{ {
@Override GregorianCalendar date = DateUtils.getStartOfTodayCalendar();
protected void doInBackground() 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 private float getMaxMonthWidth()
protected void onDetachedFromWindow()
{ {
habit.getCheckmarks().observable.removeListener(this); float maxMonthWidth = 0;
habit.getObservable().removeListener(this); GregorianCalendar day = DateUtils.getStartOfTodayCalendar();
super.onDetachedFromWindow();
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 return maxMonthWidth;
public void onModelChange() }
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; package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context; import android.content.*;
import android.graphics.Canvas; import android.graphics.*;
import android.graphics.Color; import android.graphics.Paint.*;
import android.graphics.Paint; import android.util.*;
import android.graphics.Paint.Align; import android.view.*;
import android.graphics.RectF;
import android.util.AttributeSet; import org.isoron.uhabits.*;
import android.view.HapticFeedbackConstants; import org.isoron.uhabits.models.*;
import android.view.MotionEvent; import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import java.text.*;
import org.isoron.uhabits.models.ModelObservable; import java.util.*;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.tasks.ToggleRepetitionTask; public class HabitHistoryView extends ScrollableDataView implements
import org.isoron.uhabits.utils.ColorUtils; HabitDataView,
import org.isoron.uhabits.utils.DateUtils; ToggleRepetitionTask.Listener,
import org.isoron.uhabits.utils.InterfaceUtils; ModelObservable.Listener
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
{ {
private Habit habit; private Habit habit;
private int[] checkmarks; private int[] checkmarks;
private Paint pSquareBg, pSquareFg, pTextHeader; private Paint pSquareBg, pSquareFg, pTextHeader;
private float squareSpacing; private float squareSpacing;
private float squareTextOffset; private float squareTextOffset;
private float headerTextOffset; private float headerTextOffset;
private float columnWidth; private float columnWidth;
private float columnHeight; private float columnHeight;
private int nColumns; private int nColumns;
private SimpleDateFormat dfMonth; private SimpleDateFormat dfMonth;
private SimpleDateFormat dfYear; private SimpleDateFormat dfYear;
private Calendar baseDate; private Calendar baseDate;
private int nDays; private int nDays;
/** 0-based-position of today in the column */
/**
* 0-based-position of today in the column
*/
private int todayPositionInColumn; private int todayPositionInColumn;
private int colors[]; private int colors[];
private RectF baseLocation; private RectF baseLocation;
private int primaryColor; private int primaryColor;
private boolean isBackgroundTransparent; private boolean isBackgroundTransparent;
private int textColor; private int textColor;
private int reverseTextColor; private int reverseTextColor;
private boolean isEditable; private boolean isEditable;
private String previousMonth;
private String previousYear;
private float headerOverflow = 0;
public HabitHistoryView(Context context) public HabitHistoryView(Context context)
{ {
super(context); super(context);
@ -86,115 +101,89 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
init(); init();
} }
public void setHabit(Habit habit) @Override
public void onLongPress(MotionEvent e)
{ {
this.habit = habit; onSingleTapUp(e);
createColors();
} }
private void init() @Override
public void onModelChange()
{ {
createColors(); refreshData();
createPaints();
isEditable = false;
checkmarks = new int[0];
primaryColor = ColorUtils.getColor(getContext(), 7);
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
baseLocation = new RectF();
} }
private void updateDate() @Override
public boolean onSingleTapUp(MotionEvent e)
{ {
baseDate = DateUtils.getStartOfTodayCalendar(); if (!isEditable) return false;
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
nDays = (nColumns - 1) * 7; performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
int realWeekday = DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
todayPositionInColumn = (7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
baseDate.add(Calendar.DAY_OF_YEAR, -nDays); int pointerId = e.getPointerId(0);
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn); 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 @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) public void onToggleRepetitionFinished()
{ {
int width = MeasureSpec.getSize(widthMeasureSpec); new BaseTask()
int height = MeasureSpec.getSize(heightMeasureSpec); {
setMeasuredDimension(width, height); @Override
protected void doInBackground()
{
refreshData();
} }
@Override @Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) protected void onPostExecute(Void aVoid)
{ {
if(height < 8) height = 200; invalidate();
float baseSize = height / 8.0f; super.onPostExecute(null);
setScrollerBucketSize((int) baseSize); }
}.execute();
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 float getWeekdayLabelWidth() @Override
public void refreshData()
{ {
float width = 0; if (isInEditMode()) generateRandomData();
else
for(String w : DateUtils.getLocaleDayNames(Calendar.SHORT)) {
width = Math.max(width, pSquareFg.measureText(w)); 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.habit = habit;
this.primaryColor = ColorUtils.getColor(getContext(), createColors();
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);
if(isBackgroundTransparent) public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{ {
colors = new int[3]; this.isBackgroundTransparent = isBackgroundTransparent;
colors[0] = Color.argb(16, 255, 255, 255); createColors();
colors[1] = Color.argb(128, red, green, blue);
colors[2] = primaryColor;
textColor = Color.WHITE;
reverseTextColor = Color.WHITE;
} }
else
public void setIsEditable(boolean isEditable)
{ {
colors = new int[3]; this.isEditable = isEditable;
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);
}
} }
protected void createPaints() protected void createPaints()
@ -210,49 +199,37 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
pSquareFg.setTextAlign(Align.CENTER); pSquareFg.setTextAlign(Align.CENTER);
} }
public void refreshData() @Override
protected void onAttachedToWindow()
{ {
if(isInEditMode()) super.onAttachedToWindow();
generateRandomData(); new BaseTask()
else
{ {
if(habit == null) return; @Override
checkmarks = habit.getCheckmarks().getAllValues(); protected void doInBackground()
createColors(); {
refreshData();
} }
}.execute();
updateDate(); habit.getObservable().addListener(this);
postInvalidate(); habit.getCheckmarks().observable.addListener(this);
} }
private void generateRandomData() @Override
{ protected void onDetachedFromWindow()
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; habit.getCheckmarks().observable.removeListener(this);
for (int j = 0; j < 7; j++) habit.getObservable().removeListener(this);
if(checkmarks[i + j] != 0) super.onDetachedFromWindow();
count++;
if(count >= 3) checkmarks[i] = Math.max(checkmarks[i], 1);
}
} }
private String previousMonth;
private String previousYear;
@Override @Override
protected void onDraw(Canvas canvas) protected void onDraw(Canvas canvas)
{ {
super.onDraw(canvas); super.onDraw(canvas);
baseLocation.set(0, 0, columnWidth - squareSpacing, columnWidth - squareSpacing); baseLocation.set(0, 0, columnWidth - squareSpacing,
columnWidth - squareSpacing);
baseLocation.offset(getPaddingLeft(), getPaddingTop()); baseLocation.offset(getPaddingLeft(), getPaddingTop());
headerOverflow = 0; headerOverflow = 0;
@ -266,41 +243,86 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
for (int column = 0; column < nColumns - 1; column++) for (int column = 0; column < nColumns - 1; column++)
{ {
drawColumn(canvas, baseLocation, currentDate, column); drawColumn(canvas, baseLocation, currentDate, column);
baseLocation.offset(columnWidth, - columnHeight); baseLocation.offset(columnWidth, -columnHeight);
} }
drawAxis(canvas, baseLocation); 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); int width = MeasureSpec.getSize(widthMeasureSpec);
location.offset(0, columnWidth); int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
for (int j = 0; j < 7; j++) @Override
{ protected void onSizeChanged(int width,
if (!(column == nColumns - 2 && getDataOffset() == 0 && j > todayPositionInColumn)) int height,
int oldWidth,
int oldHeight)
{ {
int checkmarkOffset = getDataOffset() * 7 + nDays - 7 * (column + 1) + if (height < 8) height = 200;
todayPositionInColumn - j; float baseSize = height / 8.0f;
drawSquare(canvas, location, date, checkmarkOffset); setScrollerBucketSize((int) baseSize);
}
date.add(Calendar.DAY_OF_MONTH, 1); squareSpacing = InterfaceUtils.dpToPixels(getContext(), 1.0f);
location.offset(0, columnWidth); 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, private void createColors()
int checkmarkOffset)
{ {
if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]); if (habit != null) this.primaryColor =
else pSquareBg.setColor(colors[checkmarks[checkmarkOffset]]); ColorUtils.getColor(getContext(), habit.getColor());
pSquareFg.setColor(reverseTextColor); if (isBackgroundTransparent)
canvas.drawRect(location, pSquareBg); primaryColor = ColorUtils.setMinValue(primaryColor, 0.75f);
String text = Integer.toString(date.get(Calendar.DAY_OF_MONTH));
canvas.drawText(text, location.centerX(), location.centerY() + squareTextOffset, pSquareFg); 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) 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);
private void drawColumnHeader(Canvas canvas, RectF location, GregorianCalendar date) 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)
{ {
String month = dfMonth.format(date.getTime()); String month = dfMonth.format(date.getTime());
String year = dfYear.format(date.getTime()); String year = dfYear.format(date.getTime());
String text = null; String text = null;
if (!month.equals(previousMonth)) if (!month.equals(previousMonth)) text = previousMonth = month;
text = previousMonth = month; else if (!year.equals(previousYear)) text = previousYear = year;
else if(!year.equals(previousYear))
text = previousYear = year;
if(text != null) if (text != null)
{ {
canvas.drawText(text, location.left + headerOverflow, location.bottom - headerTextOffset, pTextHeader); canvas.drawText(text, location.left + headerOverflow,
headerOverflow += pTextHeader.measureText(text) + columnWidth * 0.2f; location.bottom - headerTextOffset, pTextHeader);
headerOverflow +=
pTextHeader.measureText(text) + columnWidth * 0.2f;
} }
headerOverflow = Math.max(0, headerOverflow - columnWidth); 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; if (checkmarkOffset >= checkmarks.length) pSquareBg.setColor(colors[0]);
createColors(); 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 private void generateRandomData()
public void onLongPress(MotionEvent e)
{ {
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 private float getWeekdayLabelWidth()
public boolean onSingleTapUp(MotionEvent e)
{ {
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); return width;
float x = e.getX(pointerId); }
float y = e.getY(pointerId);
final Long timestamp = positionToTimestamp(x, y); private void init()
if(timestamp == null) return false; {
createColors();
createPaints();
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp); isEditable = false;
task.setListener(this); checkmarks = new int[0];
task.execute(); 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) private Long positionToTimestamp(float x, float y)
@ -375,71 +445,31 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
int col = (int) (x / columnWidth); int col = (int) (x / columnWidth);
int row = (int) (y / columnWidth); int row = (int) (y / columnWidth);
if(row == 0) return null; if (row == 0) return null;
if(col == nColumns - 1) return null; if (col == nColumns - 1) return null;
int offset = col * 7 + (row - 1); int offset = col * 7 + (row - 1);
Calendar date = (Calendar) baseDate.clone(); Calendar date = (Calendar) baseDate.clone();
date.add(Calendar.DAY_OF_YEAR, offset); date.add(Calendar.DAY_OF_YEAR, offset);
if(DateUtils.getStartOfDay(date.getTimeInMillis()) > DateUtils.getStartOfToday()) if (DateUtils.getStartOfDay(date.getTimeInMillis()) >
return null; DateUtils.getStartOfToday()) return null;
return date.getTimeInMillis(); return date.getTimeInMillis();
} }
public void setIsEditable(boolean isEditable) private void updateDate()
{
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()
{ {
refreshData(); baseDate = DateUtils.getStartOfTodayCalendar();
} baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
@Override nDays = (nColumns - 1) * 7;
protected void onDetachedFromWindow() int realWeekday =
{ DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
habit.getCheckmarks().observable.removeListener(this); todayPositionInColumn =
habit.getObservable().removeListener(this); (7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
super.onDetachedFromWindow();
}
@Override baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
public void onModelChange() baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);
{
refreshData();
} }
} }

@ -19,34 +19,18 @@
package org.isoron.uhabits.ui.habits.show.views; package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context; import android.content.*;
import android.graphics.Bitmap; import android.graphics.*;
import android.graphics.Canvas; import android.support.annotation.*;
import android.graphics.Color; import android.util.*;
import android.graphics.Paint;
import android.graphics.PorterDuff; import org.isoron.uhabits.*;
import android.graphics.PorterDuffXfermode; import org.isoron.uhabits.models.*;
import android.graphics.RectF; import org.isoron.uhabits.tasks.*;
import android.support.annotation.NonNull; import org.isoron.uhabits.utils.*;
import android.support.annotation.Nullable;
import android.util.AttributeSet; import java.text.*;
import android.util.Log; import java.util.*;
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;
public class HabitScoreView extends ScrollableDataView public class HabitScoreView extends ScrollableDataView
implements HabitDataView, ModelObservable.Listener implements HabitDataView, ModelObservable.Listener
@ -138,10 +122,8 @@ public class HabitScoreView extends ScrollableDataView
else else
{ {
if (habit == null) return; if (habit == null) return;
if (bucketSize == 1) if (bucketSize == 1) scores = habit.getScores().getAll();
scores = habit.getScores().getAll(); else scores = habit.getScores().groupBy(getTruncateField());
else
scores = habit.getScores().groupBy(getTruncateField());
createColors(); createColors();
} }
@ -168,19 +150,6 @@ public class HabitScoreView extends ScrollableDataView
requestLayout(); 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() protected void createPaints()
{ {
pText = new Paint(); pText = new Paint();
@ -194,6 +163,158 @@ public class HabitScoreView extends ScrollableDataView
pGrid.setAntiAlias(true); 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) private void drawFooter(Canvas canvas, RectF rect, long currentDate)
{ {
String yearText = dfYear.format(currentDate); String yearText = dfYear.format(currentDate);
@ -393,145 +514,6 @@ public class HabitScoreView extends ScrollableDataView
cacheCanvas = new Canvas(drawingCache); 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) private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color)
{ {
if (isTransparencyEnabled) p.setXfermode(mode); if (isTransparencyEnabled) p.setXfermode(mode);

@ -19,27 +19,18 @@
package org.isoron.uhabits.ui.habits.show.views; package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context; import android.content.*;
import android.graphics.Canvas; import android.graphics.*;
import android.graphics.Color; import android.util.*;
import android.graphics.Paint; import android.view.*;
import android.graphics.RectF;
import android.util.AttributeSet; import org.isoron.uhabits.*;
import android.view.View; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.R; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.ModelObservable; import java.text.*;
import org.isoron.uhabits.models.Streak; import java.util.*;
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;
public class HabitStreakView extends View public class HabitStreakView extends View
implements HabitDataView, ModelObservable.Listener implements HabitDataView, ModelObservable.Listener
@ -124,6 +115,82 @@ public class HabitStreakView extends View
createColors(); 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() private void createColors()
{ {
if (habit != null) this.primaryColor = if (habit != null) this.primaryColor =
@ -145,13 +212,6 @@ public class HabitStreakView extends View
R.attr.highContrastReverseTextColor); 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) private void drawRow(Canvas canvas, Streak streak, RectF rect)
{ {
if (maxLength == 0) return; if (maxLength == 0) return;
@ -208,75 +268,6 @@ public class HabitStreakView extends View
baseSize = getResources().getDimensionPixelSize(R.dimen.baseSize); 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) private int percentageToColor(float percentage)
{ {
if (percentage >= 1.0f) return colors[3]; if (percentage >= 1.0f) return colors[3];

@ -19,22 +19,17 @@
package org.isoron.uhabits.ui.habits.show.views; package org.isoron.uhabits.ui.habits.show.views;
import android.content.Context; import android.content.*;
import android.graphics.Bitmap; import android.graphics.*;
import android.graphics.Canvas; import android.support.annotation.*;
import android.graphics.Color; import android.text.*;
import android.graphics.Paint; import android.util.*;
import android.graphics.PorterDuff; import android.view.*;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF; import org.isoron.uhabits.*;
import android.support.annotation.Nullable; import org.isoron.uhabits.utils.*;
import android.text.TextPaint;
import android.util.AttributeSet; import static org.isoron.uhabits.utils.InterfaceUtils.*;
import android.view.View;
import org.isoron.uhabits.R;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
public class RingView extends View public class RingView extends View
{ {
@ -42,24 +37,34 @@ public class RingView extends View
new PorterDuffXfermode(PorterDuff.Mode.CLEAR); new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
private int color; private int color;
private float precision; private float precision;
private float percentage; private float percentage;
private int diameter; private int diameter;
private float thickness; private float thickness;
private RectF rect; private RectF rect;
private TextPaint pRing; private TextPaint pRing;
private Integer backgroundColor; private Integer backgroundColor;
private Integer inactiveColor; private Integer inactiveColor;
private float em; private float em;
private String text; private String text;
private float textSize; private float textSize;
private boolean enableFontAwesome; private boolean enableFontAwesome;
@Nullable @Nullable
private Bitmap drawingCache; private Bitmap drawingCache;
private Canvas cacheCanvas; private Canvas cacheCanvas;
private boolean isTransparencyEnabled; private boolean isTransparencyEnabled;
@ -71,54 +76,56 @@ public class RingView extends View
percentage = 0.0f; percentage = 0.0f;
precision = 0.01f; precision = 0.01f;
color = ColorUtils.getAndroidTestColor(0); color = ColorUtils.getAndroidTestColor(0);
thickness = InterfaceUtils.dpToPixels(getContext(), 2); thickness = dpToPixels(getContext(), 2);
text = ""; text = "";
textSize = context.getResources().getDimension(R.dimen.smallTextSize); textSize = context.getResources().getDimension(R.dimen.smallTextSize);
init(); 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); percentage = getFloatAttribute(ctx, attrs, "percentage", 0);
precision = InterfaceUtils.getFloatAttribute(context, attrs, "precision", 0.01f); precision = getFloatAttribute(ctx, attrs, "precision", 0.01f);
color = InterfaceUtils.getColorAttribute(context, attrs, "color", 0); color = getColorAttribute(ctx, attrs, "color", 0);
backgroundColor = InterfaceUtils.getColorAttribute(context, attrs, "backgroundColor", null); backgroundColor =
inactiveColor = InterfaceUtils.getColorAttribute(context, attrs, "inactiveColor", null); getColorAttribute(ctx, attrs, "backgroundColor", null);
inactiveColor = getColorAttribute(ctx, attrs, "inactiveColor", null);
thickness = InterfaceUtils.getFloatAttribute(context, attrs, "thickness", 0); thickness = getFloatAttribute(ctx, attrs, "thickness", 0);
thickness = InterfaceUtils.dpToPixels(context, thickness); thickness = dpToPixels(ctx, thickness);
float defaultTextSize = context.getResources().getDimension(R.dimen.smallTextSize); float defaultTextSize =
textSize = InterfaceUtils.getFloatAttribute(context, attrs, "textSize", defaultTextSize); ctx.getResources().getDimension(R.dimen.smallTextSize);
textSize = InterfaceUtils.spToPixels(context, textSize); textSize = getFloatAttribute(ctx, attrs, "textSize", defaultTextSize);
textSize = spToPixels(ctx, textSize);
text = getAttribute(ctx, attrs, "text", "");
text = InterfaceUtils.getAttribute(context, attrs, "text", ""); enableFontAwesome =
getBooleanAttribute(ctx, attrs, "enableFontAwesome", false);
enableFontAwesome = InterfaceUtils.getBooleanAttribute(context, attrs, "enableFontAwesome", false);
init(); init();
} }
public void setColor(int color) @Override
public void setBackgroundColor(int backgroundColor)
{ {
this.color = color; this.backgroundColor = backgroundColor;
postInvalidate(); postInvalidate();
} }
public void setTextSize(float textSize) public void setColor(int color)
{ {
this.textSize = textSize; this.color = color;
postInvalidate();
} }
@Override public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
public void setBackgroundColor(int backgroundColor)
{ {
this.backgroundColor = backgroundColor; this.isTransparencyEnabled = isTransparencyEnabled;
postInvalidate();
} }
public void setPercentage(float percentage) public void setPercentage(float percentage)
@ -133,64 +140,21 @@ public class RingView extends View
postInvalidate(); postInvalidate();
} }
public void setThickness(float thickness)
{
this.thickness = thickness;
postInvalidate();
}
public void setText(String text) public void setText(String text)
{ {
this.text = text; this.text = text;
postInvalidate(); postInvalidate();
} }
private void init() public void setTextSize(float textSize)
{
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)
{ {
super.onSizeChanged(w, h, oldw, oldh); this.textSize = textSize;
if(isTransparencyEnabled) reallocateCache();
} }
private void reallocateCache() public void setThickness(float thickness)
{ {
if (drawingCache != null) drawingCache.recycle(); this.thickness = thickness;
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888); postInvalidate();
cacheCanvas = new Canvas(drawingCache);
} }
@Override @Override
@ -199,9 +163,9 @@ public class RingView extends View
super.onDraw(canvas); super.onDraw(canvas);
Canvas activeCanvas; Canvas activeCanvas;
if(isTransparencyEnabled) if (isTransparencyEnabled)
{ {
if(drawingCache == null) reallocateCache(); if (drawingCache == null) reallocateCache();
activeCanvas = cacheCanvas; activeCanvas = cacheCanvas;
drawingCache.eraseColor(Color.TRANSPARENT); drawingCache.eraseColor(Color.TRANSPARENT);
} }
@ -220,12 +184,10 @@ public class RingView extends View
pRing.setColor(inactiveColor); pRing.setColor(inactiveColor);
activeCanvas.drawArc(rect, angle - 90, 360 - angle, true, pRing); activeCanvas.drawArc(rect, angle - 90, 360 - angle, true, pRing);
if(thickness > 0) if (thickness > 0)
{ {
if(isTransparencyEnabled) if (isTransparencyEnabled) pRing.setXfermode(XFERMODE_CLEAR);
pRing.setXfermode(XFERMODE_CLEAR); else pRing.setColor(backgroundColor);
else
pRing.setColor(backgroundColor);
rect.inset(thickness, thickness); rect.inset(thickness, thickness);
activeCanvas.drawArc(rect, 0, 360, true, pRing); activeCanvas.drawArc(rect, 0, 360, true, pRing);
@ -233,16 +195,63 @@ public class RingView extends View
pRing.setColor(color); pRing.setColor(color);
pRing.setTextSize(textSize); pRing.setTextSize(textSize);
if(enableFontAwesome) pRing.setTypeface(InterfaceUtils.getFontAwesome(getContext())); if (enableFontAwesome)
activeCanvas.drawText(text, rect.centerX(), rect.centerY() + 0.4f * em, pRing); pRing.setTypeface(getFontAwesome(getContext()));
activeCanvas.drawText(text, rect.centerX(),
rect.centerY() + 0.4f * em, pRing);
} }
if(activeCanvas != canvas) if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null);
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; package org.isoron.uhabits.ui.habits.show.views;
import android.animation.ValueAnimator; import android.animation.*;
import android.content.Context; import android.content.*;
import android.util.AttributeSet; import android.util.*;
import android.view.GestureDetector; import android.view.*;
import android.view.MotionEvent; import android.widget.*;
import android.view.View;
import android.view.ViewParent;
import android.widget.Scroller;
public abstract class ScrollableDataView extends View public abstract class ScrollableDataView extends View
implements GestureDetector.OnGestureListener, implements GestureDetector.OnGestureListener,

@ -20,6 +20,9 @@
package org.isoron.uhabits.ui.settings; package org.isoron.uhabits.ui.settings;
import android.os.*; import android.os.*;
import android.support.annotation.*;
import android.support.v4.app.*;
import android.view.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.ui.*; 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.Habit;
import org.isoron.uhabits.models.Score; import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView; 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.ui.habits.show.views.RingView;
import org.isoron.uhabits.utils.ColorUtils; import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils; import org.isoron.uhabits.utils.InterfaceUtils;

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

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