Merge branch 'feature/repetition-count' into dev

pull/69/head
Alinson S. Xavier 10 years ago
commit 606f66b8d9

@ -27,6 +27,7 @@ import android.os.Vibrator;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
@ -80,16 +81,35 @@ public abstract class DialogHelper
{ {
int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0); int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0);
if(resId != 0) if (resId != 0) return context.getResources().getString(resId);
return context.getResources().getString(resId); else return attrs.getAttributeValue(ISORON_NAMESPACE, name);
else }
return attrs.getAttributeValue(ISORON_NAMESPACE, name);
public static int getIntAttribute(Context context, AttributeSet attrs, String name)
{
String number = getAttribute(context, attrs, name);
if(number != null) return Integer.parseInt(number);
else return 0;
}
public static float getFloatAttribute(Context context, AttributeSet attrs, String name)
{
String number = getAttribute(context, attrs, name);
if(number != null) return Float.parseFloat(number);
else return 0;
} }
public static float dpToPixels(Context context, float dp) public static float dpToPixels(Context context, float dp)
{ {
Resources resources = context.getResources(); Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics(); DisplayMetrics metrics = resources.getDisplayMetrics();
return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT); return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, metrics);
}
public static float spToPixels(Context context, float sp)
{
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, metrics);
} }
} }

@ -29,6 +29,7 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.isoron.helpers.ColorHelper; import org.isoron.helpers.ColorHelper;
@ -41,12 +42,17 @@ import org.isoron.uhabits.dialogs.HistoryEditorDialog;
import org.isoron.uhabits.helpers.ReminderHelper; import org.isoron.uhabits.helpers.ReminderHelper;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score; import org.isoron.uhabits.models.Score;
import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitHistoryView; import org.isoron.uhabits.views.HabitHistoryView;
import org.isoron.uhabits.views.HabitFrequencyView; import org.isoron.uhabits.views.HabitFrequencyView;
import org.isoron.uhabits.views.HabitScoreView; import org.isoron.uhabits.views.HabitScoreView;
import org.isoron.uhabits.views.HabitStreakView; import org.isoron.uhabits.views.HabitStreakView;
import org.isoron.uhabits.views.RepetitionCountView;
import org.isoron.uhabits.views.RingView; import org.isoron.uhabits.views.RingView;
import java.util.LinkedList;
import java.util.List;
public class ShowHabitFragment extends Fragment public class ShowHabitFragment extends Fragment
implements DialogHelper.OnSavedListener, HistoryEditorDialog.Listener implements DialogHelper.OnSavedListener, HistoryEditorDialog.Listener
{ {
@ -57,6 +63,8 @@ public class ShowHabitFragment extends Fragment
private HabitHistoryView historyView; private HabitHistoryView historyView;
private HabitFrequencyView punchcardView; private HabitFrequencyView punchcardView;
private List<HabitDataView> dataViews;
@Override @Override
public void onStart() public void onStart()
{ {
@ -71,19 +79,28 @@ public class ShowHabitFragment extends Fragment
activity = (ShowHabitActivity) getActivity(); activity = (ShowHabitActivity) getActivity();
habit = activity.habit; habit = activity.habit;
dataViews = new LinkedList<>();
Button btEditHistory = (Button) view.findViewById(R.id.btEditHistory); Button btEditHistory = (Button) view.findViewById(R.id.btEditHistory);
streakView = (HabitStreakView) view.findViewById(R.id.streakView); streakView = (HabitStreakView) view.findViewById(R.id.streakView);
scoreView = (HabitScoreView) view.findViewById(R.id.scoreView); scoreView = (HabitScoreView) view.findViewById(R.id.scoreView);
historyView = (HabitHistoryView) view.findViewById(R.id.historyView); historyView = (HabitHistoryView) view.findViewById(R.id.historyView);
punchcardView = (HabitFrequencyView) view.findViewById(R.id.punchcardView); punchcardView = (HabitFrequencyView) view.findViewById(R.id.punchcardView);
dataViews.add((HabitStreakView) view.findViewById(R.id.streakView));
dataViews.add((HabitScoreView) view.findViewById(R.id.scoreView));
dataViews.add((HabitHistoryView) view.findViewById(R.id.historyView));
dataViews.add((HabitFrequencyView) view.findViewById(R.id.punchcardView));
LinearLayout llRepetition = (LinearLayout) view.findViewById(R.id.llRepetition);
for(int i = 0; i < llRepetition.getChildCount(); i++)
dataViews.add((RepetitionCountView) llRepetition.getChildAt(i));
updateHeaders(view); updateHeaders(view);
updateScoreRing(view); updateScoreRing(view);
streakView.setHabit(habit); for(HabitDataView dataView : dataViews)
scoreView.setHabit(habit); dataView.setHabit(habit);
historyView.setHabit(habit);
punchcardView.setHabit(habit);
btEditHistory.setOnClickListener(new View.OnClickListener() btEditHistory.setOnClickListener(new View.OnClickListener()
{ {
@ -132,6 +149,7 @@ public class ShowHabitFragment extends Fragment
updateColor(view, R.id.tvStrength); 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.tvCount);
} }
private void updateColor(View view, int viewId) private void updateColor(View view, int viewId)
@ -184,10 +202,7 @@ public class ShowHabitFragment extends Fragment
public void refreshData() public void refreshData()
{ {
streakView.refreshData(); for(HabitDataView view : dataViews)
historyView.refreshData(); view.refreshData();
scoreView.refreshData();
punchcardView.refreshData();
updateScoreRing(getView());
} }
} }

@ -178,4 +178,16 @@ public class RepetitionList
return map; return map;
} }
/**
* Returns the total number of repetitions that happened within the specified interval of time.
*
* @param from beginning of the interval
* @param to end of the interval
* @return number of repetition in the given interval
*/
public int count(long from, long to)
{
return selectFromTo(from, to).count();
}
} }

@ -0,0 +1,29 @@
/*
* 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.views;
import org.isoron.uhabits.models.Habit;
public interface HabitDataView
{
void setHabit(Habit habit);
void refreshData();
}

@ -39,7 +39,7 @@ import java.util.Locale;
import java.util.Random; import java.util.Random;
import java.util.TimeZone; import java.util.TimeZone;
public class HabitFrequencyView extends ScrollableDataView public class HabitFrequencyView extends ScrollableDataView implements HabitDataView
{ {
private Paint pGrid; private Paint pGrid;

@ -40,7 +40,7 @@ import java.util.GregorianCalendar;
import java.util.Locale; import java.util.Locale;
import java.util.Random; import java.util.Random;
public class HabitHistoryView extends ScrollableDataView public class HabitHistoryView extends ScrollableDataView implements HabitDataView
{ {
private Habit habit; private Habit habit;
private int[] checkmarks; private int[] checkmarks;

@ -37,7 +37,7 @@ import java.text.SimpleDateFormat;
import java.util.Locale; import java.util.Locale;
import java.util.Random; import java.util.Random;
public class HabitScoreView extends ScrollableDataView public class HabitScoreView extends ScrollableDataView implements HabitDataView
{ {
public static final int BUCKET_SIZE = 7; public static final int BUCKET_SIZE = 7;
public static final PorterDuffXfermode XFERMODE_CLEAR = public static final PorterDuffXfermode XFERMODE_CLEAR =

@ -36,7 +36,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Random; import java.util.Random;
public class HabitStreakView extends ScrollableDataView public class HabitStreakView extends ScrollableDataView implements HabitDataView
{ {
private Habit habit; private Habit habit;
private Paint pText, pBar; private Paint pText, pBar;

@ -0,0 +1,155 @@
/*
* 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.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import org.isoron.helpers.ColorHelper;
import org.isoron.helpers.DialogHelper;
public class NumberView extends View
{
private int size;
private int color;
private int number;
private float labelMarginTop;
private TextPaint pText;
private String label;
private RectF rect;
private StaticLayout labelLayout;
private int width;
private int height;
private float textSize;
private float labelTextSize;
private float numberTextSize;
private StaticLayout numberLayout;
public NumberView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.label = DialogHelper.getAttribute(context, attrs, "label");
this.number = DialogHelper.getIntAttribute(context, attrs, "number");
this.textSize = DialogHelper.getFloatAttribute(context, attrs, "textSize");
this.textSize = DialogHelper.spToPixels(getContext(), textSize);
this.color = ColorHelper.palette[7];
init();
}
public void setColor(int color)
{
this.color = color;
pText.setColor(color);
postInvalidate();
}
public void setLabel(String label)
{
this.label = label;
}
public void setNumber(int number)
{
this.number = number;
createNumberLayout();
postInvalidate();
}
private void init()
{
pText = new TextPaint();
pText.setAntiAlias(true);
pText.setTextAlign(Paint.Align.CENTER);
rect = new RectF();
}
@Override
@SuppressLint("DrawAllocation")
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
labelTextSize = textSize * 0.35f;
labelMarginTop = textSize * 0.125f;
numberTextSize = textSize;
createNumberLayout();
int numberWidth = numberLayout.getWidth();
int numberHeight = numberLayout.getHeight();
pText.setTextSize(labelTextSize);
labelLayout = new StaticLayout(label, pText, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f,
false);
int labelWidth = labelLayout.getWidth();
int labelHeight = labelLayout.getHeight();
width = Math.max(numberWidth, labelWidth);
height = (int) (numberHeight + labelHeight + labelMarginTop);
setMeasuredDimension(width, height);
}
private void createNumberLayout()
{
pText.setTextSize(numberTextSize);
numberLayout = new StaticLayout(Integer.toString(number), pText, width,
Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, false);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
pText.setColor(color);
pText.setTextSize(size * 0.4f);
rect.set(0, 0, width, height);
canvas.save();
canvas.translate(rect.centerX(), 0);
pText.setColor(color);
pText.setTextSize(numberTextSize);
numberLayout.draw(canvas);
canvas.restore();
canvas.save();
pText.setColor(Color.GRAY);
pText.setTextSize(labelTextSize);
canvas.translate(rect.centerX(), numberLayout.getHeight() + labelMarginTop);
labelLayout.draw(canvas);
canvas.restore();
}
}

@ -0,0 +1,78 @@
/*
* 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.views;
import android.content.Context;
import android.util.AttributeSet;
import org.isoron.helpers.DateHelper;
import org.isoron.helpers.DialogHelper;
import org.isoron.uhabits.models.Habit;
import java.util.Calendar;
import java.util.GregorianCalendar;
public class RepetitionCountView extends NumberView implements HabitDataView
{
private int interval;
private Habit habit;
public RepetitionCountView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.interval = DialogHelper.getIntAttribute(context, attrs, "interval");
refreshData();
}
@Override
public void refreshData()
{
if(isInEditMode())
{
setNumber(interval);
return;
}
long to = DateHelper.getStartOfToday();
long from;
if(interval == 0)
{
from = 0;
}
else
{
GregorianCalendar fromCalendar = DateHelper.getStartOfTodayCalendar();
fromCalendar.add(Calendar.DAY_OF_YEAR, -interval + 1);
from = fromCalendar.getTimeInMillis();
}
if(habit != null)
setNumber(habit.repetitions.count(from, to));
}
@Override
public void setHabit(Habit habit)
{
this.habit = habit;
setColor(habit.color);
refreshData();
}
}

@ -40,12 +40,74 @@
<org.isoron.uhabits.views.RingView <org.isoron.uhabits.views.RingView
android:id="@+id/scoreRing" android:id="@+id/scoreRing"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
app:label="@string/habit_strength"/> app:label="@string/habit_strength"/>
</LinearLayout> </LinearLayout>
<LinearLayout
style="@style/cardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top|start">
<TextView
android:id="@+id/tvCount"
style="@style/cardHeaderStyle"
android:text="@string/repetitions"/>
<LinearLayout
android:id="@+id/llRepetition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<org.isoron.uhabits.views.RepetitionCountView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:label="@string/month"
app:interval="31"
app:textSize="34"/>
<org.isoron.uhabits.views.RepetitionCountView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:label="@string/quarter"
app:interval="92"
app:textSize="34"/>
<org.isoron.uhabits.views.RepetitionCountView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:label="@string/year"
app:interval="365"
app:textSize="34"/>
<org.isoron.uhabits.views.RepetitionCountView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
app:label="@string/all_time"
app:interval="0"
app:textSize="34"/>
</LinearLayout>
</LinearLayout>
<LinearLayout style="@style/cardStyle"> <LinearLayout style="@style/cardStyle">
<TextView <TextView

@ -125,4 +125,9 @@
<string name="frequency">Frequency</string> <string name="frequency">Frequency</string>
<string name="checkmark">Checkmark</string> <string name="checkmark">Checkmark</string>
<string name="repetitions">Repetitions</string>
<string name="month">Month</string>
<string name="year">Year</string>
<string name="quarter">Quarter</string>
<string name="all_time">All time</string>
</resources> </resources>
Loading…
Cancel
Save