mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Reformat and reorganize some code
This commit is contained in:
@@ -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());
|
||||||
|
textView.setTextColor(androidColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateColors()
|
||||||
|
{
|
||||||
|
fragment.activeColor = ColorUtils.getColor(fragment.getContext(),
|
||||||
fragment.habit.getColor());
|
fragment.habit.getColor());
|
||||||
scoreRing.setColor(androidColor);
|
fragment.inactiveColor =
|
||||||
scoreRing.setPercentage(todayPercentage);
|
InterfaceUtils.getStyledColor(fragment.getContext(),
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
if (fragment.habit == null) return;
|
||||||
updateColor(view, R.id.tvOverview);
|
if (view == null) return;
|
||||||
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)
|
float todayPercentage = fragment.todayScore / Score.MAX_VALUE;
|
||||||
{
|
float monthDiff =
|
||||||
if (fragment.habit == null || fragment.activity == null) return;
|
todayPercentage - (fragment.lastMonthScore / Score.MAX_VALUE);
|
||||||
|
float yearDiff =
|
||||||
|
todayPercentage - (fragment.lastYearScore / Score.MAX_VALUE);
|
||||||
|
|
||||||
TextView textView = (TextView) view.findViewById(viewId);
|
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
|
||||||
int androidColor =
|
int androidColor = ColorUtils.getColor(fragment.getActivity(),
|
||||||
ColorUtils.getColor(fragment.activity, fragment.habit.getColor());
|
|
||||||
textView.setTextColor(androidColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateColors()
|
|
||||||
{
|
|
||||||
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.R;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.ModelObservable;
|
import org.isoron.uhabits.tasks.*;
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.utils.ColorUtils;
|
|
||||||
import org.isoron.uhabits.utils.DateUtils;
|
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.*;
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
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
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onModelChange()
|
||||||
|
{
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refreshData()
|
||||||
|
{
|
||||||
|
if (isInEditMode()) generateRandomData();
|
||||||
|
else if (habit != null)
|
||||||
|
{
|
||||||
|
frequency = habit.getRepetitions().getWeekdayFrequency();
|
||||||
|
createColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
public void setHabit(Habit habit)
|
public void setHabit(Habit habit)
|
||||||
{
|
{
|
||||||
this.habit = habit;
|
this.habit = habit;
|
||||||
createColors();
|
createColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init()
|
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
|
||||||
{
|
{
|
||||||
createPaints();
|
this.isBackgroundTransparent = isBackgroundTransparent;
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
dfMonth = DateUtils.getDateFormat("MMM");
|
|
||||||
dfYear = DateUtils.getDateFormat("yyyy");
|
|
||||||
|
|
||||||
rect = new RectF();
|
|
||||||
prevRect = new RectF();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createPaints()
|
protected void createPaints()
|
||||||
@@ -128,181 +127,6 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
|
|||||||
pGrid.setAntiAlias(true);
|
pGrid.setAntiAlias(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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++)
|
|
||||||
{
|
|
||||||
day.set(Calendar.MONTH, i);
|
|
||||||
float monthWidth = pText.measureText(dfMonth.format(day.getTime()));
|
|
||||||
maxMonthWidth = Math.max(maxMonthWidth, monthWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
return maxMonthWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshData()
|
|
||||||
{
|
|
||||||
if(isInEditMode()) generateRandomData();
|
|
||||||
else if(habit != null)
|
|
||||||
{
|
|
||||||
frequency = habit.getRepetitions().getWeekdayFrequency();
|
|
||||||
createColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas)
|
|
||||||
{
|
|
||||||
super.onDraw(canvas);
|
|
||||||
|
|
||||||
rect.set(0, 0, nColumns * columnWidth, columnHeight);
|
|
||||||
rect.offset(0, paddingTop);
|
|
||||||
|
|
||||||
drawGrid(canvas, rect);
|
|
||||||
|
|
||||||
pText.setTextAlign(Paint.Align.CENTER);
|
|
||||||
pText.setColor(textColor);
|
|
||||||
pGraph.setColor(primaryColor);
|
|
||||||
prevRect.setEmpty();
|
|
||||||
|
|
||||||
GregorianCalendar currentDate = DateUtils.getStartOfTodayCalendar();
|
|
||||||
|
|
||||||
currentDate.set(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset());
|
|
||||||
|
|
||||||
for(int i = 0; i < nColumns - 1; i++)
|
|
||||||
{
|
|
||||||
rect.set(0, 0, columnWidth, columnHeight);
|
|
||||||
rect.offset(i * columnWidth, 0);
|
|
||||||
|
|
||||||
drawColumn(canvas, rect, currentDate);
|
|
||||||
currentDate.add(Calendar.MONTH, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawColumn(Canvas canvas, RectF rect, GregorianCalendar date)
|
|
||||||
{
|
|
||||||
Integer values[] = frequency.get(date.getTimeInMillis());
|
|
||||||
float rowHeight = rect.height() / 8.0f;
|
|
||||||
prevRect.set(rect);
|
|
||||||
|
|
||||||
Integer[] localeWeekdayList = DateUtils.getLocaleWeekdayList();
|
|
||||||
for (int j = 0; j < localeWeekdayList.length; j++)
|
|
||||||
{
|
|
||||||
rect.set(0, 0, baseSize, baseSize);
|
|
||||||
rect.offset(prevRect.left, prevRect.top + baseSize * j);
|
|
||||||
|
|
||||||
int i = DateUtils.javaWeekdayToLoopWeekday(localeWeekdayList[j]);
|
|
||||||
if(values != null)
|
|
||||||
drawMarker(canvas, rect, values[i]);
|
|
||||||
|
|
||||||
rect.offset(0, rowHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawFooter(canvas, rect, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawFooter(Canvas canvas, RectF rect, GregorianCalendar date)
|
|
||||||
{
|
|
||||||
Date time = date.getTime();
|
|
||||||
|
|
||||||
canvas.drawText(dfMonth.format(time), rect.centerX(), rect.centerY() - 0.1f * em, pText);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawGrid(Canvas canvas, RectF rGrid)
|
|
||||||
{
|
|
||||||
int nRows = 7;
|
|
||||||
float rowHeight = rGrid.height() / (nRows + 1);
|
|
||||||
|
|
||||||
pText.setTextAlign(Paint.Align.LEFT);
|
|
||||||
pText.setColor(textColor);
|
|
||||||
pGrid.setColor(gridColor);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
rGrid.offset(0, rowHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
|
|
||||||
{
|
|
||||||
this.isBackgroundTransparent = isBackgroundTransparent;
|
|
||||||
createColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow()
|
protected void onAttachedToWindow()
|
||||||
{
|
{
|
||||||
@@ -328,8 +152,197 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onModelChange()
|
protected void onDraw(Canvas canvas)
|
||||||
{
|
{
|
||||||
refreshData();
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
rect.set(0, 0, nColumns * columnWidth, columnHeight);
|
||||||
|
rect.offset(0, paddingTop);
|
||||||
|
|
||||||
|
drawGrid(canvas, rect);
|
||||||
|
|
||||||
|
pText.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pText.setColor(textColor);
|
||||||
|
pGraph.setColor(primaryColor);
|
||||||
|
prevRect.setEmpty();
|
||||||
|
|
||||||
|
GregorianCalendar currentDate = DateUtils.getStartOfTodayCalendar();
|
||||||
|
|
||||||
|
currentDate.set(Calendar.DAY_OF_MONTH, 1);
|
||||||
|
currentDate.add(Calendar.MONTH, -nColumns + 2 - getDataOffset());
|
||||||
|
|
||||||
|
for (int i = 0; i < nColumns - 1; i++)
|
||||||
|
{
|
||||||
|
rect.set(0, 0, columnWidth, columnHeight);
|
||||||
|
rect.offset(i * columnWidth, 0);
|
||||||
|
|
||||||
|
drawColumn(canvas, rect, currentDate);
|
||||||
|
currentDate.add(Calendar.MONTH, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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());
|
||||||
|
float rowHeight = rect.height() / 8.0f;
|
||||||
|
prevRect.set(rect);
|
||||||
|
|
||||||
|
Integer[] localeWeekdayList = DateUtils.getLocaleWeekdayList();
|
||||||
|
for (int j = 0; j < localeWeekdayList.length; j++)
|
||||||
|
{
|
||||||
|
rect.set(0, 0, baseSize, baseSize);
|
||||||
|
rect.offset(prevRect.left, prevRect.top + baseSize * j);
|
||||||
|
|
||||||
|
int i = DateUtils.javaWeekdayToLoopWeekday(localeWeekdayList[j]);
|
||||||
|
if (values != null) drawMarker(canvas, rect, values[i]);
|
||||||
|
|
||||||
|
rect.offset(0, rowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawFooter(canvas, rect, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawFooter(Canvas canvas, RectF rect, GregorianCalendar date)
|
||||||
|
{
|
||||||
|
Date time = date.getTime();
|
||||||
|
|
||||||
|
canvas.drawText(dfMonth.format(time), rect.centerX(),
|
||||||
|
rect.centerY() - 0.1f * em, pText);
|
||||||
|
|
||||||
|
if (date.get(Calendar.MONTH) == 1)
|
||||||
|
canvas.drawText(dfYear.format(time), rect.centerX(),
|
||||||
|
rect.centerY() + 0.9f * em, pText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawGrid(Canvas canvas, RectF rGrid)
|
||||||
|
{
|
||||||
|
int nRows = 7;
|
||||||
|
float rowHeight = rGrid.height() / (nRows + 1);
|
||||||
|
|
||||||
|
pText.setTextAlign(Paint.Align.LEFT);
|
||||||
|
pText.setColor(textColor);
|
||||||
|
pGrid.setColor(gridColor);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
rGrid.offset(0, rowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getMaxMonthWidth()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxMonthWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
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 android.view.HapticFeedbackConstants;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.ModelObservable;
|
import org.isoron.uhabits.tasks.*;
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
import org.isoron.uhabits.utils.*;
|
||||||
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.text.*;
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class HabitHistoryView extends ScrollableDataView implements HabitDataView,
|
public class HabitHistoryView extends ScrollableDataView implements
|
||||||
ToggleRepetitionTask.Listener, ModelObservable.Listener
|
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,273 +101,22 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHabit(Habit habit)
|
|
||||||
{
|
|
||||||
this.habit = habit;
|
|
||||||
createColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
createColors();
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
baseDate = DateUtils.getStartOfTodayCalendar();
|
|
||||||
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
|
|
||||||
|
|
||||||
nDays = (nColumns - 1) * 7;
|
|
||||||
int realWeekday = DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
|
|
||||||
todayPositionInColumn = (7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
|
|
||||||
|
|
||||||
baseDate.add(Calendar.DAY_OF_YEAR, -nDays);
|
|
||||||
baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn);
|
|
||||||
}
|
|
||||||
|
|
||||||
@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 < 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getWeekdayLabelWidth()
|
|
||||||
{
|
|
||||||
float width = 0;
|
|
||||||
|
|
||||||
for(String w : DateUtils.getLocaleDayNames(Calendar.SHORT))
|
|
||||||
width = Math.max(width, pSquareFg.measureText(w));
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createColors()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void createPaints()
|
|
||||||
{
|
|
||||||
pTextHeader = new Paint();
|
|
||||||
pTextHeader.setTextAlign(Align.LEFT);
|
|
||||||
pTextHeader.setAntiAlias(true);
|
|
||||||
|
|
||||||
pSquareBg = new Paint();
|
|
||||||
|
|
||||||
pSquareFg = new Paint();
|
|
||||||
pSquareFg.setAntiAlias(true);
|
|
||||||
pSquareFg.setTextAlign(Align.CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshData()
|
|
||||||
{
|
|
||||||
if(isInEditMode())
|
|
||||||
generateRandomData();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(habit == null) return;
|
|
||||||
checkmarks = habit.getCheckmarks().getAllValues();
|
|
||||||
createColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDate();
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String previousMonth;
|
|
||||||
private String previousYear;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas)
|
|
||||||
{
|
|
||||||
super.onDraw(canvas);
|
|
||||||
|
|
||||||
baseLocation.set(0, 0, columnWidth - squareSpacing, columnWidth - squareSpacing);
|
|
||||||
baseLocation.offset(getPaddingLeft(), getPaddingTop());
|
|
||||||
|
|
||||||
headerOverflow = 0;
|
|
||||||
previousMonth = "";
|
|
||||||
previousYear = "";
|
|
||||||
pTextHeader.setColor(textColor);
|
|
||||||
|
|
||||||
updateDate();
|
|
||||||
GregorianCalendar currentDate = (GregorianCalendar) baseDate.clone();
|
|
||||||
|
|
||||||
for (int column = 0; column < nColumns - 1; column++)
|
|
||||||
{
|
|
||||||
drawColumn(canvas, baseLocation, currentDate, column);
|
|
||||||
baseLocation.offset(columnWidth, - columnHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawAxis(canvas, baseLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 drawSquare(Canvas canvas, RectF location, GregorianCalendar date,
|
|
||||||
int checkmarkOffset)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawAxis(Canvas canvas, RectF location)
|
|
||||||
{
|
|
||||||
float verticalOffset = pTextHeader.getFontSpacing() * 0.4f;
|
|
||||||
|
|
||||||
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
|
|
||||||
{
|
|
||||||
location.offset(0, columnWidth);
|
|
||||||
canvas.drawText(day, location.left + headerTextOffset,
|
|
||||||
location.centerY() + verticalOffset, pTextHeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float headerOverflow = 0;
|
|
||||||
|
|
||||||
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(text != null)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
this.isBackgroundTransparent = isBackgroundTransparent;
|
|
||||||
createColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLongPress(MotionEvent e)
|
public void onLongPress(MotionEvent e)
|
||||||
{
|
{
|
||||||
onSingleTapUp(e);
|
onSingleTapUp(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onModelChange()
|
||||||
|
{
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onSingleTapUp(MotionEvent e)
|
public boolean onSingleTapUp(MotionEvent e)
|
||||||
{
|
{
|
||||||
if(!isEditable) return false;
|
if (!isEditable) return false;
|
||||||
|
|
||||||
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||||
|
|
||||||
@@ -361,7 +125,7 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
|
|||||||
float y = e.getY(pointerId);
|
float y = e.getY(pointerId);
|
||||||
|
|
||||||
final Long timestamp = positionToTimestamp(x, y);
|
final Long timestamp = positionToTimestamp(x, y);
|
||||||
if(timestamp == null) return false;
|
if (timestamp == null) return false;
|
||||||
|
|
||||||
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
|
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
|
||||||
task.setListener(this);
|
task.setListener(this);
|
||||||
@@ -370,29 +134,6 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Long positionToTimestamp(float x, float y)
|
|
||||||
{
|
|
||||||
int col = (int) (x / columnWidth);
|
|
||||||
int row = (int) (y / columnWidth);
|
|
||||||
|
|
||||||
if(row == 0) return null;
|
|
||||||
if(col == nColumns - 1) return null;
|
|
||||||
|
|
||||||
int offset = col * 7 + (row - 1);
|
|
||||||
Calendar date = (Calendar) baseDate.clone();
|
|
||||||
date.add(Calendar.DAY_OF_YEAR, offset);
|
|
||||||
|
|
||||||
if(DateUtils.getStartOfDay(date.getTimeInMillis()) > DateUtils.getStartOfToday())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return date.getTimeInMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsEditable(boolean isEditable)
|
|
||||||
{
|
|
||||||
this.isEditable = isEditable;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onToggleRepetitionFinished()
|
public void onToggleRepetitionFinished()
|
||||||
{
|
{
|
||||||
@@ -413,6 +154,51 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshData()
|
||||||
|
{
|
||||||
|
if (isInEditMode()) generateRandomData();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (habit == null) return;
|
||||||
|
checkmarks = habit.getCheckmarks().getAllValues();
|
||||||
|
createColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDate();
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHabit(Habit habit)
|
||||||
|
{
|
||||||
|
this.habit = habit;
|
||||||
|
createColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
|
||||||
|
{
|
||||||
|
this.isBackgroundTransparent = isBackgroundTransparent;
|
||||||
|
createColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsEditable(boolean isEditable)
|
||||||
|
{
|
||||||
|
this.isEditable = isEditable;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createPaints()
|
||||||
|
{
|
||||||
|
pTextHeader = new Paint();
|
||||||
|
pTextHeader.setTextAlign(Align.LEFT);
|
||||||
|
pTextHeader.setAntiAlias(true);
|
||||||
|
|
||||||
|
pSquareBg = new Paint();
|
||||||
|
|
||||||
|
pSquareFg = new Paint();
|
||||||
|
pSquareFg.setAntiAlias(true);
|
||||||
|
pSquareFg.setTextAlign(Align.CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow()
|
protected void onAttachedToWindow()
|
||||||
{
|
{
|
||||||
@@ -438,8 +224,252 @@ public class HabitHistoryView extends ScrollableDataView implements HabitDataVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onModelChange()
|
protected void onDraw(Canvas canvas)
|
||||||
{
|
{
|
||||||
refreshData();
|
super.onDraw(canvas);
|
||||||
|
|
||||||
|
baseLocation.set(0, 0, columnWidth - squareSpacing,
|
||||||
|
columnWidth - squareSpacing);
|
||||||
|
baseLocation.offset(getPaddingLeft(), getPaddingTop());
|
||||||
|
|
||||||
|
headerOverflow = 0;
|
||||||
|
previousMonth = "";
|
||||||
|
previousYear = "";
|
||||||
|
pTextHeader.setColor(textColor);
|
||||||
|
|
||||||
|
updateDate();
|
||||||
|
GregorianCalendar currentDate = (GregorianCalendar) baseDate.clone();
|
||||||
|
|
||||||
|
for (int column = 0; column < nColumns - 1; column++)
|
||||||
|
{
|
||||||
|
drawColumn(canvas, baseLocation, currentDate, column);
|
||||||
|
baseLocation.offset(columnWidth, -columnHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawAxis(canvas, baseLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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 < 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createColors()
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
float verticalOffset = pTextHeader.getFontSpacing() * 0.4f;
|
||||||
|
|
||||||
|
for (String day : DateUtils.getLocaleDayNames(Calendar.SHORT))
|
||||||
|
{
|
||||||
|
location.offset(0, columnWidth);
|
||||||
|
canvas.drawText(day, location.left + headerTextOffset,
|
||||||
|
location.centerY() + verticalOffset, pTextHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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 (text != null)
|
||||||
|
{
|
||||||
|
canvas.drawText(text, location.left + headerOverflow,
|
||||||
|
location.bottom - headerTextOffset, pTextHeader);
|
||||||
|
headerOverflow +=
|
||||||
|
pTextHeader.measureText(text) + columnWidth * 0.2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
headerOverflow = Math.max(0, headerOverflow - columnWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawSquare(Canvas canvas,
|
||||||
|
RectF location,
|
||||||
|
GregorianCalendar date,
|
||||||
|
int checkmarkOffset)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getWeekdayLabelWidth()
|
||||||
|
{
|
||||||
|
float width = 0;
|
||||||
|
|
||||||
|
for (String w : DateUtils.getLocaleDayNames(Calendar.SHORT))
|
||||||
|
width = Math.max(width, pSquareFg.measureText(w));
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
createColors();
|
||||||
|
createPaints();
|
||||||
|
|
||||||
|
isEditable = false;
|
||||||
|
checkmarks = new int[0];
|
||||||
|
primaryColor = ColorUtils.getColor(getContext(), 7);
|
||||||
|
dfMonth = DateUtils.getDateFormat("MMM");
|
||||||
|
dfYear = DateUtils.getDateFormat("yyyy");
|
||||||
|
|
||||||
|
baseLocation = new RectF();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long positionToTimestamp(float x, float y)
|
||||||
|
{
|
||||||
|
int col = (int) (x / columnWidth);
|
||||||
|
int row = (int) (y / columnWidth);
|
||||||
|
|
||||||
|
if (row == 0) return null;
|
||||||
|
if (col == nColumns - 1) return null;
|
||||||
|
|
||||||
|
int offset = col * 7 + (row - 1);
|
||||||
|
Calendar date = (Calendar) baseDate.clone();
|
||||||
|
date.add(Calendar.DAY_OF_YEAR, offset);
|
||||||
|
|
||||||
|
if (DateUtils.getStartOfDay(date.getTimeInMillis()) >
|
||||||
|
DateUtils.getStartOfToday()) return null;
|
||||||
|
|
||||||
|
return date.getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDate()
|
||||||
|
{
|
||||||
|
baseDate = DateUtils.getStartOfTodayCalendar();
|
||||||
|
baseDate.add(Calendar.DAY_OF_YEAR, -(getDataOffset() - 1) * 7);
|
||||||
|
|
||||||
|
nDays = (nColumns - 1) * 7;
|
||||||
|
int realWeekday =
|
||||||
|
DateUtils.getStartOfTodayCalendar().get(Calendar.DAY_OF_WEEK);
|
||||||
|
todayPositionInColumn =
|
||||||
|
(7 + realWeekday - baseDate.getFirstDayOfWeek()) % 7;
|
||||||
|
|
||||||
|
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;
|
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 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.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.ModelObservable;
|
import org.isoron.uhabits.tasks.*;
|
||||||
import org.isoron.uhabits.models.Score;
|
import org.isoron.uhabits.utils.*;
|
||||||
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.text.*;
|
||||||
import java.util.Calendar;
|
import java.util.*;
|
||||||
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 android.view.View;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.models.ModelObservable;
|
import org.isoron.uhabits.tasks.*;
|
||||||
import org.isoron.uhabits.models.Streak;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.tasks.BaseTask;
|
|
||||||
import org.isoron.uhabits.utils.ColorUtils;
|
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.*;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
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,27 +115,6 @@ public class HabitStreakView extends View
|
|||||||
createColors();
|
createColors();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createColors()
|
|
||||||
{
|
|
||||||
if (habit != null) this.primaryColor =
|
|
||||||
ColorUtils.getColor(getContext(), habit.getColor());
|
|
||||||
|
|
||||||
int red = Color.red(primaryColor);
|
|
||||||
int green = Color.green(primaryColor);
|
|
||||||
int blue = Color.blue(primaryColor);
|
|
||||||
|
|
||||||
colors = new int[4];
|
|
||||||
colors[3] = primaryColor;
|
|
||||||
colors[2] = Color.argb(192, red, green, blue);
|
|
||||||
colors[1] = Color.argb(96, red, green, blue);
|
|
||||||
colors[0] = InterfaceUtils.getStyledColor(getContext(),
|
|
||||||
R.attr.lowContrastTextColor);
|
|
||||||
textColor = InterfaceUtils.getStyledColor(getContext(),
|
|
||||||
R.attr.mediumContrastTextColor);
|
|
||||||
reverseTextColor = InterfaceUtils.getStyledColor(getContext(),
|
|
||||||
R.attr.highContrastReverseTextColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void createPaints()
|
protected void createPaints()
|
||||||
{
|
{
|
||||||
paint = new Paint();
|
paint = new Paint();
|
||||||
@@ -152,62 +122,6 @@ public class HabitStreakView extends View
|
|||||||
paint.setAntiAlias(true);
|
paint.setAntiAlias(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawRow(Canvas canvas, Streak streak, RectF rect)
|
|
||||||
{
|
|
||||||
if (maxLength == 0) return;
|
|
||||||
|
|
||||||
float percentage = (float) streak.getLength() / maxLength;
|
|
||||||
float availableWidth = width - 2 * maxLabelWidth;
|
|
||||||
if (shouldShowLabels) availableWidth -= 2 * textMargin;
|
|
||||||
|
|
||||||
float barWidth = percentage * availableWidth;
|
|
||||||
float minBarWidth =
|
|
||||||
paint.measureText(Long.toString(streak.getLength())) + em;
|
|
||||||
barWidth = Math.max(barWidth, minBarWidth);
|
|
||||||
|
|
||||||
float gap = (width - barWidth) / 2;
|
|
||||||
float paddingTopBottom = baseSize * 0.05f;
|
|
||||||
|
|
||||||
paint.setColor(percentageToColor(percentage));
|
|
||||||
|
|
||||||
canvas.drawRect(rect.left + gap, rect.top + paddingTopBottom,
|
|
||||||
rect.right - gap, rect.bottom - paddingTopBottom, paint);
|
|
||||||
|
|
||||||
float yOffset = rect.centerY() + 0.3f * em;
|
|
||||||
|
|
||||||
paint.setColor(reverseTextColor);
|
|
||||||
paint.setTextAlign(Paint.Align.CENTER);
|
|
||||||
canvas.drawText(Long.toString(streak.getLength()), rect.centerX(),
|
|
||||||
yOffset, paint);
|
|
||||||
|
|
||||||
if (shouldShowLabels)
|
|
||||||
{
|
|
||||||
String startLabel = dateFormat.format(new Date(streak.getStart()));
|
|
||||||
String endLabel = dateFormat.format(new Date(streak.getEnd()));
|
|
||||||
|
|
||||||
paint.setColor(textColor);
|
|
||||||
paint.setTextAlign(Paint.Align.RIGHT);
|
|
||||||
canvas.drawText(startLabel, gap - textMargin, yOffset, paint);
|
|
||||||
|
|
||||||
paint.setTextAlign(Paint.Align.LEFT);
|
|
||||||
canvas.drawText(endLabel, width - gap + textMargin, yOffset, paint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
createPaints();
|
|
||||||
createColors();
|
|
||||||
|
|
||||||
streaks = Collections.emptyList();
|
|
||||||
|
|
||||||
dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
|
|
||||||
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
||||||
rect = new RectF();
|
|
||||||
maxStreakCount = 10;
|
|
||||||
baseSize = getResources().getDimensionPixelSize(R.dimen.baseSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow()
|
protected void onAttachedToWindow()
|
||||||
{
|
{
|
||||||
@@ -277,6 +191,83 @@ public class HabitStreakView extends View
|
|||||||
updateMaxMin();
|
updateMaxMin();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createColors()
|
||||||
|
{
|
||||||
|
if (habit != null) this.primaryColor =
|
||||||
|
ColorUtils.getColor(getContext(), habit.getColor());
|
||||||
|
|
||||||
|
int red = Color.red(primaryColor);
|
||||||
|
int green = Color.green(primaryColor);
|
||||||
|
int blue = Color.blue(primaryColor);
|
||||||
|
|
||||||
|
colors = new int[4];
|
||||||
|
colors[3] = primaryColor;
|
||||||
|
colors[2] = Color.argb(192, red, green, blue);
|
||||||
|
colors[1] = Color.argb(96, red, green, blue);
|
||||||
|
colors[0] = InterfaceUtils.getStyledColor(getContext(),
|
||||||
|
R.attr.lowContrastTextColor);
|
||||||
|
textColor = InterfaceUtils.getStyledColor(getContext(),
|
||||||
|
R.attr.mediumContrastTextColor);
|
||||||
|
reverseTextColor = InterfaceUtils.getStyledColor(getContext(),
|
||||||
|
R.attr.highContrastReverseTextColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawRow(Canvas canvas, Streak streak, RectF rect)
|
||||||
|
{
|
||||||
|
if (maxLength == 0) return;
|
||||||
|
|
||||||
|
float percentage = (float) streak.getLength() / maxLength;
|
||||||
|
float availableWidth = width - 2 * maxLabelWidth;
|
||||||
|
if (shouldShowLabels) availableWidth -= 2 * textMargin;
|
||||||
|
|
||||||
|
float barWidth = percentage * availableWidth;
|
||||||
|
float minBarWidth =
|
||||||
|
paint.measureText(Long.toString(streak.getLength())) + em;
|
||||||
|
barWidth = Math.max(barWidth, minBarWidth);
|
||||||
|
|
||||||
|
float gap = (width - barWidth) / 2;
|
||||||
|
float paddingTopBottom = baseSize * 0.05f;
|
||||||
|
|
||||||
|
paint.setColor(percentageToColor(percentage));
|
||||||
|
|
||||||
|
canvas.drawRect(rect.left + gap, rect.top + paddingTopBottom,
|
||||||
|
rect.right - gap, rect.bottom - paddingTopBottom, paint);
|
||||||
|
|
||||||
|
float yOffset = rect.centerY() + 0.3f * em;
|
||||||
|
|
||||||
|
paint.setColor(reverseTextColor);
|
||||||
|
paint.setTextAlign(Paint.Align.CENTER);
|
||||||
|
canvas.drawText(Long.toString(streak.getLength()), rect.centerX(),
|
||||||
|
yOffset, paint);
|
||||||
|
|
||||||
|
if (shouldShowLabels)
|
||||||
|
{
|
||||||
|
String startLabel = dateFormat.format(new Date(streak.getStart()));
|
||||||
|
String endLabel = dateFormat.format(new Date(streak.getEnd()));
|
||||||
|
|
||||||
|
paint.setColor(textColor);
|
||||||
|
paint.setTextAlign(Paint.Align.RIGHT);
|
||||||
|
canvas.drawText(startLabel, gap - textMargin, yOffset, paint);
|
||||||
|
|
||||||
|
paint.setTextAlign(Paint.Align.LEFT);
|
||||||
|
canvas.drawText(endLabel, width - gap + textMargin, yOffset, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
createPaints();
|
||||||
|
createColors();
|
||||||
|
|
||||||
|
streaks = Collections.emptyList();
|
||||||
|
|
||||||
|
dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
rect = new RectF();
|
||||||
|
maxStreakCount = 10;
|
||||||
|
baseSize = getResources().getDimensionPixelSize(R.dimen.baseSize);
|
||||||
|
}
|
||||||
|
|
||||||
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 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.*;
|
||||||
import org.isoron.uhabits.utils.ColorUtils;
|
import org.isoron.uhabits.utils.*;
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils;
|
|
||||||
|
import static 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBackgroundColor(int backgroundColor)
|
||||||
|
{
|
||||||
|
this.backgroundColor = backgroundColor;
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
public void setColor(int color)
|
public void setColor(int color)
|
||||||
{
|
{
|
||||||
this.color = color;
|
this.color = color;
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTextSize(float textSize)
|
public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
|
||||||
{
|
{
|
||||||
this.textSize = textSize;
|
this.isTransparencyEnabled = isTransparencyEnabled;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBackgroundColor(int backgroundColor)
|
|
||||||
{
|
|
||||||
this.backgroundColor = backgroundColor;
|
|
||||||
postInvalidate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPercentage(float percentage)
|
public void setPercentage(float percentage)
|
||||||
@@ -133,34 +140,68 @@ 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();
|
this.textSize = textSize;
|
||||||
pRing.setAntiAlias(true);
|
}
|
||||||
|
|
||||||
|
public void setThickness(float thickness)
|
||||||
|
{
|
||||||
|
this.thickness = thickness;
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas)
|
||||||
|
{
|
||||||
|
super.onDraw(canvas);
|
||||||
|
Canvas activeCanvas;
|
||||||
|
|
||||||
|
if (isTransparencyEnabled)
|
||||||
|
{
|
||||||
|
if (drawingCache == null) reallocateCache();
|
||||||
|
activeCanvas = cacheCanvas;
|
||||||
|
drawingCache.eraseColor(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activeCanvas = canvas;
|
||||||
|
}
|
||||||
|
|
||||||
pRing.setColor(color);
|
pRing.setColor(color);
|
||||||
pRing.setTextAlign(Paint.Align.CENTER);
|
rect.set(0, 0, diameter, diameter);
|
||||||
|
|
||||||
if(backgroundColor == null)
|
float angle = 360 * Math.round(percentage / precision) * precision;
|
||||||
backgroundColor = InterfaceUtils.getStyledColor(getContext(), R.attr.cardBackgroundColor);
|
|
||||||
|
|
||||||
if(inactiveColor == null)
|
activeCanvas.drawArc(rect, -90, angle, true, pRing);
|
||||||
inactiveColor = InterfaceUtils.getStyledColor(getContext(), R.attr.highContrastTextColor);
|
|
||||||
|
|
||||||
inactiveColor = ColorUtils.setAlpha(inactiveColor, 0.1f);
|
pRing.setColor(inactiveColor);
|
||||||
|
activeCanvas.drawArc(rect, angle - 90, 360 - angle, true, pRing);
|
||||||
|
|
||||||
rect = new RectF();
|
if (thickness > 0)
|
||||||
|
{
|
||||||
|
if (isTransparencyEnabled) pRing.setXfermode(XFERMODE_CLEAR);
|
||||||
|
else pRing.setColor(backgroundColor);
|
||||||
|
|
||||||
|
rect.inset(thickness, thickness);
|
||||||
|
activeCanvas.drawArc(rect, 0, 360, true, pRing);
|
||||||
|
pRing.setXfermode(null);
|
||||||
|
|
||||||
|
pRing.setColor(color);
|
||||||
|
pRing.setTextSize(textSize);
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -183,66 +224,34 @@ public class RingView extends View
|
|||||||
{
|
{
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
|
|
||||||
if(isTransparencyEnabled) reallocateCache();
|
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()
|
private void reallocateCache()
|
||||||
{
|
{
|
||||||
if (drawingCache != null) drawingCache.recycle();
|
if (drawingCache != null) drawingCache.recycle();
|
||||||
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
|
drawingCache =
|
||||||
|
Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
|
||||||
cacheCanvas = new Canvas(drawingCache);
|
cacheCanvas = new Canvas(drawingCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas)
|
|
||||||
{
|
|
||||||
super.onDraw(canvas);
|
|
||||||
Canvas activeCanvas;
|
|
||||||
|
|
||||||
if(isTransparencyEnabled)
|
|
||||||
{
|
|
||||||
if(drawingCache == null) reallocateCache();
|
|
||||||
activeCanvas = cacheCanvas;
|
|
||||||
drawingCache.eraseColor(Color.TRANSPARENT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
activeCanvas = canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
pRing.setColor(color);
|
|
||||||
rect.set(0, 0, diameter, diameter);
|
|
||||||
|
|
||||||
float angle = 360 * Math.round(percentage / precision) * precision;
|
|
||||||
|
|
||||||
activeCanvas.drawArc(rect, -90, angle, true, pRing);
|
|
||||||
|
|
||||||
pRing.setColor(inactiveColor);
|
|
||||||
activeCanvas.drawArc(rect, angle - 90, 360 - angle, true, pRing);
|
|
||||||
|
|
||||||
if(thickness > 0)
|
|
||||||
{
|
|
||||||
if(isTransparencyEnabled)
|
|
||||||
pRing.setXfermode(XFERMODE_CLEAR);
|
|
||||||
else
|
|
||||||
pRing.setColor(backgroundColor);
|
|
||||||
|
|
||||||
rect.inset(thickness, thickness);
|
|
||||||
activeCanvas.drawArc(rect, 0, 360, true, pRing);
|
|
||||||
pRing.setXfermode(null);
|
|
||||||
|
|
||||||
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(activeCanvas != canvas)
|
|
||||||
canvas.drawBitmap(drawingCache, 0, 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
|
|
||||||
{
|
|
||||||
this.isTransparencyEnabled = isTransparencyEnabled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 android.widget.FrameLayout;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.*;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.*;
|
||||||
import org.isoron.uhabits.utils.InterfaceUtils;
|
import org.isoron.uhabits.ui.habits.show.views.*;
|
||||||
|
import org.isoron.uhabits.utils.*;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user