Refactor ShowHabit fragment; break widgets

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

@ -91,3 +91,7 @@ dependencies {
exclude group: 'com.android.support'
}
}
retrolambda {
defaultMethods true
}

@ -24,7 +24,7 @@ import android.os.*;
import android.view.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import java.io.*;
@ -209,7 +209,7 @@ public class BaseViewTest extends BaseAndroidTest
e.recycle();
}
protected void refreshData(final HabitDataView view)
protected void refreshData(final HabitChart view)
{
new BaseTask()
{

@ -135,7 +135,7 @@ public class MainTest
onView(withId(R.id.scoreView)).perform(scrollTo(), swipeRight());
onView(withId(R.id.punchcardView)).perform(scrollTo(), swipeRight());
onView(withId(R.id.frequencyChart)).perform(scrollTo(), swipeRight());
}
/**
@ -234,7 +234,7 @@ public class MainTest
clickAtRandomLocations(20));
pressBack();
onView(withId(R.id.historyView)).perform(scrollTo(), swipeRight(),
onView(withId(R.id.historyChart)).perform(scrollTo(), swipeRight(),
swipeLeft());
}

@ -31,7 +31,7 @@ public class ShowHabitActivityActions
{
public static void openHistoryEditor()
{
onView(ViewMatchers.withId(R.id.btEditHistory))
onView(ViewMatchers.withId(R.id.edit))
.perform(scrollTo(), click());
}
}

@ -22,8 +22,10 @@ package org.isoron.uhabits.ui.habits.show.views;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -43,9 +45,10 @@ public class FrequencyChartTest extends BaseViewTest
Habit habit = fixtures.createLongHabit();
view = new FrequencyChart(targetContext);
view.setHabit(habit);
refreshData(view);
measureView(dpToPixels(300), dpToPixels(100), view);
throw new NotImplementedException("");
// view.setHabit(habit);
// refreshData(view);
// measureView(dpToPixels(300), dpToPixels(100), view);
}
@Test

@ -22,8 +22,10 @@ package org.isoron.uhabits.ui.habits.show.views;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.DateUtils;
import org.junit.Before;
import org.junit.Test;
@ -36,11 +38,11 @@ import static org.hamcrest.Matchers.equalTo;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class HabitHistoryViewTest extends BaseViewTest
public class HabitHistoryChartTest extends BaseViewTest
{
private Habit habit;
private HistoryView view;
private HistoryChart chart;
@Before
public void setUp()
@ -50,10 +52,11 @@ public class HabitHistoryViewTest extends BaseViewTest
fixtures.purgeHabits(habitList);
habit = fixtures.createLongHabit();
view = new HistoryView(targetContext);
view.setHabit(habit);
measureView(dpToPixels(400), dpToPixels(200), view);
refreshData(view);
chart = new HistoryChart(targetContext);
throw new NotImplementedException("");
// chart.setHabit(habit);
// measureView(dpToPixels(400), dpToPixels(200), chart);
// refreshData(chart);
}
@Test
@ -61,10 +64,10 @@ public class HabitHistoryViewTest extends BaseViewTest
{
int expectedCheckmarkValues[] = habit.getCheckmarks().getAllValues();
view.setIsEditable(true);
tap(view, 118, 13); // header
tap(view, 336, 60); // tomorrow's square
tap(view, 370, 60); // right axis
chart.setIsEditable(true);
tap(chart, 118, 13); // header
tap(chart, 336, 60); // tomorrow's square
tap(chart, 370, 60); // right axis
waitForAsyncTasks();
int actualCheckmarkValues[] = habit.getCheckmarks().getAllValues();
@ -74,8 +77,8 @@ public class HabitHistoryViewTest extends BaseViewTest
@Test
public void tapDate_withEditableView() throws Throwable
{
view.setIsEditable(true);
tap(view, 340, 40); // today's square
chart.setIsEditable(true);
tap(chart, 340, 40); // today's square
waitForAsyncTasks();
long today = DateUtils.getStartOfToday();
@ -85,8 +88,8 @@ public class HabitHistoryViewTest extends BaseViewTest
@Test
public void tapDate_withReadOnlyView() throws Throwable
{
view.setIsEditable(false);
tap(view, 340, 40); // today's square
chart.setIsEditable(false);
tap(chart, 340, 40); // today's square
waitForAsyncTasks();
long today = DateUtils.getStartOfToday();
@ -96,30 +99,29 @@ public class HabitHistoryViewTest extends BaseViewTest
@Test
public void testRender() throws Throwable
{
assertRenders(view, "HabitHistoryView/render.png");
assertRenders(chart, "HabitHistoryView/render.png");
}
@Test
public void testRender_withDataOffset() throws Throwable
{
view.onScroll(null, null, -dpToPixels(150), 0);
view.invalidate();
chart.onScroll(null, null, -dpToPixels(150), 0);
chart.invalidate();
assertRenders(view, "HabitHistoryView/renderDataOffset.png");
assertRenders(chart, "HabitHistoryView/renderDataOffset.png");
}
@Test
public void testRender_withDifferentSize() throws Throwable
{
measureView(dpToPixels(200), dpToPixels(200), view);
assertRenders(view, "HabitHistoryView/renderDifferentSize.png");
measureView(dpToPixels(200), dpToPixels(200), chart);
assertRenders(chart, "HabitHistoryView/renderDifferentSize.png");
}
@Test
public void testRender_withTransparentBackground() throws Throwable
{
view.setIsBackgroundTransparent(true);
assertRenders(view, "HabitHistoryView/renderTransparent.png");
chart.setIsBackgroundTransparent(true);
assertRenders(chart, "HabitHistoryView/renderTransparent.png");
}
}

@ -25,6 +25,7 @@ import android.util.Log;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import org.junit.Before;
import org.junit.Test;

@ -22,8 +22,10 @@ package org.isoron.uhabits.ui.habits.show.views;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -45,9 +47,10 @@ public class StreakChartTest extends BaseViewTest
view = new StreakChart(targetContext);
measureView(dpToPixels(300), dpToPixels(100), view);
throw new NotImplementedException("");
view.setHabit(habit);
refreshData(view);
// view.setHabit(habit);
// refreshData(view);
}
@Test
@ -60,7 +63,7 @@ public class StreakChartTest extends BaseViewTest
public void testRender_withSmallSize() throws Throwable
{
measureView(dpToPixels(100), dpToPixels(100), view);
refreshData(view);
// refreshData(view);
assertRenders(view, "HabitStreakView/renderSmallSize.png");
}

@ -24,6 +24,7 @@ import android.support.annotation.*;
import org.apache.commons.lang3.builder.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.memory.*;
import java.util.*;
@ -82,14 +83,8 @@ public class Habit
*/
public Habit(Habit model)
{
HabitsApplication.getComponent().inject(this);
copyFrom(model);
checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this);
repetitions = factory.buildRepetitionList(this);
buildLists();
}
/**
@ -100,12 +95,19 @@ public class Habit
*/
public Habit()
{
HabitsApplication.getComponent().inject(this);
this.color = 5;
this.archived = false;
this.frequency = new Frequency(3, 7);
buildLists();
}
private void buildLists()
{
BaseComponent component = HabitsApplication.getComponent();
if(component == null) factory = new MemoryModelFactory();
else component.inject(this);
checkmarks = factory.buildCheckmarkList(this);
streaks = factory.buildStreakList(this);
scores = factory.buildScoreList(this);

@ -27,12 +27,13 @@ import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatDialogFragment;
import android.util.DisplayMetrics;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.HabitsApplication;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.HabitList;
import org.isoron.uhabits.tasks.BaseTask;
import org.isoron.uhabits.ui.habits.show.views.HistoryView;
import org.isoron.uhabits.ui.habits.show.views.charts.HistoryChart;
import javax.inject.Inject;
@ -43,7 +44,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
private Listener listener;
HistoryView historyView;
HistoryChart historyChart;
@Inject
HabitList habitList;
@ -53,7 +54,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
{
Context context = getActivity();
HabitsApplication.getComponent().inject(this);
historyView = new HistoryView(context, null);
historyChart = new HistoryChart(context, null);
if (savedInstanceState != null)
{
@ -63,14 +64,16 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
int padding =
(int) getResources().getDimension(R.dimen.history_editor_padding);
historyView.setPadding(padding, 0, padding, 0);
historyView.setHabit(habit);
historyView.setIsEditable(true);
if(true) throw new NotImplementedException("");
historyChart.setPadding(padding, 0, padding, 0);
// historyChart.setHabit(habit);
historyChart.setIsEditable(true);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder
.setTitle(R.string.history)
.setView(historyView)
.setView(historyChart)
.setPositiveButton(android.R.string.ok, this);
refreshData();
@ -85,7 +88,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
@Override
protected void doInBackground()
{
historyView.refreshData();
// historyChart.refreshData();
}
}.execute();
}
@ -112,8 +115,8 @@ public class HistoryEditorDialog extends AppCompatDialogFragment
public void setHabit(Habit habit)
{
this.habit = habit;
if (historyView != null) historyView.setHabit(habit);
// this.habit = habit;
// if (historyChart != null) historyChart.setHabit(habit);
}
@Override

@ -26,35 +26,21 @@ import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.edit.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import java.util.*;
import org.isoron.uhabits.ui.habits.show.views.cards.*;
import butterknife.*;
public class ShowHabitFragment extends Fragment
implements ModelObservable.Listener
{
Habit habit;
int activeColor;
int inactiveColor;
private ShowHabitHelper helper;
protected ShowHabitActivity activity;
private List<HabitDataView> dataViews;
@BindView(R.id.historyView)
HistoryView historyView;
@BindView(R.id.punchcardView)
FrequencyChart frequencyChart;
@BindView(R.id.frequencyCard)
FrequencyCard frequencyCard;
@BindView(R.id.streakChart)
StreakChart streakChart;
@BindView(R.id.streakCard)
StreakCard streakCard;
@BindView(R.id.subtitleCard)
SubtitleCard subtitleCard;
@ -65,6 +51,15 @@ public class ShowHabitFragment extends Fragment
@BindView(R.id.strengthCard)
ScoreCard scoreCard;
@BindView(R.id.historyCard)
HistoryCard historyCard;
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
// inflater.inflate(R.menu.show_habit_fragment, menu);
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
@ -74,45 +69,17 @@ public class ShowHabitFragment extends Fragment
ButterKnife.bind(this, view);
activity = (ShowHabitActivity) getActivity();
helper = new ShowHabitHelper(this);
habit = activity.getHabit();
helper.updateColors();
createDataViews();
helper.updateCardHeaders(view);
setHasOptionsMenu(true);
return view;
}
@OnClick(R.id.btEditHistory)
public void onClickEditHistory()
{
HistoryEditorDialog frag = new HistoryEditorDialog();
frag.setHabit(habit);
frag.show(getFragmentManager(), "historyEditor");
}
private void createDataViews()
{
subtitleCard.setHabit(habit);
overviewCard.setHabit(habit);
scoreCard.setHabit(habit);
historyCard.setHabit(habit);
streakCard.setHabit(habit);
frequencyCard.setHabit(habit);
dataViews = new LinkedList<>();
dataViews.add(historyView);
dataViews.add(frequencyChart);
dataViews.add(streakChart);
for (HabitDataView dataView : dataViews)
dataView.setHabit(habit);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
// inflater.inflate(R.menu.show_habit_fragment, menu);
setHasOptionsMenu(true);
return view;
}
@Override
@ -124,6 +91,7 @@ public class ShowHabitFragment extends Fragment
return false;
}
private boolean showEditHabitDialog()
{
if (habit == null) return false;
@ -133,28 +101,4 @@ public class ShowHabitFragment extends Fragment
frag.show(getFragmentManager(), "editHabit");
return true;
}
@Override
public void onModelChange()
{
activity.runOnUiThread(() -> {
helper.updateColors();
helper.updateCardHeaders(getView());
if (activity != null) activity.setupHabitActionBar();
});
}
@Override
public void onStart()
{
super.onStart();
habit.getObservable().addListener(this);
}
@Override
public void onPause()
{
habit.getObservable().removeListener(this);
super.onPause();
}
}

@ -1,63 +0,0 @@
/*
* 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;
import android.view.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.utils.*;
public class ShowHabitHelper
{
private ShowHabitFragment fragment;
public ShowHabitHelper(ShowHabitFragment fragment)
{
this.fragment = fragment;
}
void updateCardHeaders(View view)
{
updateColor(view, R.id.tvHistory);
updateColor(view, R.id.tvStreaks);
updateColor(view, R.id.tvWeekdayFreq);
updateColor(view, R.id.scoreLabel);
}
void updateColor(View view, int viewId)
{
if (fragment.habit == null || fragment.activity == null) return;
TextView textView = (TextView) view.findViewById(viewId);
int androidColor =
ColorUtils.getColor(fragment.activity, fragment.habit.getColor());
textView.setTextColor(androidColor);
}
void updateColors()
{
fragment.activeColor = ColorUtils.getColor(fragment.getContext(),
fragment.habit.getColor());
fragment.inactiveColor =
InterfaceUtils.getStyledColor(fragment.getContext(),
R.attr.mediumContrastTextColor);
}
}

@ -0,0 +1,92 @@
/*
* 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.cards;
import android.content.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import butterknife.*;
public class FrequencyCard extends HabitCard
{
@BindView(R.id.title)
TextView title;
@BindView(R.id.frequencyChart)
FrequencyChart chart;
public FrequencyCard(Context context)
{
super(context);
init();
}
public FrequencyCard(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
inflate(getContext(), R.layout.show_habit_frequency, this);
ButterKnife.bind(this);
if(isInEditMode()) initEditMode();
}
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
title.setTextColor(color);
chart.setColor(color);
chart.populateWithRandomData();
}
@Override
protected void refreshData()
{
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
new BaseTask()
{
@Override
protected void doInBackground()
{
RepetitionList reps = habit.getRepetitions();
HashMap<Long, Integer[]> frequency = reps.getWeekdayFrequency();
chart.setFrequency(frequency);
}
}.execute();
}
}

@ -0,0 +1,102 @@
/*
* 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.cards;
import android.content.*;
import android.support.annotation.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.models.*;
public abstract class HabitCard extends LinearLayout
implements ModelObservable.Listener
{
@NonNull
private Habit habit;
public HabitCard(Context context)
{
super(context);
init();
}
public HabitCard(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
@NonNull
public Habit getHabit()
{
return habit;
}
public void setHabit(@NonNull Habit habit)
{
detachFrom(this.habit);
attachTo(habit);
this.habit = habit;
}
@Override
public void onModelChange()
{
refreshData();
}
@Override
protected void onAttachedToWindow()
{
if(isInEditMode()) return;
super.onAttachedToWindow();
refreshData();
attachTo(habit);
}
@Override
protected void onDetachedFromWindow()
{
detachFrom(habit);
super.onDetachedFromWindow();
}
protected abstract void refreshData();
private void attachTo(Habit habit)
{
habit.getObservable().addListener(this);
habit.getRepetitions().getObservable().addListener(this);
}
private void detachFrom(Habit habit)
{
habit.getRepetitions().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
}
private void init()
{
if(!isInEditMode()) habit = new Habit();
}
}

@ -0,0 +1,99 @@
/*
* 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.cards;
import android.content.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import butterknife.*;
public class HistoryCard extends HabitCard
{
@BindView(R.id.historyChart)
HistoryChart chart;
@BindView(R.id.title)
TextView title;
public HistoryCard(Context context)
{
super(context);
init();
}
public HistoryCard(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
@OnClick(R.id.edit)
public void onClickEditButton()
{
Log.d("HistoryCard", "onClickEditButton");
// HistoryEditorDialog frag = new HistoryEditorDialog();
// frag.setHabit(habit);
// frag.show(getContext().getFragmentManager(), "historyEditor");
}
private void init()
{
inflate(getContext(), R.layout.show_habit_history, this);
ButterKnife.bind(this);
if (isInEditMode()) initEditMode();
}
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
title.setTextColor(color);
chart.setColor(color);
chart.populateWithRandomData();
}
@Override
protected void refreshData()
{
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
chart.setColor(color);
new BaseTask()
{
@Override
protected void doInBackground()
{
int checkmarks[] = habit.getCheckmarks().getAllValues();
chart.setCheckmarks(checkmarks);
}
}.execute();
}
}

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.cards;
import android.content.*;
import android.support.annotation.*;
@ -27,16 +27,13 @@ import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.utils.*;
import butterknife.*;
public class OverviewCard extends LinearLayout
implements ModelObservable.Listener
public class OverviewCard extends HabitCard
{
@Nullable
private Habit habit;
@NonNull
private Cache cache;
@ -70,61 +67,19 @@ public class OverviewCard extends LinearLayout
}
@Override
public void onModelChange()
protected void refreshData()
{
refreshCache();
}
public void setHabit(@Nullable Habit habit)
{
this.habit = habit;
Habit habit = getHabit();
color = ColorUtils.getColor(getContext(), habit.getColor());
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
refreshCache();
if(habit != null) habit.getObservable().addListener(this);
}
refreshColors();
@Override
protected void onDetachedFromWindow()
{
if(habit != null) habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
private void init()
{
inflate(getContext(), R.layout.show_habit_overview, this);
ButterKnife.bind(this);
cache = new Cache();
if(isInEditMode()) initEditMode();
}
private void initEditMode()
{
color = ColorUtils.getAndroidTestColor(1);
cache.todayScore = Score.MAX_VALUE * 0.6f;
cache.lastMonthScore = Score.MAX_VALUE * 0.42f;
cache.lastYearScore = Score.MAX_VALUE * 0.75f;
updateScore();
}
private void refreshCache()
{
new BaseTask()
{
@Override
protected void doInBackground()
{
if(habit == null) return;
ScoreList scores = habit.getScores();
long today = DateUtils.getStartOfToday();
long lastMonth = today - 30 * DateUtils.millisecondsInOneDay;
long lastYear = today - 365 * DateUtils.millisecondsInOneDay;
@ -137,25 +92,54 @@ public class OverviewCard extends LinearLayout
@Override
protected void onPostExecute(Void aVoid)
{
updateScore();
refreshScore();
super.onPostExecute(aVoid);
}
}.execute();
}
void updateScore()
private String formatPercentageDiff(float percentageDiff)
{
float todayPercentage = cache.todayScore / Score.MAX_VALUE;
float monthDiff = todayPercentage - (cache.lastMonthScore / Score.MAX_VALUE);
float yearDiff = todayPercentage - (cache.lastYearScore / Score.MAX_VALUE);
return String.format("%s%.0f%%", (percentageDiff >= 0 ? "+" : "\u2212"),
Math.abs(percentageDiff) * 100);
}
scoreRing.setColor(color);
scoreRing.setPercentage(todayPercentage);
private void init()
{
inflate(getContext(), R.layout.show_habit_overview, this);
ButterKnife.bind(this);
cache = new Cache();
scoreLabel.setTextColor(color);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
if (isInEditMode()) initEditMode();
}
private void initEditMode()
{
color = ColorUtils.getAndroidTestColor(1);
cache.todayScore = Score.MAX_VALUE * 0.6f;
cache.lastMonthScore = Score.MAX_VALUE * 0.42f;
cache.lastYearScore = Score.MAX_VALUE * 0.75f;
refreshColors();
refreshScore();
}
private void refreshColors()
{
scoreRing.setColor(color);
scoreLabel.setTextColor(color);
title.setTextColor(color);
}
private void refreshScore()
{
float todayPercentage = cache.todayScore / Score.MAX_VALUE;
float monthDiff =
todayPercentage - (cache.lastMonthScore / Score.MAX_VALUE);
float yearDiff =
todayPercentage - (cache.lastYearScore / Score.MAX_VALUE);
scoreRing.setPercentage(todayPercentage);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
monthDiffLabel.setText(formatPercentageDiff(monthDiff));
yearDiffLabel.setText(formatPercentageDiff(yearDiff));
@ -169,12 +153,6 @@ public class OverviewCard extends LinearLayout
postInvalidate();
}
private String formatPercentageDiff(float percentageDiff)
{
return String.format("%s%.0f%%", (percentageDiff >= 0 ? "+" : "\u2212"),
Math.abs(percentageDiff) * 100);
}
private class Cache
{
public float todayScore;

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.cards;
import android.content.*;
import android.support.annotation.*;
@ -27,14 +27,14 @@ import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import butterknife.*;
public class ScoreCard extends RelativeLayout
implements ModelObservable.Listener
public class ScoreCard extends HabitCard
{
public static final int[] BUCKET_SIZES = { 1, 7, 31, 92, 365 };
@ -47,11 +47,6 @@ public class ScoreCard extends RelativeLayout
@BindView(R.id.title)
TextView title;
@Nullable
private Habit habit;
private int color;
private int bucketSize;
public ScoreCard(Context context)
@ -70,86 +65,64 @@ public class ScoreCard extends RelativeLayout
public void onItemSelected(int position)
{
setBucketSizeFromPosition(position);
refreshData();
}
@Override
public void onModelChange()
protected void refreshData()
{
refreshData();
}
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
public void setHabit(@NonNull Habit habit)
{
this.habit = habit;
color = ColorUtils.getColor(getContext(), habit.getColor());
refreshData();
}
title.setTextColor(color);
chart.setPrimaryColor(color);
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
if (habit != null)
new BaseTask()
{
habit.getObservable().addListener(this);
habit.getScores().getObservable().addListener(this);
}
@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();
}
@Override
protected void onDetachedFromWindow()
private int getDefaultSpinnerPosition()
{
if (habit != null)
{
habit.getObservable().removeListener(this);
habit.getScores().getObservable().removeListener(this);
}
super.onDetachedFromWindow();
if (isInEditMode()) return 0;
return InterfaceUtils.getDefaultScoreSpinnerPosition(getContext());
}
@NonNull
private DateUtils.TruncateField getTruncateField()
{
DateUtils.TruncateField field;
if (bucketSize == 7) return DateUtils.TruncateField.WEEK_NUMBER;
if (bucketSize == 31) return DateUtils.TruncateField.MONTH;
if (bucketSize == 92) return DateUtils.TruncateField.QUARTER;
if (bucketSize == 365) return DateUtils.TruncateField.YEAR;
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;
}
Log.e("ScoreCard",
String.format("Unknown bucket size: %d", bucketSize));
return field;
return DateUtils.TruncateField.MONTH;
}
private void init()
{
inflate(getContext(), R.layout.show_habit_strength, this);
inflate(getContext(), R.layout.show_habit_score, this);
ButterKnife.bind(this);
int defaultPosition = getDefaultSpinnerPosition();
setBucketSizeFromPosition(defaultPosition);
spinner.setSelection(defaultPosition);
if(isInEditMode())
if (isInEditMode())
{
spinner.setVisibility(GONE);
title.setTextColor(ColorUtils.getAndroidTestColor(1));
@ -158,41 +131,11 @@ public class ScoreCard extends RelativeLayout
}
}
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;
if (isInEditMode()) return;
InterfaceUtils.setDefaultScoreSpinnerPosition(getContext(), position);
bucketSize = BUCKET_SIZES[position];
refreshData();
}
}

@ -0,0 +1,99 @@
/*
* 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.cards;
import android.content.*;
import android.util.*;
import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
import butterknife.*;
public class StreakCard extends HabitCard
{
@BindView(R.id.title)
TextView title;
@BindView(R.id.streakChart)
StreakChart streakChart;
public StreakCard(Context context)
{
super(context);
init();
}
public StreakCard(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
inflate(getContext(), R.layout.show_habit_streak, this);
ButterKnife.bind(this);
setOrientation(VERTICAL);
if(isInEditMode()) initEditMode();
}
private void initEditMode()
{
int color = ColorUtils.getAndroidTestColor(1);
title.setTextColor(color);
streakChart.setColor(color);
streakChart.populateWithRandomData();
}
@Override
protected void refreshData()
{
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
title.setTextColor(color);
streakChart.setColor(color);
new BaseTask()
{
public List<Streak> streaks;
@Override
protected void doInBackground()
{
streaks = habit.getStreaks().getBest(10);
}
@Override
protected void onPostExecute(Void aVoid)
{
streakChart.setStreaks(streaks);
super.onPostExecute(aVoid);
}
}.execute();
}
}

@ -17,12 +17,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.cards;
import android.annotation.*;
import android.content.*;
import android.content.res.*;
import android.support.annotation.*;
import android.util.*;
import android.view.*;
import android.widget.*;
@ -33,8 +32,7 @@ import org.isoron.uhabits.utils.*;
import butterknife.*;
public class SubtitleCard extends LinearLayout
implements ModelObservable.Listener
public class SubtitleCard extends HabitCard
{
@BindView(R.id.questionLabel)
TextView questionLabel;
@ -45,9 +43,6 @@ public class SubtitleCard extends LinearLayout
@BindView(R.id.reminderLabel)
TextView reminderLabel;
@Nullable
private Habit habit;
public SubtitleCard(Context context)
{
super(context);
@ -60,32 +55,6 @@ public class SubtitleCard extends LinearLayout
init();
}
@Override
public void onModelChange()
{
refreshData();
}
public void setHabit(@Nullable Habit habit)
{
this.habit = habit;
refreshData();
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
if (habit != null) habit.getObservable().addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
if (habit != null) habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
private void init()
{
Context context = getContext();
@ -103,9 +72,10 @@ public class SubtitleCard extends LinearLayout
reminderLabel.setText("08:00");
}
private void refreshData()
@Override
protected void refreshData()
{
if (habit == null) return;
Habit habit = getHabit();
int color = ColorUtils.getColor(getContext(), habit.getColor());
reminderLabel.setText(getResources().getString(R.string.reminder_off));
@ -123,7 +93,7 @@ public class SubtitleCard extends LinearLayout
postInvalidate();
}
String toText(Frequency freq)
private String toText(Frequency freq)
{
Resources resources = getResources();
Integer num = freq.getNumerator();

@ -17,29 +17,25 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import android.content.*;
import android.graphics.*;
import android.support.annotation.*;
import android.util.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class FrequencyChart extends ScrollableChart
implements HabitDataView, ModelObservable.Listener
{
private Paint pGrid;
private float em;
private Habit habit;
private SimpleDateFormat dfMonth;
private SimpleDateFormat dfYear;
@ -68,6 +64,7 @@ public class FrequencyChart extends ScrollableChart
private boolean isBackgroundTransparent;
@NonNull
private HashMap<Long, Integer[]> frequency;
public FrequencyChart(Context context)
@ -79,42 +76,30 @@ public class FrequencyChart extends ScrollableChart
public FrequencyChart(Context context, AttributeSet attrs)
{
super(context, attrs);
this.primaryColor = ColorUtils.getColor(getContext(), 7);
this.frequency = new HashMap<>();
init();
}
@Override
public void onModelChange()
{
refreshData();
}
public void refreshData()
public void setColor(int color)
{
if (isInEditMode()) generateRandomData();
else if (habit != null)
{
frequency = habit.getRepetitions().getWeekdayFrequency();
createColors();
}
this.primaryColor = color;
initColors();
postInvalidate();
}
public void setHabit(Habit habit)
public void setFrequency(HashMap<Long, Integer[]> frequency)
{
this.habit = habit;
createColors();
this.frequency = frequency;
postInvalidate();
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
initColors();
}
protected void createPaints()
protected void initPaints()
{
pText = new Paint();
pText.setAntiAlias(true);
@ -127,30 +112,6 @@ public class FrequencyChart extends ScrollableChart
pGrid.setAntiAlias(true);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
@ -214,26 +175,6 @@ public class FrequencyChart extends ScrollableChart
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());
@ -301,24 +242,6 @@ public class FrequencyChart extends ScrollableChart
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;
@ -336,13 +259,53 @@ public class FrequencyChart extends ScrollableChart
private void init()
{
createPaints();
createColors();
initPaints();
initColors();
initDateFormats();
initRects();
}
private void initColors()
{
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 initDateFormats()
{
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
}
private void initRects()
{
rect = new RectF();
prevRect = new RectF();
}
public void populateWithRandomData()
{
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);
}
}
}

@ -17,11 +17,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import org.isoron.uhabits.models.Habit;
public interface HabitDataView
public interface HabitChart
{
void setHabit(Habit habit);

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import android.content.*;
import android.graphics.*;
@ -26,19 +26,13 @@ import android.util.*;
import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class HistoryView extends ScrollableChart implements HabitDataView,
ToggleRepetitionTask.Listener,
ModelObservable.Listener
public class HistoryChart extends ScrollableChart
{
private Habit habit;
private int[] checkmarks;
private Paint pSquareBg, pSquareFg, pTextHeader;
@ -88,13 +82,13 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
private float headerOverflow = 0;
public HistoryView(Context context)
public HistoryChart(Context context)
{
super(context);
init();
}
public HistoryView(Context context, AttributeSet attrs)
public HistoryChart(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
@ -106,12 +100,6 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
onSingleTapUp(e);
}
@Override
public void onModelChange()
{
refreshData();
}
@Override
public boolean onSingleTapUp(MotionEvent e)
{
@ -126,59 +114,48 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
final Long timestamp = positionToTimestamp(x, y);
if (timestamp == null) return false;
ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
task.setListener(this);
task.execute();
// ToggleRepetitionTask task = new ToggleRepetitionTask(habit, timestamp);
// task.setListener(this);
// task.execute();
return true;
}
@Override
public void onToggleRepetitionFinished()
public void populateWithRandomData()
{
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
Random random = new Random();
checkmarks = new int[100];
@Override
protected void onPostExecute(Void aVoid)
{
invalidate();
super.onPostExecute(null);
}
}.execute();
}
for (int i = 0; i < 100; i++)
if (random.nextFloat() < 0.3) checkmarks[i] = 2;
@Override
public void refreshData()
{
if (isInEditMode()) generateRandomData();
else
for (int i = 0; i < 100 - 7; i++)
{
if (habit == null) return;
checkmarks = habit.getCheckmarks().getAllValues();
createColors();
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);
}
}
updateDate();
public void setCheckmarks(int[] checkmarks)
{
this.checkmarks = checkmarks;
postInvalidate();
}
@Override
public void setHabit(Habit habit)
public void setColor(int color)
{
this.habit = habit;
createColors();
this.primaryColor = color;
initColors();
postInvalidate();
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
initColors();
}
public void setIsEditable(boolean isEditable)
@ -186,7 +163,7 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
this.isEditable = isEditable;
}
protected void createPaints()
protected void initPaints()
{
pTextHeader = new Paint();
pTextHeader.setTextAlign(Align.LEFT);
@ -199,30 +176,6 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
pSquareFg.setTextAlign(Align.CENTER);
}
@Override
protected void onAttachedToWindow()
{
super.onAttachedToWindow();
new BaseTask()
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getCheckmarks().observable.addListener(this);
}
@Override
protected void onDetachedFromWindow()
{
habit.getCheckmarks().observable.removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
}
@Override
protected void onDraw(Canvas canvas)
{
@ -290,41 +243,6 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
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;
@ -398,24 +316,6 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
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;
@ -428,15 +328,55 @@ public class HistoryView extends ScrollableChart implements HabitDataView,
private void init()
{
createColors();
createPaints();
isEditable = false;
checkmarks = new int[0];
primaryColor = ColorUtils.getColor(getContext(), 7);
initColors();
initPaints();
initDateFormats();
initRects();
}
private void initColors()
{
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 initDateFormats()
{
dfMonth = DateUtils.getDateFormat("MMM");
dfYear = DateUtils.getDateFormat("yyyy");
}
private void initRects()
{
baseLocation = new RectF();
}

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import android.content.*;
import android.graphics.*;
@ -31,6 +31,8 @@ import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
import static org.isoron.uhabits.utils.InterfaceUtils.*;
public class ScoreChart extends ScrollableChart
{
private static final PorterDuffXfermode XFERMODE_CLEAR =
@ -72,6 +74,7 @@ public class ScoreChart extends ScrollableChart
private int primaryColor;
@Deprecated
private int bucketSize = 7;
private int backgroundColor;
@ -100,6 +103,26 @@ public class ScoreChart extends ScrollableChart
init();
}
public void populateWithRandomData()
{
Random random = new Random();
scores = new LinkedList<>();
int previous = Score.MAX_VALUE / 2;
long timestamp = DateUtils.getStartOfToday();
long day = DateUtils.millisecondsInOneDay;
for (int i = 1; i < 100; i++)
{
int step = Score.MAX_VALUE / 10;
int current = previous + random.nextInt(step * 2) - step;
current = Math.max(0, Math.min(Score.MAX_VALUE, current));
scores.add(new Score(timestamp, current));
previous = current;
timestamp -= day;
}
}
@Deprecated
public void setBucketSize(int bucketSize)
{
@ -110,7 +133,7 @@ public class ScoreChart extends ScrollableChart
public void setIsTransparencyEnabled(boolean enabled)
{
this.isTransparencyEnabled = enabled;
createColors();
initColors();
requestLayout();
}
@ -126,19 +149,6 @@ public class ScoreChart extends ScrollableChart
postInvalidate();
}
protected void createPaints()
{
pText = new Paint();
pText.setAntiAlias(true);
pGraph = new Paint();
pGraph.setTextAlign(Paint.Align.CENTER);
pGraph.setAntiAlias(true);
pGrid = new Paint();
pGrid.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas)
{
@ -240,7 +250,7 @@ public class ScoreChart extends ScrollableChart
columnHeight = 8 * baseSize;
float minStrokeWidth = InterfaceUtils.dpToPixels(getContext(), 1);
float minStrokeWidth = dpToPixels(getContext(), 1);
pGraph.setTextSize(baseSize * 0.5f);
pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(Math.min(minStrokeWidth, baseSize * 0.05f));
@ -248,17 +258,6 @@ public class ScoreChart extends ScrollableChart
if (isTransparencyEnabled) initCache(width, height);
}
private void createColors()
{
primaryColor = Color.BLACK;
textColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.mediumContrastTextColor);
gridColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.lowContrastTextColor);
backgroundColor = InterfaceUtils.getStyledColor(getContext(),
R.attr.cardBackgroundColor);
}
private void drawFooter(Canvas canvas, RectF rect, long currentDate)
{
String yearText = dfYear.format(currentDate);
@ -340,7 +339,7 @@ public class ScoreChart extends ScrollableChart
private void drawMarker(Canvas canvas, RectF rect)
{
rect.inset(baseSize * 0.15f, baseSize * 0.15f);
rect.inset(baseSize * 0.225f, baseSize * 0.225f);
setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
canvas.drawOval(rect, pGraph);
@ -348,33 +347,13 @@ public class ScoreChart extends ScrollableChart
setModeOrColor(pGraph, XFERMODE_SRC, primaryColor);
canvas.drawOval(rect, pGraph);
rect.inset(baseSize * 0.1f, baseSize * 0.1f);
setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
canvas.drawOval(rect, pGraph);
// rect.inset(baseSize * 0.1f, baseSize * 0.1f);
// setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
// canvas.drawOval(rect, pGraph);
if (isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC);
}
public void populateWithRandomData()
{
Random random = new Random();
scores = new LinkedList<>();
int previous = Score.MAX_VALUE / 2;
long timestamp = DateUtils.getStartOfToday();
long day = DateUtils.millisecondsInOneDay;
for (int i = 1; i < 100; i++)
{
int step = Score.MAX_VALUE / 10;
int current = previous + random.nextInt(step * 2) - step;
current = Math.max(0, Math.min(Score.MAX_VALUE, current));
scores.add(new Score(timestamp, current));
previous = current;
timestamp -= day;
}
}
private float getMaxDayWidth()
{
float maxDayWidth = 0;
@ -407,15 +386,10 @@ public class ScoreChart extends ScrollableChart
private void init()
{
createPaints();
createColors();
dfYear = DateUtils.getDateFormat("yyyy");
dfMonth = DateUtils.getDateFormat("MMM");
dfDay = DateUtils.getDateFormat("d");
rect = new RectF();
prevRect = new RectF();
initPaints();
initColors();
initDateFormats();
initRects();
}
private void initCache(int width, int height)
@ -426,6 +400,42 @@ public class ScoreChart extends ScrollableChart
cacheCanvas = new Canvas(drawingCache);
}
private void initColors()
{
Context context = getContext();
primaryColor = Color.BLACK;
textColor = getStyledColor(context, R.attr.mediumContrastTextColor);
gridColor = getStyledColor(context, R.attr.lowContrastTextColor);
backgroundColor = getStyledColor(context, R.attr.cardBackgroundColor);
}
private void initDateFormats()
{
dfYear = DateUtils.getDateFormat("yyyy");
dfMonth = DateUtils.getDateFormat("MMM");
dfDay = DateUtils.getDateFormat("d");
}
private void initPaints()
{
pText = new Paint();
pText.setAntiAlias(true);
pGraph = new Paint();
pGraph.setTextAlign(Paint.Align.CENTER);
pGraph.setAntiAlias(true);
pGrid = new Paint();
pGrid.setAntiAlias(true);
}
private void initRects()
{
rect = new RectF();
prevRect = new RectF();
}
private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color)
{
if (isTransparencyEnabled) p.setXfermode(mode);

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import android.animation.*;
import android.content.*;

@ -17,7 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.ui.habits.show.views;
package org.isoron.uhabits.ui.habits.show.views.charts;
import android.content.*;
import android.graphics.*;
@ -26,17 +26,13 @@ import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.tasks.*;
import org.isoron.uhabits.utils.*;
import java.text.*;
import java.util.*;
public class StreakChart extends View
implements HabitDataView, ModelObservable.Listener
{
private Habit habit;
private Paint paint;
private long minLength;
@ -67,8 +63,6 @@ public class StreakChart extends View
private boolean shouldShowLabels;
private int maxStreakCount;
private int textColor;
private int reverseTextColor;
@ -82,68 +76,44 @@ public class StreakChart extends View
public StreakChart(Context context, AttributeSet attrs)
{
super(context, attrs);
this.primaryColor = ColorUtils.getColor(getContext(), 7);
init();
}
@Override
public void onModelChange()
{
refreshData();
}
@Override
public void refreshData()
{
if (habit == null) return;
streaks = habit.getStreaks().getBest(maxStreakCount);
createColors();
updateMaxMin();
postInvalidate();
}
@Override
public void setHabit(Habit habit)
{
this.habit = habit;
createColors();
}
public void setIsBackgroundTransparent(boolean isBackgroundTransparent)
{
this.isBackgroundTransparent = isBackgroundTransparent;
createColors();
initColors();
}
protected void createPaints()
public void setStreaks(List<Streak> streaks)
{
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
this.streaks = streaks;
initColors();
updateMaxMinLengths();
requestLayout();
}
@Override
protected void onAttachedToWindow()
public void populateWithRandomData()
{
super.onAttachedToWindow();
new BaseTask()
long day = DateUtils.millisecondsInOneDay;
long start = DateUtils.getStartOfToday();
LinkedList<Streak> streaks = new LinkedList<>();
for(int i = 0; i < 10; i++)
{
@Override
protected void doInBackground()
{
refreshData();
}
}.execute();
habit.getObservable().addListener(this);
habit.getStreaks().getObservable().addListener(this);
int length = new Random().nextInt(100);
long end = start + length * day;
streaks.add(new Streak(start, end));
start = end + day;
}
setStreaks(streaks);
}
@Override
protected void onDetachedFromWindow()
public void setColor(int color)
{
habit.getStreaks().getObservable().removeListener(this);
habit.getObservable().removeListener(this);
super.onDetachedFromWindow();
this.primaryColor = color;
postInvalidate();
}
@Override
@ -162,11 +132,14 @@ public class StreakChart extends View
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
protected void onMeasure(int widthSpec, int heightSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
int width = MeasureSpec.getSize(widthSpec);
int height = streaks.size() * baseSize;
heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
setMeasuredDimension(widthSpec, heightSpec);
}
@Override
@ -175,7 +148,6 @@ public class StreakChart extends View
int oldWidth,
int oldHeight)
{
maxStreakCount = height / baseSize;
this.width = width;
float minTextSize = getResources().getDimension(R.dimen.tinyTextSize);
@ -188,28 +160,7 @@ public class StreakChart extends View
em = paint.getFontSpacing();
textMargin = 0.5f * em;
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);
updateMaxMinLengths();
}
private void drawRow(Canvas canvas, Streak streak, RectF rect)
@ -256,18 +207,42 @@ public class StreakChart extends View
private void init()
{
createPaints();
createColors();
initPaints();
initColors();
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 void initColors()
{
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 initPaints()
{
paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setAntiAlias(true);
}
private int percentageToColor(float percentage)
{
if (percentage >= 1.0f) return colors[3];
@ -276,7 +251,7 @@ public class StreakChart extends View
return colors[0];
}
private void updateMaxMin()
private void updateMaxMinLengths()
{
maxLength = 0;
minLength = Long.MAX_VALUE;

@ -24,7 +24,7 @@ import android.view.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.widgets.views.*;
public class CheckmarkWidgetProvider extends BaseWidgetProvider
@ -65,7 +65,7 @@ public class CheckmarkWidgetProvider extends BaseWidgetProvider
@Override
protected void refreshCustomViewData(View view)
{
((HabitDataView) view).refreshData();
((HabitChart) view).refreshData();
}

@ -19,16 +19,14 @@
package org.isoron.uhabits.widgets;
import android.app.PendingIntent;
import android.content.Context;
import android.view.View;
import android.app.*;
import android.content.*;
import android.view.*;
import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.FrequencyChart;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
public class FrequencyWidgetProvider extends BaseWidgetProvider
{
@ -36,15 +34,16 @@ public class FrequencyWidgetProvider extends BaseWidgetProvider
protected View buildCustomView(Context context, Habit habit)
{
FrequencyChart dataView = new FrequencyChart(context);
GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit);
return view;
throw new NotImplementedException("");
// GraphWidgetView view = new GraphWidgetView(context, dataView);
// view.setHabit(habit);
// return view;
}
@Override
protected void refreshCustomViewData(View view)
{
((HabitDataView) view).refreshData();
((HabitChart) view).refreshData();
}
@Override

@ -18,32 +18,31 @@
*/
package org.isoron.uhabits.widgets;
import android.app.PendingIntent;
import android.content.Context;
import android.view.View;
import android.app.*;
import android.content.*;
import android.view.*;
import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.HistoryView;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
public class HistoryWidgetProvider extends BaseWidgetProvider
{
@Override
protected View buildCustomView(Context context, Habit habit)
{
HistoryView dataView = new HistoryView(context);
GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit);
return view;
throw new NotImplementedException("");
// HistoryChart dataView = new HistoryChart(context);
// GraphWidgetView view = new GraphWidgetView(context, dataView);
// view.setHabit(habit);
// return view;
}
@Override
protected void refreshCustomViewData(View view)
{
((HabitDataView) view).refreshData();
((HabitChart) view).refreshData();
}
@Override

@ -25,7 +25,8 @@ import android.view.*;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.ui.habits.show.views.cards.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
public class ScoreWidgetProvider extends BaseWidgetProvider
@ -50,7 +51,7 @@ public class ScoreWidgetProvider extends BaseWidgetProvider
@Override
protected void refreshCustomViewData(View view)
{
((HabitDataView) view).refreshData();
((HabitChart) view).refreshData();
}
@Override

@ -18,16 +18,14 @@
*/
package org.isoron.uhabits.widgets;
import android.app.PendingIntent;
import android.content.Context;
import android.view.View;
import android.app.*;
import android.content.*;
import android.view.*;
import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.widgets.views.GraphWidgetView;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.StreakChart;
import org.apache.commons.lang3.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
public class StreakWidgetProvider extends BaseWidgetProvider
{
@ -35,15 +33,16 @@ public class StreakWidgetProvider extends BaseWidgetProvider
protected View buildCustomView(Context context, Habit habit)
{
StreakChart dataView = new StreakChart(context);
GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit);
return view;
throw new NotImplementedException("");
// GraphWidgetView view = new GraphWidgetView(context, dataView);
// view.setHabit(habit);
// return view;
}
@Override
protected void refreshCustomViewData(View view)
{
((HabitDataView) view).refreshData();
((HabitChart) view).refreshData();
}
@Override

@ -30,13 +30,13 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.charts.HabitChart;
import org.isoron.uhabits.ui.habits.show.views.RingView;
import org.isoron.uhabits.utils.ColorUtils;
import org.isoron.uhabits.utils.InterfaceUtils;
public class CheckmarkWidgetView extends HabitWidgetView
implements HabitDataView
implements HabitChart
{
private int activeColor;

@ -27,15 +27,15 @@ import android.widget.TextView;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.ui.habits.show.views.HabitDataView;
import org.isoron.uhabits.ui.habits.show.views.charts.HabitChart;
public class GraphWidgetView extends HabitWidgetView implements HabitDataView
public class GraphWidgetView extends HabitWidgetView implements HabitChart
{
private final HabitDataView dataView;
private final HabitChart dataView;
private TextView title;
public GraphWidgetView(Context context, HabitDataView dataView)
public GraphWidgetView(Context context, HabitChart dataView)
{
super(context);
this.dataView = dataView;

@ -30,13 +30,13 @@ import android.widget.*;
import org.isoron.uhabits.*;
import org.isoron.uhabits.models.*;
import org.isoron.uhabits.ui.habits.show.views.*;
import org.isoron.uhabits.ui.habits.show.views.charts.*;
import org.isoron.uhabits.utils.*;
import java.util.*;
public abstract class HabitWidgetView extends FrameLayout
implements HabitDataView
implements HabitChart
{
@Nullable
protected InsetDrawable background;

@ -19,7 +19,6 @@
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:habit="http://isoron.org/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@ -31,7 +30,7 @@
style="@style/CardList"
android:clipToPadding="false">
<org.isoron.uhabits.ui.habits.show.views.SubtitleCard
<org.isoron.uhabits.ui.habits.show.views.cards.SubtitleCard
style="@style/ShowHabit.Subtitle"
android:id="@+id/subtitleCard"/>
@ -39,74 +38,29 @@
<!--android:id="@+id/headerShadow"-->
<!--style="@style/ToolbarShadow"/>-->
<org.isoron.uhabits.ui.habits.show.views.OverviewCard
<org.isoron.uhabits.ui.habits.show.views.cards.OverviewCard
android:id="@+id/overviewCard"
android:paddingTop="12dp"
style="@style/Card" />
<org.isoron.uhabits.ui.habits.show.views.ScoreCard
<org.isoron.uhabits.ui.habits.show.views.cards.ScoreCard
android:id="@+id/strengthCard"
style="@style/Card"
android:gravity="center" />
<LinearLayout
<org.isoron.uhabits.ui.habits.show.views.cards.HistoryCard
android:id="@+id/historyCard"
style="@style/Card"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="0dp">
<TextView
android:id="@+id/tvHistory"
style="@style/CardHeader"
android:text="@string/history"/>
<org.isoron.uhabits.ui.habits.show.views.HistoryView
android:id="@+id/historyView"
android:layout_width="match_parent"
android:layout_height="160dp"/>
<Button
android:id="@+id/btEditHistory"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_action_edit_light"
android:text="@string/edit"
android:textColor="@color/grey_400"
android:textSize="@dimen/smallTextSize"/>
</LinearLayout>
<LinearLayout
style="@style/Card"
android:orientation="vertical">
<TextView
android:id="@+id/tvStreaks"
style="@style/CardHeader"
android:text="@string/best_streaks"/>
<org.isoron.uhabits.ui.habits.show.views.StreakChart
android:id="@+id/streakChart"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
<LinearLayout
style="@style/Card"
android:orientation="vertical">
android:paddingBottom="0dp"
android:gravity="center" />
<TextView
android:id="@+id/tvWeekdayFreq"
style="@style/CardHeader"
android:text="@string/frequency"/>
<org.isoron.uhabits.ui.habits.show.views.cards.StreakCard
android:id="@+id/streakCard"
style="@style/Card"/>
<org.isoron.uhabits.ui.habits.show.views.FrequencyChart
android:id="@+id/punchcardView"
android:layout_width="match_parent"
android:layout_height="200dp"/>
<org.isoron.uhabits.ui.habits.show.views.cards.FrequencyCard
android:id="@+id/frequencyCard"
style="@style/Card"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

@ -19,30 +19,13 @@
-->
<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"/>
android:text="@string/frequency"/>
<org.isoron.uhabits.ui.habits.show.views.ScoreChart
android:id="@+id/scoreView"
<org.isoron.uhabits.ui.habits.show.views.charts.FrequencyChart
android:id="@+id/frequencyChart"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_below="@id/title"/>
android:layout_height="200dp"/>
</merge>

@ -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:clipToPadding="false"
android:orientation="vertical"
android:paddingBottom="0dp">
<TextView
android:id="@+id/title"
style="@style/CardHeader"
android:text="@string/history"/>
<org.isoron.uhabits.ui.habits.show.views.charts.HistoryChart
android:id="@+id/historyChart"
android:layout_width="match_parent"
android:layout_height="160dp"/>
<Button
android:id="@+id/edit"
style="?android:borderlessButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_action_edit_light"
android:text="@string/edit"
android:textColor="@color/grey_400"
android:textSize="@dimen/smallTextSize"/>
</merge>

@ -1,57 +0,0 @@
<?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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="?windowBackgroundColor"
android:clipToPadding="false"
android:fillViewport="true"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
style="@style/Toolbar"
android:background="@color/deep_orange_700"
android:elevation="1dp"
app:popupTheme="?toolbarPopupTheme"
app:title="Meditation"/>
<LinearLayout
style="@style/CardList"
android:clipToPadding="false">
<org.isoron.uhabits.ui.habits.show.views.SubtitleCard
android:id="@+id/subtitleView"
style="@style/ShowHabit.Subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<org.isoron.uhabits.ui.habits.show.views.OverviewCard
style="@style/Card"
android:paddingTop="12dp"/>
<org.isoron.uhabits.ui.habits.show.views.ScoreCard
style="@style/Card"
android:paddingTop="12dp"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,52 @@
<?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">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<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.charts.ScoreChart
android:id="@+id/scoreView"
android:layout_width="match_parent"
android:layout_height="220dp"
android:layout_below="@id/title"/>
</RelativeLayout>
</merge>

@ -0,0 +1,31 @@
<?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">
<TextView
android:id="@+id/title"
style="@style/CardHeader"
android:text="@string/best_streaks"/>
<org.isoron.uhabits.ui.habits.show.views.charts.StreakChart
android:id="@+id/streakChart"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</merge>
Loading…
Cancel
Save