ShowHabit: Refactor score chart

pull/145/head
Alinson S. Xavier 9 years ago
parent a060cbe578
commit a11ad6e909

@ -30,9 +30,9 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class HabitFrequencyViewTest extends BaseViewTest public class FrequencyChartTest extends BaseViewTest
{ {
private HabitFrequencyView view; private FrequencyChart view;
@Before @Before
public void setUp() public void setUp()
@ -42,7 +42,7 @@ public class HabitFrequencyViewTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
Habit habit = fixtures.createLongHabit(); Habit habit = fixtures.createLongHabit();
view = new HabitFrequencyView(targetContext); view = new FrequencyChart(targetContext);
view.setHabit(habit); view.setHabit(habit);
refreshData(view); refreshData(view);
measureView(dpToPixels(300), dpToPixels(100), view); measureView(dpToPixels(300), dpToPixels(100), view);

@ -40,7 +40,7 @@ public class HabitHistoryViewTest extends BaseViewTest
{ {
private Habit habit; private Habit habit;
private HabitHistoryView view; private HistoryView view;
@Before @Before
public void setUp() public void setUp()
@ -50,7 +50,7 @@ public class HabitHistoryViewTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
view = new HabitHistoryView(targetContext); view = new HistoryView(targetContext);
view.setHabit(habit); view.setHabit(habit);
measureView(dpToPixels(400), dpToPixels(200), view); measureView(dpToPixels(400), dpToPixels(200), view);
refreshData(view); refreshData(view);

@ -25,18 +25,20 @@ import android.util.Log;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.utils.*;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class HabitScoreViewTest extends BaseViewTest public class ScoreChartTest extends BaseViewTest
{ {
private Habit habit; private Habit habit;
private HabitScoreView view; private ScoreChart view;
@Override
@Before @Before
public void setUp() public void setUp()
{ {
@ -45,10 +47,10 @@ public class HabitScoreViewTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
habit = fixtures.createLongHabit(); habit = fixtures.createLongHabit();
view = new HabitScoreView(targetContext); view = new ScoreChart(targetContext);
view.setHabit(habit); view.setScores(habit.getScores().getAll());
view.setPrimaryColor(ColorUtils.getColor(targetContext, habit.getColor()));
view.setBucketSize(7); view.setBucketSize(7);
refreshData(view);
measureView(dpToPixels(300), dpToPixels(200), view); measureView(dpToPixels(300), dpToPixels(200), view);
} }
@ -79,8 +81,8 @@ public class HabitScoreViewTest extends BaseViewTest
@Test @Test
public void testRender_withMonthlyBucket() throws Throwable public void testRender_withMonthlyBucket() throws Throwable
{ {
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.MONTH));
view.setBucketSize(30); view.setBucketSize(30);
view.refreshData();
view.invalidate(); view.invalidate();
assertRenders(view, "HabitScoreView/renderMonthly.png"); assertRenders(view, "HabitScoreView/renderMonthly.png");
@ -96,8 +98,8 @@ public class HabitScoreViewTest extends BaseViewTest
@Test @Test
public void testRender_withYearlyBucket() throws Throwable public void testRender_withYearlyBucket() throws Throwable
{ {
view.setScores(habit.getScores().groupBy(DateUtils.TruncateField.YEAR));
view.setBucketSize(365); view.setBucketSize(365);
view.refreshData();
view.invalidate(); view.invalidate();
assertRenders(view, "HabitScoreView/renderYearly.png"); assertRenders(view, "HabitScoreView/renderYearly.png");

@ -30,9 +30,9 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class HabitStreakViewTest extends BaseViewTest public class StreakChartTest extends BaseViewTest
{ {
private HabitStreakView view; private StreakChart view;
@Override @Override
@Before @Before
@ -43,7 +43,7 @@ public class HabitStreakViewTest extends BaseViewTest
fixtures.purgeHabits(habitList); fixtures.purgeHabits(habitList);
Habit habit = fixtures.createLongHabit(); Habit habit = fixtures.createLongHabit();
view = new HabitStreakView(targetContext); view = new StreakChart(targetContext);
measureView(dpToPixels(300), dpToPixels(100), view); measureView(dpToPixels(300), dpToPixels(100), view);
view.setHabit(habit); view.setHabit(habit);

@ -44,6 +44,7 @@ public class MemoryScoreList extends ScoreList
if (s.getTimestamp() >= timestamp) discard.add(s); if (s.getTimestamp() >= timestamp) discard.add(s);
list.removeAll(discard); list.removeAll(discard);
getObservable().notifyListeners();
} }
@Override @Override

@ -134,6 +134,8 @@ public class SQLiteScoreList extends ScoreList
.where("habit = ?", habit.getId()) .where("habit = ?", habit.getId())
.and("timestamp >= ?", timestamp) .and("timestamp >= ?", timestamp)
.execute(); .execute();
getObservable().notifyListeners();
} }
@Nullable @Nullable

@ -32,7 +32,7 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList; import org.isoron.uhabits.models.HabitList;
import org.isoron.uhabits.tasks.BaseTask; import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.ui.habits.show.views.HabitHistoryView; import org.isoron.uhabits.ui.habits.show.views.HistoryView;
import javax.inject.Inject; import javax.inject.Inject;
@ -43,7 +43,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
private Listener listener; private Listener listener;
HabitHistoryView historyView; HistoryView historyView;
@Inject @Inject
HabitList habitList; HabitList habitList;
@ -53,7 +53,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
{ {
Context context = getActivity(); Context context = getActivity();
HabitsApplication.getComponent().inject(this); HabitsApplication.getComponent().inject(this);
historyView = new HabitHistoryView(context, null); historyView = new HistoryView(context, null);
if (savedInstanceState != null) if (savedInstanceState != null)
{ {

@ -22,13 +22,11 @@ package org.isoron.uhabits.ui.habits.show;
import android.os.*; import android.os.*;
import android.support.v4.app.*; import android.support.v4.app.*;
import android.view.*; import android.view.*;
import android.widget.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.edit.*; import org.isoron.uhabits.ui.habits.edit.*;
import org.isoron.uhabits.ui.habits.show.views.*; import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.utils.*;
import java.util.*; import java.util.*;
@ -39,44 +37,33 @@ public class ShowHabitFragment extends Fragment
{ {
Habit habit; Habit habit;
float todayScore;
float lastMonthScore;
float lastYearScore;
int activeColor; int activeColor;
int inactiveColor; int inactiveColor;
int previousScoreInterval;
private ShowHabitHelper helper; private ShowHabitHelper helper;
protected ShowHabitActivity activity; protected ShowHabitActivity activity;
private List<HabitDataView> dataViews; private List<HabitDataView> dataViews;
@BindView(R.id.sStrengthInterval)
Spinner sStrengthInterval;
@BindView(R.id.scoreView)
HabitScoreView habitScoreView;
@BindView(R.id.historyView) @BindView(R.id.historyView)
HabitHistoryView habitHistoryView; HistoryView historyView;
@BindView(R.id.punchcardView) @BindView(R.id.punchcardView)
HabitFrequencyView habitFrequencyView; FrequencyChart frequencyChart;
@BindView(R.id.streakChart)
StreakChart streakChart;
@BindView(R.id.streakView) @BindView(R.id.subtitleCard)
HabitStreakView habitStreakView; SubtitleCard subtitleCard;
@BindView(R.id.subtitle) @BindView(R.id.overviewCard)
SubtitleCardView subtitleView; OverviewCard overviewCard;
@BindView(R.id.overview) @BindView(R.id.strengthCard)
OverviewCardView overview; ScoreCard scoreCard;
@Override @Override
public View onCreateView(LayoutInflater inflater, public View onCreateView(LayoutInflater inflater,
@ -92,15 +79,6 @@ public class ShowHabitFragment extends Fragment
habit = activity.getHabit(); habit = activity.getHabit();
helper.updateColors(); helper.updateColors();
int defaultScoreInterval =
InterfaceUtils.getDefaultScoreInterval(getContext());
previousScoreInterval = defaultScoreInterval;
setScoreBucketSize(defaultScoreInterval);
sStrengthInterval.setSelection(defaultScoreInterval);
sStrengthInterval.setOnItemSelectedListener(
new OnItemSelectedListener());
createDataViews(); createDataViews();
helper.updateCardHeaders(view); helper.updateCardHeaders(view);
setHasOptionsMenu(true); setHasOptionsMenu(true);
@ -118,14 +96,14 @@ public class ShowHabitFragment extends Fragment
private void createDataViews() private void createDataViews()
{ {
subtitleView.setHabit(habit); subtitleCard.setHabit(habit);
overview.setHabit(habit); overviewCard.setHabit(habit);
scoreCard.setHabit(habit);
dataViews = new LinkedList<>(); dataViews = new LinkedList<>();
dataViews.add(habitScoreView); dataViews.add(historyView);
dataViews.add(habitHistoryView); dataViews.add(frequencyChart);
dataViews.add(habitFrequencyView); dataViews.add(streakChart);
dataViews.add(habitStreakView);
for (HabitDataView dataView : dataViews) for (HabitDataView dataView : dataViews)
dataView.setHabit(habit); dataView.setHabit(habit);
@ -156,17 +134,6 @@ public class ShowHabitFragment extends Fragment
return true; return true;
} }
private void setScoreBucketSize(int position)
{
if (getView() == null) return;
habitScoreView.setBucketSize(
HabitScoreView.DEFAULT_BUCKET_SIZES[position]);
InterfaceUtils.setDefaultScoreInterval(getContext(), position);
previousScoreInterval = position;
}
@Override @Override
public void onModelChange() public void onModelChange()
{ {
@ -190,23 +157,4 @@ public class ShowHabitFragment extends Fragment
habit.getObservable().removeListener(this); habit.getObservable().removeListener(this);
super.onPause(); super.onPause();
} }
private class OnItemSelectedListener
implements AdapterView.OnItemSelectedListener
{
@Override
public void onItemSelected(AdapterView<?> parent,
View view,
int position,
long id)
{
setScoreBucketSize(position);
}
@Override
public void onNothingSelected(AdapterView<?> parent)
{
}
}
} }

@ -37,7 +37,6 @@ public class ShowHabitHelper
void updateCardHeaders(View view) void updateCardHeaders(View view)
{ {
updateColor(view, R.id.tvHistory); updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvStrength);
updateColor(view, R.id.tvStreaks); updateColor(view, R.id.tvStreaks);
updateColor(view, R.id.tvWeekdayFreq); updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel); updateColor(view, R.id.scoreLabel);

@ -31,7 +31,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
public class HabitFrequencyView extends ScrollableDataView public class FrequencyChart extends ScrollableChart
implements HabitDataView, ModelObservable.Listener implements HabitDataView, ModelObservable.Listener
{ {
private Paint pGrid; private Paint pGrid;
@ -70,13 +70,13 @@ public class HabitFrequencyView extends ScrollableDataView
private HashMap<Long, Integer[]> frequency; private HashMap<Long, Integer[]> frequency;
public HabitFrequencyView(Context context) public FrequencyChart(Context context)
{ {
super(context); super(context);
init(); init();
} }
public HabitFrequencyView(Context context, AttributeSet attrs) public FrequencyChart(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
this.primaryColor = ColorUtils.getColor(getContext(), 7); this.primaryColor = ColorUtils.getColor(getContext(), 7);

@ -33,8 +33,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
public class HabitHistoryView extends ScrollableDataView implements public class HistoryView extends ScrollableChart implements HabitDataView,
HabitDataView,
ToggleRepetitionTask.Listener, ToggleRepetitionTask.Listener,
ModelObservable.Listener ModelObservable.Listener
{ {
@ -89,13 +88,13 @@ public class HabitHistoryView extends ScrollableDataView implements
private float headerOverflow = 0; private float headerOverflow = 0;
public HabitHistoryView(Context context) public HistoryView(Context context)
{ {
super(context); super(context);
init(); init();
} }
public HabitHistoryView(Context context, AttributeSet attrs) public HistoryView(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
init(); init();
@ -169,6 +168,7 @@ public class HabitHistoryView extends ScrollableDataView implements
postInvalidate(); postInvalidate();
} }
@Override
public void setHabit(Habit habit) public void setHabit(Habit habit)
{ {
this.habit = habit; this.habit = habit;

@ -31,7 +31,7 @@ import org.isoron.uhabits.utils.*;
import butterknife.*; import butterknife.*;
public class OverviewCardView extends LinearLayout public class OverviewCard extends LinearLayout
implements ModelObservable.Listener implements ModelObservable.Listener
{ {
@Nullable @Nullable
@ -57,13 +57,13 @@ public class OverviewCardView extends LinearLayout
private int color; private int color;
public OverviewCardView(Context context) public OverviewCard(Context context)
{ {
super(context); super(context);
init(); init();
} }
public OverviewCardView(Context context, AttributeSet attrs) public OverviewCard(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
init(); init();

@ -0,0 +1,198 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
import android.content.*;
import android.support.annotation.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import butterknife.*;
public class ScoreCard extends RelativeLayout
implements ModelObservable.Listener
{
public static final int[] BUCKET_SIZES = { 1, 7, 31, 92, 365 };
@BindView(R.id.spinner)
Spinner spinner;
@BindView(R.id.scoreView)
ScoreChart chart;
@BindView(R.id.title)
TextView title;
@Nullable
private Habit habit;
private int color;
private int bucketSize;
public ScoreCard(Context context)
{
super(context);
init();
}
public ScoreCard(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
@OnItemSelected(R.id.spinner)
public void onItemSelected(int position)
{
setBucketSizeFromPosition(position);
}
@Override
public void onModelChange()
{
refreshData();
}
public void setHabit(@NonNull Habit habit)
{
this.habit = habit;
color = ColorUtils.getColor(getContext(), habit.getColor());
refreshData();
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
if (habit != null)
{
habit.getObservable().addListener(this);
habit.getScores().getObservable().addListener(this);
}
}
@Override
protected void onDetachedFromWindow()
{
if (habit != null)
{
habit.getObservable().removeListener(this);
habit.getScores().getObservable().removeListener(this);
}
super.onDetachedFromWindow();
}
@NonNull
private DateUtils.TruncateField getTruncateField()
{
DateUtils.TruncateField field;
switch (bucketSize)
{
case 7:
field = DateUtils.TruncateField.WEEK_NUMBER;
break;
case 365:
field = DateUtils.TruncateField.YEAR;
break;
case 92:
field = DateUtils.TruncateField.QUARTER;
break;
default:
Log.e("ScoreCard",
String.format("Unknown bucket size: %d", bucketSize));
// continue to case 31
case 31:
field = DateUtils.TruncateField.MONTH;
break;
}
return field;
}
private void init()
{
inflate(getContext(), R.layout.show_habit_strength, this);
ButterKnife.bind(this);
int defaultPosition = getDefaultSpinnerPosition();
setBucketSizeFromPosition(defaultPosition);
spinner.setSelection(defaultPosition);
if(isInEditMode())
{
spinner.setVisibility(GONE);
title.setTextColor(ColorUtils.getAndroidTestColor(1));
chart.setPrimaryColor(ColorUtils.getAndroidTestColor(1));
chart.populateWithRandomData();
}
}
private int getDefaultSpinnerPosition()
{
if(isInEditMode()) return 0;
return InterfaceUtils.getDefaultScoreSpinnerPosition(getContext());
}
private void refreshData()
{
if (habit == null) return;
title.setTextColor(color);
chart.setPrimaryColor(color);
new BaseTask()
{
@Override
protected void doInBackground()
{
List<Score> scores;
if (bucketSize == 1) scores = habit.getScores().getAll();
else scores = habit.getScores().groupBy(getTruncateField());
chart.setScores(scores);
chart.setBucketSize(bucketSize);
}
}.execute();
}
private void setBucketSizeFromPosition(int position)
{
if(isInEditMode()) return;
InterfaceUtils.setDefaultScoreSpinnerPosition(getContext(), position);
bucketSize = BUCKET_SIZES[position];
refreshData();
}
}

@ -26,14 +26,12 @@ import android.util.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*; import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
public class HabitScoreView extends ScrollableDataView public class ScoreChart extends ScrollableChart
implements HabitDataView, ModelObservable.Listener
{ {
private static final PorterDuffXfermode XFERMODE_CLEAR = private static final PorterDuffXfermode XFERMODE_CLEAR =
new PorterDuffXfermode(PorterDuff.Mode.CLEAR); new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
@ -41,14 +39,10 @@ public class HabitScoreView extends ScrollableDataView
private static final PorterDuffXfermode XFERMODE_SRC = private static final PorterDuffXfermode XFERMODE_SRC =
new PorterDuffXfermode(PorterDuff.Mode.SRC); new PorterDuffXfermode(PorterDuff.Mode.SRC);
public static int DEFAULT_BUCKET_SIZES[] = {1, 7, 31, 92, 365};
private Paint pGrid; private Paint pGrid;
private float em; private float em;
private Habit habit;
private SimpleDateFormat dfMonth; private SimpleDateFormat dfMonth;
private SimpleDateFormat dfDay; private SimpleDateFormat dfDay;
@ -80,8 +74,6 @@ public class HabitScoreView extends ScrollableDataView
private int bucketSize = 7; private int bucketSize = 7;
private int footerHeight;
private int backgroundColor; private int backgroundColor;
private Bitmap drawingCache; private Bitmap drawingCache;
@ -96,58 +88,42 @@ public class HabitScoreView extends ScrollableDataView
private String previousMonthText; private String previousMonthText;
public HabitScoreView(Context context) public ScoreChart(Context context)
{ {
super(context); super(context);
init(); init();
} }
public HabitScoreView(Context context, AttributeSet attrs) public ScoreChart(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
this.primaryColor = ColorUtils.getColor(getContext(), 7);
init(); init();
} }
@Override @Deprecated
public void onModelChange() public void setBucketSize(int bucketSize)
{
refreshData();
}
@Override
public void refreshData()
{
if (isInEditMode()) generateRandomData();
else
{ {
if (habit == null) return; this.bucketSize = bucketSize;
if (bucketSize == 1) scores = habit.getScores().getAll();
else scores = habit.getScores().groupBy(getTruncateField());
createColors();
}
postInvalidate(); postInvalidate();
} }
public void setBucketSize(int bucketSize) public void setIsTransparencyEnabled(boolean enabled)
{ {
this.bucketSize = bucketSize; this.isTransparencyEnabled = enabled;
createColors();
requestLayout();
} }
@Override public void setPrimaryColor(int primaryColor)
public void setHabit(Habit habit)
{ {
this.habit = habit; this.primaryColor = primaryColor;
createColors(); postInvalidate();
} }
public void setIsTransparencyEnabled(boolean enabled) public void setScores(@NonNull List<Score> scores)
{ {
this.isTransparencyEnabled = enabled; this.scores = scores;
createColors(); postInvalidate();
requestLayout();
} }
protected void createPaints() protected void createPaints()
@ -163,30 +139,6 @@ 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 @Override
protected void onDraw(Canvas canvas) protected void onDraw(Canvas canvas)
{ {
@ -205,7 +157,7 @@ public class HabitScoreView extends ScrollableDataView
activeCanvas = canvas; activeCanvas = canvas;
} }
if (habit == null || scores == null) return; if (scores == null) return;
rect.set(0, 0, nColumns * columnWidth, columnHeight); rect.set(0, 0, nColumns * columnWidth, columnHeight);
rect.offset(0, paddingTop); rect.offset(0, paddingTop);
@ -220,16 +172,13 @@ public class HabitScoreView extends ScrollableDataView
previousYearText = ""; previousYearText = "";
skipYear = 0; 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++) for (int k = 0; k < nColumns; k++)
{ {
int score = 0;
int offset = nColumns - k - 1 + getDataOffset(); int offset = nColumns - k - 1 + getDataOffset();
if (offset < scores.size()) score = scores.get(offset).getValue(); if (offset >= scores.size()) continue;
int score = scores.get(offset).getValue();
long timestamp = scores.get(offset).getTimestamp();
double relativeScore = ((double) score) / Score.MAX_VALUE; double relativeScore = ((double) score) / Score.MAX_VALUE;
int height = (int) (columnHeight * relativeScore); int height = (int) (columnHeight * relativeScore);
@ -250,9 +199,7 @@ public class HabitScoreView extends ScrollableDataView
rect.set(0, 0, columnWidth, columnHeight); rect.set(0, 0, columnWidth, columnHeight);
rect.offset(k * columnWidth, paddingTop); rect.offset(k * columnWidth, paddingTop);
drawFooter(activeCanvas, rect, currentDate); drawFooter(activeCanvas, rect, timestamp);
currentDate += bucketSize * DateUtils.millisecondsInOneDay;
} }
if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null); if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null);
@ -279,18 +226,17 @@ public class HabitScoreView extends ScrollableDataView
pText.setTextSize(Math.min(textSize, maxTextSize)); pText.setTextSize(Math.min(textSize, maxTextSize));
em = pText.getFontSpacing(); em = pText.getFontSpacing();
footerHeight = (int) (3 * em); int footerHeight = (int) (3 * em);
paddingTop = (int) (em); paddingTop = (int) (em);
baseSize = (height - footerHeight - paddingTop) / 8; baseSize = (height - footerHeight - paddingTop) / 8;
setScrollerBucketSize(baseSize);
columnWidth = baseSize; columnWidth = baseSize;
columnWidth = Math.max(columnWidth, getMaxDayWidth() * 1.5f); columnWidth = Math.max(columnWidth, getMaxDayWidth() * 1.5f);
columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f); columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f);
nColumns = (int) (width / columnWidth); nColumns = (int) (width / columnWidth);
columnWidth = (float) width / nColumns; columnWidth = (float) width / nColumns;
setScrollerBucketSize((int) columnWidth);
columnHeight = 8 * baseSize; columnHeight = 8 * baseSize;
@ -304,9 +250,7 @@ public class HabitScoreView extends ScrollableDataView
private void createColors() private void createColors()
{ {
if (habit != null) this.primaryColor = primaryColor = Color.BLACK;
ColorUtils.getColor(getContext(), habit.getColor());
textColor = InterfaceUtils.getStyledColor(getContext(), textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor); R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(), gridColor = InterfaceUtils.getStyledColor(getContext(),
@ -411,7 +355,7 @@ public class HabitScoreView extends ScrollableDataView
if (isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC); if (isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC);
} }
private void generateRandomData() public void populateWithRandomData()
{ {
Random random = new Random(); Random random = new Random();
scores = new LinkedList<>(); scores = new LinkedList<>();
@ -461,38 +405,6 @@ public class HabitScoreView extends ScrollableDataView
return maxMonthWidth; return maxMonthWidth;
} }
@NonNull
private DateUtils.TruncateField getTruncateField()
{
DateUtils.TruncateField field;
switch (bucketSize)
{
case 7:
field = DateUtils.TruncateField.WEEK_NUMBER;
break;
case 365:
field = DateUtils.TruncateField.YEAR;
break;
case 92:
field = DateUtils.TruncateField.QUARTER;
break;
default:
Log.e("HabitScoreView",
String.format("Unknown bucket size: %d", bucketSize));
// continue to case 31
case 31:
field = DateUtils.TruncateField.MONTH;
break;
}
return field;
}
private void init() private void init()
{ {
createPaints(); createPaints();

@ -25,7 +25,7 @@ import android.util.*;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
public abstract class ScrollableDataView extends View public abstract class ScrollableChart extends View
implements GestureDetector.OnGestureListener, implements GestureDetector.OnGestureListener,
ValueAnimator.AnimatorUpdateListener ValueAnimator.AnimatorUpdateListener
{ {
@ -40,13 +40,13 @@ public abstract class ScrollableDataView extends View
private ValueAnimator scrollAnimator; private ValueAnimator scrollAnimator;
public ScrollableDataView(Context context) public ScrollableChart(Context context)
{ {
super(context); super(context);
init(context); init(context);
} }
public ScrollableDataView(Context context, AttributeSet attrs) public ScrollableChart(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
init(context); init(context);

@ -32,7 +32,7 @@ import org.isoron.uhabits.utils.*;
import java.text.*; import java.text.*;
import java.util.*; import java.util.*;
public class HabitStreakView extends View public class StreakChart extends View
implements HabitDataView, ModelObservable.Listener implements HabitDataView, ModelObservable.Listener
{ {
private Habit habit; private Habit habit;
@ -73,13 +73,13 @@ public class HabitStreakView extends View
private int reverseTextColor; private int reverseTextColor;
public HabitStreakView(Context context) public StreakChart(Context context)
{ {
super(context); super(context);
init(); init();
} }
public HabitStreakView(Context context, AttributeSet attrs) public StreakChart(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
this.primaryColor = ColorUtils.getColor(getContext(), 7); this.primaryColor = ColorUtils.getColor(getContext(), 7);

@ -33,7 +33,7 @@ import org.isoron.uhabits.utils.*;
import butterknife.*; import butterknife.*;
public class SubtitleCardView extends LinearLayout public class SubtitleCard extends LinearLayout
implements ModelObservable.Listener implements ModelObservable.Listener
{ {
@BindView(R.id.questionLabel) @BindView(R.id.questionLabel)
@ -48,13 +48,13 @@ public class SubtitleCardView extends LinearLayout
@Nullable @Nullable
private Habit habit; private Habit habit;
public SubtitleCardView(Context context) public SubtitleCard(Context context)
{ {
super(context); super(context);
init(); init();
} }
public SubtitleCardView(Context context, AttributeSet attrs) public SubtitleCard(Context context, AttributeSet attrs)
{ {
super(context, attrs); super(context, attrs);
init(); init();

@ -269,13 +269,13 @@ public abstract class InterfaceUtils
} }
public static void setDefaultScoreInterval(Context context, int position) public static void setDefaultScoreSpinnerPosition(Context context, int position)
{ {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putInt("pref_score_view_interval", position).apply(); prefs.edit().putInt("pref_score_view_interval", position).apply();
} }
public static int getDefaultScoreInterval(Context context) public static int getDefaultScoreSpinnerPosition(Context context)
{ {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
int defaultScoreInterval = prefs.getInt("pref_score_view_interval", 1); int defaultScoreInterval = prefs.getInt("pref_score_view_interval", 1);

@ -28,14 +28,14 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView; import org.isoron.uhabits.widgets.views.GraphWidgetView;
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.HabitFrequencyView; import org.isoron.uhabits.ui.habits.show.views.FrequencyChart;
public class FrequencyWidgetProvider extends BaseWidgetProvider public class FrequencyWidgetProvider extends BaseWidgetProvider
{ {
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitFrequencyView dataView = new HabitFrequencyView(context); FrequencyChart dataView = new FrequencyChart(context);
GraphWidgetView view = new GraphWidgetView(context, dataView); GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;

@ -27,14 +27,14 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView; import org.isoron.uhabits.widgets.views.GraphWidgetView;
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.HabitHistoryView; import org.isoron.uhabits.ui.habits.show.views.HistoryView;
public class HistoryWidgetProvider extends BaseWidgetProvider public class HistoryWidgetProvider extends BaseWidgetProvider
{ {
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitHistoryView dataView = new HabitHistoryView(context); HistoryView dataView = new HistoryView(context);
GraphWidgetView view = new GraphWidgetView(context, dataView); GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;

@ -18,33 +18,33 @@
*/ */
package org.isoron.uhabits.widgets; package org.isoron.uhabits.widgets;
import android.app.PendingIntent; import android.app.*;
import android.content.Context; import android.content.*;
import android.view.View; import android.view.*;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.apache.commons.lang3.*;
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.widgets.views.GraphWidgetView; import org.isoron.uhabits.utils.*;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.HabitScoreView;
public class ScoreWidgetProvider extends BaseWidgetProvider public class ScoreWidgetProvider extends BaseWidgetProvider
{ {
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
int defaultScoreInterval = InterfaceUtils.getDefaultScoreInterval(context); int defaultScoreInterval = InterfaceUtils.getDefaultScoreSpinnerPosition(context);
int size = HabitScoreView.DEFAULT_BUCKET_SIZES[defaultScoreInterval]; int size = ScoreCard.BUCKET_SIZES[defaultScoreInterval];
HabitScoreView dataView = new HabitScoreView(context); ScoreChart dataView = new ScoreChart(context);
dataView.setIsTransparencyEnabled(true); dataView.setIsTransparencyEnabled(true);
dataView.setBucketSize(size); dataView.setBucketSize(size);
GraphWidgetView view = new GraphWidgetView(context, dataView); // GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); // view.setHabit(habit);
return view; // return view;
throw new NotImplementedException("");
} }
@Override @Override

@ -27,14 +27,14 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView; import org.isoron.uhabits.widgets.views.GraphWidgetView;
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.HabitStreakView; import org.isoron.uhabits.ui.habits.show.views.StreakChart;
public class StreakWidgetProvider extends BaseWidgetProvider public class StreakWidgetProvider extends BaseWidgetProvider
{ {
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitStreakView dataView = new HabitStreakView(context); StreakChart dataView = new StreakChart(context);
GraphWidgetView view = new GraphWidgetView(context, dataView); GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;

@ -31,49 +31,23 @@
style="@style/CardList" style="@style/CardList"
android:clipToPadding="false"> android:clipToPadding="false">
<org.isoron.uhabits.ui.habits.show.views.SubtitleCardView <org.isoron.uhabits.ui.habits.show.views.SubtitleCard
style="@style/ShowHabit.Subtitle" style="@style/ShowHabit.Subtitle"
android:id="@+id/subtitle"/> android:id="@+id/subtitleCard"/>
<!--<View--> <!--<View-->
<!--android:id="@+id/headerShadow"--> <!--android:id="@+id/headerShadow"-->
<!--style="@style/ToolbarShadow"/>--> <!--style="@style/ToolbarShadow"/>-->
<org.isoron.uhabits.ui.habits.show.views.OverviewCardView <org.isoron.uhabits.ui.habits.show.views.OverviewCard
android:id="@+id/overview" android:id="@+id/overviewCard"
android:paddingTop="12dp" android:paddingTop="12dp"
style="@style/Card" /> style="@style/Card" />
<RelativeLayout <org.isoron.uhabits.ui.habits.show.views.ScoreCard
android:id="@+id/strengthCard"
style="@style/Card" style="@style/Card"
android:gravity="center"> android:gravity="center" />
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/sStrengthInterval"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:entries="@array/strengthIntervalNames"
android:theme="@style/SmallSpinner"
/>
<TextView
android:id="@+id/tvStrength"
style="@style/CardHeader"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/habit_strength"/>
<org.isoron.uhabits.ui.habits.show.views.HabitScoreView
android:id="@+id/scoreView"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_below="@id/tvStrength"/>
</RelativeLayout>
<LinearLayout <LinearLayout
style="@style/Card" style="@style/Card"
@ -86,7 +60,7 @@
style="@style/CardHeader" style="@style/CardHeader"
android:text="@string/history"/> android:text="@string/history"/>
<org.isoron.uhabits.ui.habits.show.views.HabitHistoryView <org.isoron.uhabits.ui.habits.show.views.HistoryView
android:id="@+id/historyView" android:id="@+id/historyView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="160dp"/> android:layout_height="160dp"/>
@ -113,8 +87,8 @@
style="@style/CardHeader" style="@style/CardHeader"
android:text="@string/best_streaks"/> android:text="@string/best_streaks"/>
<org.isoron.uhabits.ui.habits.show.views.HabitStreakView <org.isoron.uhabits.ui.habits.show.views.StreakChart
android:id="@+id/streakView" android:id="@+id/streakChart"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp"/> android:layout_height="200dp"/>
</LinearLayout> </LinearLayout>
@ -128,7 +102,7 @@
style="@style/CardHeader" style="@style/CardHeader"
android:text="@string/frequency"/> android:text="@string/frequency"/>
<org.isoron.uhabits.ui.habits.show.views.HabitFrequencyView <org.isoron.uhabits.ui.habits.show.views.FrequencyChart
android:id="@+id/punchcardView" android:id="@+id/punchcardView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp"/> android:layout_height="200dp"/>

@ -20,7 +20,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?windowBackgroundColor" android:background="?windowBackgroundColor"
@ -31,24 +30,28 @@
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
style="@style/Toolbar" style="@style/Toolbar"
app:title="Meditation"
android:background="@color/deep_orange_700" android:background="@color/deep_orange_700"
android:elevation="1dp"
app:popupTheme="?toolbarPopupTheme" app:popupTheme="?toolbarPopupTheme"
android:elevation="1dp"/> app:title="Meditation"/>
<LinearLayout <LinearLayout
style="@style/CardList" style="@style/CardList"
android:clipToPadding="false"> android:clipToPadding="false">
<org.isoron.uhabits.ui.habits.show.views.SubtitleCardView <org.isoron.uhabits.ui.habits.show.views.SubtitleCard
android:id="@+id/subtitleView" android:id="@+id/subtitleView"
style="@style/ShowHabit.Subtitle" style="@style/ShowHabit.Subtitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<org.isoron.uhabits.ui.habits.show.views.OverviewCardView <org.isoron.uhabits.ui.habits.show.views.OverviewCard
android:paddingTop="12dp" style="@style/Card"
style="@style/Card" /> android:paddingTop="12dp"/>
<org.isoron.uhabits.ui.habits.show.views.ScoreCard
style="@style/Card"
android:paddingTop="12dp"/>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
~
~ This file is part of Loop Habit Tracker.
~
~ Loop Habit Tracker is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by the
~ Free Software Foundation, either version 3 of the License, or (at your
~ option) any later version.
~
~ Loop Habit Tracker is distributed in the hope that it will be useful, but
~ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
~ more details.
~
~ You should have received a copy of the GNU General Public License along
~ with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:entries="@array/strengthIntervalNames"
android:theme="@style/SmallSpinner"
/>
<TextView
android:id="@+id/title"
style="@style/CardHeader"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/habit_strength"/>
<org.isoron.uhabits.ui.habits.show.views.ScoreChart
android:id="@+id/scoreView"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_below="@id/title"/>
</merge>
Loading…
Cancel
Save