diff --git a/app/src/main/java/org/isoron/helpers/DialogHelper.java b/app/src/main/java/org/isoron/helpers/DialogHelper.java index e65a50430..ebaf6c9b5 100644 --- a/app/src/main/java/org/isoron/helpers/DialogHelper.java +++ b/app/src/main/java/org/isoron/helpers/DialogHelper.java @@ -27,6 +27,7 @@ import android.os.Vibrator; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.TypedValue; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -80,16 +81,35 @@ public abstract class DialogHelper { int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0); - if(resId != 0) - return context.getResources().getString(resId); - else - return attrs.getAttributeValue(ISORON_NAMESPACE, name); + if (resId != 0) return context.getResources().getString(resId); + 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) { Resources resources = context.getResources(); 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); } } diff --git a/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java b/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java index 6f57abc9c..1b7817afb 100644 --- a/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java +++ b/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java @@ -29,6 +29,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; 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.models.Habit; import org.isoron.uhabits.models.Score; +import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitHistoryView; import org.isoron.uhabits.views.HabitFrequencyView; import org.isoron.uhabits.views.HabitScoreView; import org.isoron.uhabits.views.HabitStreakView; +import org.isoron.uhabits.views.RepetitionCountView; import org.isoron.uhabits.views.RingView; +import java.util.LinkedList; +import java.util.List; + public class ShowHabitFragment extends Fragment implements DialogHelper.OnSavedListener, HistoryEditorDialog.Listener { @@ -57,6 +63,8 @@ public class ShowHabitFragment extends Fragment private HabitHistoryView historyView; private HabitFrequencyView punchcardView; + private List dataViews; + @Override public void onStart() { @@ -71,19 +79,28 @@ public class ShowHabitFragment extends Fragment activity = (ShowHabitActivity) getActivity(); habit = activity.habit; + dataViews = new LinkedList<>(); + Button btEditHistory = (Button) view.findViewById(R.id.btEditHistory); streakView = (HabitStreakView) view.findViewById(R.id.streakView); scoreView = (HabitScoreView) view.findViewById(R.id.scoreView); historyView = (HabitHistoryView) view.findViewById(R.id.historyView); 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); updateScoreRing(view); - streakView.setHabit(habit); - scoreView.setHabit(habit); - historyView.setHabit(habit); - punchcardView.setHabit(habit); + for(HabitDataView dataView : dataViews) + dataView.setHabit(habit); btEditHistory.setOnClickListener(new View.OnClickListener() { @@ -132,6 +149,7 @@ public class ShowHabitFragment extends Fragment updateColor(view, R.id.tvStrength); updateColor(view, R.id.tvStreaks); updateColor(view, R.id.tvWeekdayFreq); + updateColor(view, R.id.tvCount); } private void updateColor(View view, int viewId) @@ -184,10 +202,7 @@ public class ShowHabitFragment extends Fragment public void refreshData() { - streakView.refreshData(); - historyView.refreshData(); - scoreView.refreshData(); - punchcardView.refreshData(); - updateScoreRing(getView()); + for(HabitDataView view : dataViews) + view.refreshData(); } } diff --git a/app/src/main/java/org/isoron/uhabits/models/RepetitionList.java b/app/src/main/java/org/isoron/uhabits/models/RepetitionList.java index ebdf35c66..daa889669 100644 --- a/app/src/main/java/org/isoron/uhabits/models/RepetitionList.java +++ b/app/src/main/java/org/isoron/uhabits/models/RepetitionList.java @@ -178,4 +178,16 @@ public class RepetitionList 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(); + } } diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitDataView.java b/app/src/main/java/org/isoron/uhabits/views/HabitDataView.java new file mode 100644 index 000000000..f6d3c712a --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/HabitDataView.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * 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 . + */ + +package org.isoron.uhabits.views; + +import org.isoron.uhabits.models.Habit; + +public interface HabitDataView +{ + void setHabit(Habit habit); + + void refreshData(); +} diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java b/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java index 42c41b64b..9a64aa44b 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java @@ -39,7 +39,7 @@ import java.util.Locale; import java.util.Random; import java.util.TimeZone; -public class HabitFrequencyView extends ScrollableDataView +public class HabitFrequencyView extends ScrollableDataView implements HabitDataView { private Paint pGrid; diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java b/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java index 18bbc1e0e..8a4416bbc 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitHistoryView.java @@ -40,7 +40,7 @@ import java.util.GregorianCalendar; import java.util.Locale; import java.util.Random; -public class HabitHistoryView extends ScrollableDataView +public class HabitHistoryView extends ScrollableDataView implements HabitDataView { private Habit habit; private int[] checkmarks; diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java index 02f596e0b..c64a6101b 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java @@ -37,7 +37,7 @@ import java.text.SimpleDateFormat; import java.util.Locale; 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 PorterDuffXfermode XFERMODE_CLEAR = diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java index 1fc61cc0c..c4a5115ce 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java @@ -36,7 +36,7 @@ import java.util.List; import java.util.Locale; import java.util.Random; -public class HabitStreakView extends ScrollableDataView +public class HabitStreakView extends ScrollableDataView implements HabitDataView { private Habit habit; private Paint pText, pBar; diff --git a/app/src/main/java/org/isoron/uhabits/views/NumberView.java b/app/src/main/java/org/isoron/uhabits/views/NumberView.java new file mode 100644 index 000000000..53fa64413 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/NumberView.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * 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 . + */ + +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(); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/views/RepetitionCountView.java b/app/src/main/java/org/isoron/uhabits/views/RepetitionCountView.java new file mode 100644 index 000000000..f99a2221a --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/RepetitionCountView.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * 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 . + */ + +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(); + } +} diff --git a/app/src/main/res/layout/show_habit.xml b/app/src/main/res/layout/show_habit.xml index d603b891a..9cd6bbb40 100644 --- a/app/src/main/res/layout/show_habit.xml +++ b/app/src/main/res/layout/show_habit.xml @@ -40,12 +40,74 @@ + + + + + + + + + + + + + + + + + + Frequency Checkmark + Repetitions + Month + Year + Quarter + All time \ No newline at end of file