mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Allow custom views to be rendered on the layout editor
This commit is contained in:
@@ -17,21 +17,18 @@
|
|||||||
package org.isoron.helpers;
|
package org.isoron.helpers;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnClickListener;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.isoron.uhabits.R;
|
|
||||||
|
|
||||||
public abstract class DialogHelper
|
public abstract class DialogHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static final String ISORON_NAMESPACE = "http://isoron.org/android";
|
||||||
private static Typeface fontawesome;
|
private static Typeface fontawesome;
|
||||||
|
|
||||||
public interface OnSavedListener
|
public interface OnSavedListener
|
||||||
@@ -65,4 +62,14 @@ public abstract class DialogHelper
|
|||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
return prefs.getInt("launch_count", 0);
|
return prefs.getInt("launch_count", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getAttribute(Context context, AttributeSet attrs, String name)
|
||||||
|
{
|
||||||
|
int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0);
|
||||||
|
|
||||||
|
if(resId != 0)
|
||||||
|
return context.getResources().getString(resId);
|
||||||
|
else
|
||||||
|
return attrs.getAttributeValue(ISORON_NAMESPACE, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,15 +25,14 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
import org.isoron.helpers.Command;
|
import org.isoron.helpers.Command;
|
||||||
import org.isoron.helpers.DialogHelper;
|
import org.isoron.helpers.DialogHelper;
|
||||||
import org.isoron.uhabits.R;
|
import org.isoron.uhabits.R;
|
||||||
import org.isoron.uhabits.helpers.ReminderHelper;
|
|
||||||
import org.isoron.uhabits.ShowHabitActivity;
|
import org.isoron.uhabits.ShowHabitActivity;
|
||||||
|
import org.isoron.uhabits.helpers.ReminderHelper;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
import org.isoron.uhabits.views.HabitHistoryView;
|
import org.isoron.uhabits.views.HabitHistoryView;
|
||||||
import org.isoron.uhabits.views.HabitScoreView;
|
import org.isoron.uhabits.views.HabitScoreView;
|
||||||
@@ -71,29 +70,21 @@ public class ShowHabitFragment extends Fragment implements DialogHelper.OnSavedL
|
|||||||
TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview);
|
TextView tvOverview = (TextView) view.findViewById(R.id.tvOverview);
|
||||||
TextView tvStrength = (TextView) view.findViewById(R.id.tvStrength);
|
TextView tvStrength = (TextView) view.findViewById(R.id.tvStrength);
|
||||||
TextView tvStreaks = (TextView) view.findViewById(R.id.tvStreaks);
|
TextView tvStreaks = (TextView) view.findViewById(R.id.tvStreaks);
|
||||||
|
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
|
||||||
|
HabitStreakView streakView = (HabitStreakView) view.findViewById(R.id.streakView);
|
||||||
|
HabitScoreView scoreView = (HabitScoreView) view.findViewById(R.id.scoreView);
|
||||||
|
HabitHistoryView historyView = (HabitHistoryView) view.findViewById(R.id.historyView);
|
||||||
|
|
||||||
tvHistory.setTextColor(habit.color);
|
tvHistory.setTextColor(habit.color);
|
||||||
tvOverview.setTextColor(habit.color);
|
tvOverview.setTextColor(habit.color);
|
||||||
tvStrength.setTextColor(habit.color);
|
tvStrength.setTextColor(habit.color);
|
||||||
tvStreaks.setTextColor(habit.color);
|
tvStreaks.setTextColor(habit.color);
|
||||||
|
|
||||||
LinearLayout llOverview = (LinearLayout) view.findViewById(R.id.llOverview);
|
scoreRing.setColor(habit.color);
|
||||||
llOverview.addView(new RingView(activity,
|
scoreRing.setPercentage((float) habit.getScore() / Habit.MAX_SCORE);
|
||||||
(int) activity.getResources().getDimension(R.dimen.small_square_size) * 4,
|
streakView.setHabit(habit);
|
||||||
habit.color, ((float) habit.getScore() / Habit.MAX_SCORE), activity.getString(R.string.habit_strength)));
|
scoreView.setHabit(habit);
|
||||||
|
historyView.setHabit(habit);
|
||||||
LinearLayout llStrength = (LinearLayout) view.findViewById(R.id.llStrength);
|
|
||||||
llStrength.addView(new HabitScoreView(activity, habit,
|
|
||||||
(int) activity.getResources().getDimension(R.dimen.small_square_size)));
|
|
||||||
|
|
||||||
LinearLayout llHistory = (LinearLayout) view.findViewById(R.id.llHistory);
|
|
||||||
HabitHistoryView hhv = new HabitHistoryView(activity, habit,
|
|
||||||
(int) activity.getResources().getDimension(R.dimen.small_square_size));
|
|
||||||
llHistory.addView(hhv);
|
|
||||||
|
|
||||||
LinearLayout llStreaks = (LinearLayout) view.findViewById(R.id.llStreaks);
|
|
||||||
HabitStreakView hsv = new HabitStreakView(activity, habit,
|
|
||||||
(int) activity.getResources().getDimension(R.dimen.small_square_size));
|
|
||||||
llStreaks.addView(hsv);
|
|
||||||
|
|
||||||
setHasOptionsMenu(true);
|
setHasOptionsMenu(true);
|
||||||
return view;
|
return view;
|
||||||
|
|||||||
@@ -22,19 +22,21 @@ import android.graphics.Color;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Align;
|
import android.graphics.Paint.Align;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class HabitHistoryView extends ScrollableDataView
|
public class HabitHistoryView extends ScrollableDataView
|
||||||
{
|
{
|
||||||
|
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
private int[] checkmarks;
|
private int[] checkmarks;
|
||||||
private Paint pSquareBg, pSquareFg, pTextHeader;
|
private Paint pSquareBg, pSquareFg, pTextHeader;
|
||||||
@@ -52,13 +54,29 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
private int todayWeekday;
|
private int todayWeekday;
|
||||||
private int colors[];
|
private int colors[];
|
||||||
private Rect baseLocation;
|
private Rect baseLocation;
|
||||||
|
private int baseSize;
|
||||||
|
private int primaryColor;
|
||||||
|
|
||||||
public HabitHistoryView(Context context, Habit habit, int baseSize)
|
public HabitHistoryView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context, attrs);
|
||||||
this.habit = habit;
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
|
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
setDimensions(baseSize);
|
public void setHabit(Habit habit)
|
||||||
|
{
|
||||||
|
this.habit = habit;
|
||||||
|
this.primaryColor = habit.color;
|
||||||
|
createColors();
|
||||||
|
fetchData();
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
setDimensions(this.baseSize);
|
||||||
createPaints();
|
createPaints();
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
@@ -90,7 +108,6 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
|
|
||||||
private void createColors()
|
private void createColors()
|
||||||
{
|
{
|
||||||
int primaryColor = habit.color;
|
|
||||||
int primaryColorBright = ColorHelper.mixColors(primaryColor, Color.WHITE, 0.5f);
|
int primaryColorBright = ColorHelper.mixColors(primaryColor, Color.WHITE, 0.5f);
|
||||||
int grey = Color.rgb(230, 230, 230);
|
int grey = Color.rgb(230, 230, 230);
|
||||||
|
|
||||||
@@ -116,7 +133,7 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
pTextHeader.setAntiAlias(true);
|
pTextHeader.setAntiAlias(true);
|
||||||
|
|
||||||
pSquareBg = new Paint();
|
pSquareBg = new Paint();
|
||||||
pSquareBg.setColor(habit.color);
|
pSquareBg.setColor(primaryColor);
|
||||||
|
|
||||||
pSquareFg = new Paint();
|
pSquareFg = new Paint();
|
||||||
pSquareFg.setColor(Color.WHITE);
|
pSquareFg.setColor(Color.WHITE);
|
||||||
@@ -130,10 +147,41 @@ public class HabitHistoryView extends ScrollableDataView
|
|||||||
|
|
||||||
protected void fetchData()
|
protected void fetchData()
|
||||||
{
|
{
|
||||||
checkmarks = habit.getAllCheckmarks();
|
if(isInEditMode())
|
||||||
|
generateRandomData();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(habit == null)
|
||||||
|
{
|
||||||
|
checkmarks = new int[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkmarks = habit.getAllCheckmarks();
|
||||||
|
}
|
||||||
|
|
||||||
updateDate();
|
updateDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateRandomData()
|
||||||
|
{
|
||||||
|
Random random = new Random();
|
||||||
|
checkmarks = new int[100];
|
||||||
|
|
||||||
|
for(int i = 0; i < 100; i++)
|
||||||
|
if(random.nextFloat() < 0.3) checkmarks[i] = 2;
|
||||||
|
|
||||||
|
for(int i = 0; i < 100 - 7; i++)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int j = 0; j < 7; j++)
|
||||||
|
if(checkmarks[i + j] != 0)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if(count >= 3) checkmarks[i] = Math.max(checkmarks[i], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String previousMonth;
|
private String previousMonth;
|
||||||
private String previousYear;
|
private String previousYear;
|
||||||
private boolean justPrintedYear;
|
private boolean justPrintedYear;
|
||||||
|
|||||||
@@ -21,65 +21,56 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
import org.isoron.helpers.DateHelper;
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class HabitScoreView extends ScrollableDataView
|
public class HabitScoreView extends ScrollableDataView
|
||||||
{
|
{
|
||||||
public static final int BUCKET_SIZE = 7;
|
public static final int BUCKET_SIZE = 7;
|
||||||
|
|
||||||
private final Paint pGrid;
|
private Paint pGrid;
|
||||||
private final float em;
|
private float em;
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
private SimpleDateFormat dfMonth;
|
private SimpleDateFormat dfMonth;
|
||||||
private SimpleDateFormat dfDay;
|
private SimpleDateFormat dfDay;
|
||||||
|
|
||||||
private Paint pText, pGraph;
|
private Paint pText, pGraph;
|
||||||
private RectF rect, prevRect;
|
private RectF rect, prevRect;
|
||||||
|
private int baseSize;
|
||||||
|
|
||||||
private int[] colors;
|
private int[] colors;
|
||||||
private int[] scores;
|
private int[] scores;
|
||||||
|
private int primaryColor;
|
||||||
|
|
||||||
public HabitScoreView(Context context, Habit habit, int columnWidth)
|
public HabitScoreView(Context context, AttributeSet attrs)
|
||||||
|
{
|
||||||
|
super(context, attrs);
|
||||||
|
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
||||||
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHabit(Habit habit)
|
||||||
{
|
{
|
||||||
super(context);
|
|
||||||
this.habit = habit;
|
this.habit = habit;
|
||||||
|
this.primaryColor = habit.color;
|
||||||
|
fetchData();
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
pText = new Paint();
|
private void init()
|
||||||
pText.setColor(Color.LTGRAY);
|
{
|
||||||
pText.setTextAlign(Paint.Align.LEFT);
|
createPaints();
|
||||||
pText.setTextSize(columnWidth * 0.5f);
|
setDimensions();
|
||||||
pText.setAntiAlias(true);
|
createColors();
|
||||||
|
|
||||||
pGraph = new Paint();
|
|
||||||
pGraph.setTextAlign(Paint.Align.CENTER);
|
|
||||||
pGraph.setTextSize(columnWidth * 0.5f);
|
|
||||||
pGraph.setAntiAlias(true);
|
|
||||||
pGraph.setStrokeWidth(columnWidth * 0.1f);
|
|
||||||
|
|
||||||
pGrid = new Paint();
|
|
||||||
pGrid.setColor(Color.LTGRAY);
|
|
||||||
pGrid.setAntiAlias(true);
|
|
||||||
pGrid.setStrokeWidth(columnWidth * 0.05f);
|
|
||||||
|
|
||||||
this.columnWidth = columnWidth;
|
|
||||||
columnHeight = 8 * columnWidth;
|
|
||||||
headerHeight = columnWidth;
|
|
||||||
footerHeight = columnWidth;
|
|
||||||
|
|
||||||
em = pText.getFontSpacing();
|
|
||||||
|
|
||||||
colors = new int[4];
|
|
||||||
|
|
||||||
colors[0] = Color.rgb(230, 230, 230);
|
|
||||||
colors[3] = habit.color;
|
|
||||||
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
|
||||||
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
|
||||||
|
|
||||||
dfMonth = new SimpleDateFormat("MMM", Locale.getDefault());
|
dfMonth = new SimpleDateFormat("MMM", Locale.getDefault());
|
||||||
dfDay = new SimpleDateFormat("d", Locale.getDefault());
|
dfDay = new SimpleDateFormat("d", Locale.getDefault());
|
||||||
@@ -88,9 +79,74 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
prevRect = new RectF();
|
prevRect = new RectF();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setDimensions()
|
||||||
|
{
|
||||||
|
this.columnWidth = baseSize;
|
||||||
|
columnHeight = 8 * baseSize;
|
||||||
|
headerHeight = baseSize;
|
||||||
|
footerHeight = baseSize;
|
||||||
|
em = pText.getFontSpacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createColors()
|
||||||
|
{
|
||||||
|
colors = new int[4];
|
||||||
|
|
||||||
|
colors[0] = Color.rgb(230, 230, 230);
|
||||||
|
colors[3] = primaryColor;
|
||||||
|
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
||||||
|
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createPaints()
|
||||||
|
{
|
||||||
|
pText = new Paint();
|
||||||
|
pText.setColor(Color.LTGRAY);
|
||||||
|
pText.setTextAlign(Paint.Align.LEFT);
|
||||||
|
pText.setTextSize(baseSize * 0.5f);
|
||||||
|
pText.setAntiAlias(true);
|
||||||
|
|
||||||
|
pGraph = new Paint();
|
||||||
|
pGraph.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pGraph.setTextSize(baseSize * 0.5f);
|
||||||
|
pGraph.setAntiAlias(true);
|
||||||
|
pGraph.setStrokeWidth(baseSize * 0.1f);
|
||||||
|
|
||||||
|
pGrid = new Paint();
|
||||||
|
pGrid.setColor(Color.LTGRAY);
|
||||||
|
pGrid.setAntiAlias(true);
|
||||||
|
pGrid.setStrokeWidth(baseSize * 0.05f);
|
||||||
|
}
|
||||||
|
|
||||||
protected void fetchData()
|
protected void fetchData()
|
||||||
{
|
{
|
||||||
scores = habit.getAllScores(BUCKET_SIZE * DateHelper.millisecondsInOneDay);
|
if(isInEditMode())
|
||||||
|
generateRandomData();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (habit == null)
|
||||||
|
{
|
||||||
|
scores = new int[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scores = habit.getAllScores(BUCKET_SIZE * DateHelper.millisecondsInOneDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateRandomData()
|
||||||
|
{
|
||||||
|
Random random = new Random();
|
||||||
|
scores = new int[100];
|
||||||
|
scores[0] = Habit.MAX_SCORE / 2;
|
||||||
|
|
||||||
|
for(int i = 1; i < 100; i++)
|
||||||
|
{
|
||||||
|
int step = Habit.MAX_SCORE / 10;
|
||||||
|
scores[i] = scores[i - 1] + random.nextInt(step * 2) - step;
|
||||||
|
scores[i] = Math.max(0, Math.min(Habit.MAX_SCORE, scores[i]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -106,7 +162,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
|
|
||||||
String previousMonth = "";
|
String previousMonth = "";
|
||||||
|
|
||||||
pGraph.setColor(habit.color);
|
pGraph.setColor(primaryColor);
|
||||||
prevRect.setEmpty();
|
prevRect.setEmpty();
|
||||||
|
|
||||||
long currentDate = DateHelper.getStartOfToday();
|
long currentDate = DateHelper.getStartOfToday();
|
||||||
@@ -171,7 +227,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
|
|
||||||
private void drawLine(Canvas canvas, RectF rectFrom, RectF rectTo)
|
private void drawLine(Canvas canvas, RectF rectFrom, RectF rectTo)
|
||||||
{
|
{
|
||||||
pGraph.setColor(habit.color);
|
pGraph.setColor(primaryColor);
|
||||||
canvas.drawLine(rectFrom.centerX(), rectFrom.centerY(), rectTo.centerX(), rectTo.centerY(),
|
canvas.drawLine(rectFrom.centerX(), rectFrom.centerY(), rectTo.centerX(), rectTo.centerY(),
|
||||||
pGraph);
|
pGraph);
|
||||||
}
|
}
|
||||||
@@ -183,7 +239,7 @@ public class HabitScoreView extends ScrollableDataView
|
|||||||
canvas.drawOval(rect, pGraph);
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
pGraph.setColor(habit.color);
|
pGraph.setColor(primaryColor);
|
||||||
canvas.drawOval(rect, pGraph);
|
canvas.drawOval(rect, pGraph);
|
||||||
|
|
||||||
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
rect.inset(columnWidth * 0.1f, columnWidth * 0.1f);
|
||||||
|
|||||||
@@ -21,31 +21,55 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
import org.isoron.helpers.ColorHelper;
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.DateHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
import org.isoron.uhabits.models.Habit;
|
import org.isoron.uhabits.models.Habit;
|
||||||
import org.isoron.uhabits.models.Streak;
|
import org.isoron.uhabits.models.Streak;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class HabitStreakView extends ScrollableDataView
|
public class HabitStreakView extends ScrollableDataView
|
||||||
{
|
{
|
||||||
private Habit habit;
|
private Habit habit;
|
||||||
private Paint pText, pBar;
|
private Paint pText, pBar;
|
||||||
private List<Streak> streaks;
|
|
||||||
|
private long[] startTimes;
|
||||||
|
private long[] endTimes;
|
||||||
|
private long[] lengths;
|
||||||
|
|
||||||
private long maxStreakLength;
|
private long maxStreakLength;
|
||||||
private int[] colors;
|
private int[] colors;
|
||||||
private SimpleDateFormat dfMonth;
|
private SimpleDateFormat dfMonth;
|
||||||
private Rect rect;
|
private Rect rect;
|
||||||
|
private int baseSize;
|
||||||
|
private int primaryColor;
|
||||||
|
|
||||||
public HabitStreakView(Context context, Habit habit, int columnWidth)
|
public HabitStreakView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context, attrs);
|
||||||
this.habit = habit;
|
this.baseSize = (int) context.getResources().getDimension(R.dimen.small_square_size);
|
||||||
|
this.primaryColor = ColorHelper.palette[7];
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
setDimensions(columnWidth);
|
public void setHabit(Habit habit)
|
||||||
|
{
|
||||||
|
this.habit = habit;
|
||||||
|
this.primaryColor = habit.color;
|
||||||
|
createColors();
|
||||||
|
fetchData();
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
setDimensions(baseSize);
|
||||||
createPaints();
|
createPaints();
|
||||||
createColors();
|
createColors();
|
||||||
|
|
||||||
@@ -65,7 +89,7 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
{
|
{
|
||||||
colors = new int[4];
|
colors = new int[4];
|
||||||
colors[0] = Color.rgb(230, 230, 230);
|
colors[0] = Color.rgb(230, 230, 230);
|
||||||
colors[3] = habit.color;
|
colors[3] = primaryColor;
|
||||||
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);
|
||||||
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
colors[2] = ColorHelper.mixColors(colors[0], colors[3], 0.33f);
|
||||||
}
|
}
|
||||||
@@ -86,12 +110,59 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
|
|
||||||
protected void fetchData()
|
protected void fetchData()
|
||||||
{
|
{
|
||||||
streaks = habit.getStreaks();
|
if(isInEditMode())
|
||||||
|
generateRandomData();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(habit == null)
|
||||||
|
{
|
||||||
|
startTimes = endTimes = lengths = new long[0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Streak s : streaks)
|
List<Streak> streaks = habit.getStreaks();
|
||||||
maxStreakLength = Math.max(maxStreakLength, s.length);
|
int size = streaks.size();
|
||||||
|
|
||||||
|
startTimes = new long[size];
|
||||||
|
endTimes = new long[size];
|
||||||
|
lengths = new long[size];
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (Streak s : streaks)
|
||||||
|
{
|
||||||
|
startTimes[k] = s.start;
|
||||||
|
endTimes[k] = s.end;
|
||||||
|
lengths[k] = s.length;
|
||||||
|
k++;
|
||||||
|
|
||||||
|
maxStreakLength = Math.max(maxStreakLength, s.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateRandomData()
|
||||||
|
{
|
||||||
|
int size = 30;
|
||||||
|
|
||||||
|
startTimes = new long[size];
|
||||||
|
endTimes = new long[size];
|
||||||
|
lengths = new long[size];
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
Long date = DateHelper.getStartOfToday();
|
||||||
|
|
||||||
|
for(int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
int l = (int) Math.pow(2, random.nextFloat() * 5 + 1);
|
||||||
|
|
||||||
|
endTimes[i] = date;
|
||||||
|
date -= l * DateHelper.millisecondsInOneDay;
|
||||||
|
lengths[i] = (long) l;
|
||||||
|
startTimes[i] = date;
|
||||||
|
|
||||||
|
maxStreakLength = Math.max(maxStreakLength, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas)
|
protected void onDraw(Canvas canvas)
|
||||||
@@ -101,7 +172,7 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
float lineHeight = pText.getFontSpacing();
|
float lineHeight = pText.getFontSpacing();
|
||||||
float barHeaderOffset = lineHeight * 0.4f;
|
float barHeaderOffset = lineHeight * 0.4f;
|
||||||
|
|
||||||
int nStreaks = streaks.size();
|
int nStreaks = startTimes.length;
|
||||||
int start = nStreaks - nColumns - dataOffset;
|
int start = nStreaks - nColumns - dataOffset;
|
||||||
|
|
||||||
String previousMonth = "";
|
String previousMonth = "";
|
||||||
@@ -109,9 +180,9 @@ public class HabitStreakView extends ScrollableDataView
|
|||||||
for (int offset = 0; offset < nColumns && start + offset < nStreaks; offset++)
|
for (int offset = 0; offset < nColumns && start + offset < nStreaks; offset++)
|
||||||
{
|
{
|
||||||
if(start + offset < 0) continue;
|
if(start + offset < 0) continue;
|
||||||
String month = dfMonth.format(streaks.get(start + offset).start);
|
String month = dfMonth.format(startTimes[start + offset]);
|
||||||
|
|
||||||
long l = streaks.get(offset + start).length;
|
long l = lengths[offset + start];
|
||||||
double lRelative = ((double) l) / maxStreakLength;
|
double lRelative = ((double) l) / maxStreakLength;
|
||||||
|
|
||||||
pBar.setColor(colors[(int) Math.floor(lRelative * 3)]);
|
pBar.setColor(colors[(int) Math.floor(lRelative * 3)]);
|
||||||
|
|||||||
@@ -21,34 +21,57 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
|
import org.isoron.helpers.ColorHelper;
|
||||||
|
import org.isoron.helpers.DialogHelper;
|
||||||
|
import org.isoron.uhabits.R;
|
||||||
|
|
||||||
public class RingView extends View
|
public class RingView extends View
|
||||||
{
|
{
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
private int color;
|
private int color;
|
||||||
private float perc;
|
private float percentage;
|
||||||
private Paint pRing;
|
private Paint pRing;
|
||||||
private float lineHeight;
|
private float lineHeight;
|
||||||
private String label;
|
private String label;
|
||||||
private RectF rect;
|
private RectF rect;
|
||||||
|
|
||||||
public RingView(Context context, int size, int color, float perc, String label)
|
public RingView(Context context, AttributeSet attrs)
|
||||||
|
{
|
||||||
|
super(context, attrs);
|
||||||
|
|
||||||
|
this.size = (int) context.getResources().getDimension(R.dimen.small_square_size) * 4;
|
||||||
|
this.label = DialogHelper.getAttribute(context, attrs, "label");
|
||||||
|
this.color = ColorHelper.palette[7];
|
||||||
|
this.percentage = 0.75f;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(int color)
|
||||||
{
|
{
|
||||||
super(context);
|
|
||||||
this.size = size;
|
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.perc = perc;
|
|
||||||
|
|
||||||
pRing = new Paint();
|
|
||||||
pRing.setColor(color);
|
pRing.setColor(color);
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPercentage(float percentage)
|
||||||
|
{
|
||||||
|
this.percentage = percentage;
|
||||||
|
postInvalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init()
|
||||||
|
{
|
||||||
|
pRing = new Paint();
|
||||||
pRing.setAntiAlias(true);
|
pRing.setAntiAlias(true);
|
||||||
|
pRing.setColor(color);
|
||||||
pRing.setTextAlign(Paint.Align.CENTER);
|
pRing.setTextAlign(Paint.Align.CENTER);
|
||||||
|
pRing.setTextSize(size * 0.2f);
|
||||||
|
lineHeight = pRing.getFontSpacing();
|
||||||
rect = new RectF();
|
rect = new RectF();
|
||||||
|
|
||||||
this.label = label;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,10 +89,10 @@ public class RingView extends View
|
|||||||
|
|
||||||
pRing.setColor(color);
|
pRing.setColor(color);
|
||||||
rect.set(0, 0, size, size);
|
rect.set(0, 0, size, size);
|
||||||
canvas.drawArc(rect, -90, 360 * perc, true, pRing);
|
canvas.drawArc(rect, -90, 360 * percentage, true, pRing);
|
||||||
|
|
||||||
pRing.setColor(Color.rgb(230, 230, 230));
|
pRing.setColor(Color.rgb(230, 230, 230));
|
||||||
canvas.drawArc(rect, 360 * perc - 90 + 2, 360 * (1 - perc) - 4, true, pRing);
|
canvas.drawArc(rect, 360 * percentage - 90 + 2, 360 * (1 - percentage) - 4, true, pRing);
|
||||||
|
|
||||||
pRing.setColor(Color.WHITE);
|
pRing.setColor(Color.WHITE);
|
||||||
rect.inset(thickness, thickness);
|
rect.inset(thickness, thickness);
|
||||||
@@ -77,8 +100,7 @@ public class RingView extends View
|
|||||||
|
|
||||||
pRing.setColor(Color.GRAY);
|
pRing.setColor(Color.GRAY);
|
||||||
pRing.setTextSize(size * 0.2f);
|
pRing.setTextSize(size * 0.2f);
|
||||||
lineHeight = pRing.getFontSpacing();
|
canvas.drawText(String.format("%.0f%%", percentage * 100), rect.centerX(),
|
||||||
canvas.drawText(String.format("%.0f%%", perc * 100), rect.centerX(),
|
|
||||||
rect.centerY() + lineHeight / 3, pRing);
|
rect.centerY() + lineHeight / 3, pRing);
|
||||||
|
|
||||||
pRing.setTextSize(size * 0.15f);
|
pRing.setTextSize(size * 0.15f);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package org.isoron.uhabits.views;
|
|||||||
|
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -42,7 +43,17 @@ public abstract class ScrollableDataView extends View implements GestureDetector
|
|||||||
public ScrollableDataView(Context context)
|
public ScrollableDataView(Context context)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScrollableDataView(Context context, AttributeSet attrs)
|
||||||
|
{
|
||||||
|
super(context, attrs);
|
||||||
|
init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(Context context)
|
||||||
|
{
|
||||||
detector = new GestureDetector(context, this);
|
detector = new GestureDetector(context, this);
|
||||||
scroller = new Scroller(context, null, true);
|
scroller = new Scroller(context, null, true);
|
||||||
scrollAnimator = ValueAnimator.ofFloat(0, 1);
|
scrollAnimator = ValueAnimator.ofFloat(0, 1);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://isoron.org/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@color/windowBackground"
|
android:background="@color/windowBackground"
|
||||||
@@ -19,6 +20,12 @@
|
|||||||
style="@style/cardHeaderStyle"
|
style="@style/cardHeaderStyle"
|
||||||
android:text="@string/overview"/>
|
android:text="@string/overview"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.views.RingView
|
||||||
|
android:id="@+id/scoreRing"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:label="@string/habit_strength"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -31,6 +38,11 @@
|
|||||||
style="@style/cardHeaderStyle"
|
style="@style/cardHeaderStyle"
|
||||||
android:text="@string/habit_strength"/>
|
android:text="@string/habit_strength"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.views.HabitScoreView
|
||||||
|
android:id="@+id/scoreView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout style="@style/cardStyle">
|
<LinearLayout style="@style/cardStyle">
|
||||||
@@ -45,6 +57,12 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"/>
|
android:orientation="horizontal"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.views.HabitHistoryView
|
||||||
|
android:id="@+id/historyView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout style="@style/cardStyle">
|
<LinearLayout style="@style/cardStyle">
|
||||||
@@ -59,6 +77,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"/>
|
android:orientation="horizontal"/>
|
||||||
|
|
||||||
|
<org.isoron.uhabits.views.HabitStreakView
|
||||||
|
android:id="@+id/streakView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -4,12 +4,15 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="org.isoron.uhabits.ShowHabitActivity"
|
tools:context="org.isoron.uhabits.ShowHabitActivity"
|
||||||
tools:ignore="MergeRootFrame" >
|
tools:ignore="MergeRootFrame"
|
||||||
|
tools:menu="show_habit_activity_menu,show_habit_fragment_menu">
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/fragment2"
|
android:id="@+id/fragment2"
|
||||||
android:name="org.isoron.uhabits.fragments.ShowHabitFragment"
|
android:name="org.isoron.uhabits.fragments.ShowHabitFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent"
|
||||||
|
tools:layout="@layout/show_habit"
|
||||||
|
android:layout_gravity="center"/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user