Merge branch 'feature/ring-view' into dev

pull/84/merge
Alinson S. Xavier 10 years ago
commit 7e4c508d7d

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -25,7 +25,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import org.isoron.uhabits.helpers.DateHelper; import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.unit.HabitFixtures; import org.isoron.uhabits.unit.HabitFixtures;
import org.isoron.uhabits.views.CheckmarkView; import org.isoron.uhabits.views.CheckmarkWidgetView;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -34,9 +34,9 @@ import java.io.IOException;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class CheckmarkViewTest extends ViewTest public class CheckmarkWidgetViewTest extends ViewTest
{ {
private CheckmarkView view; private CheckmarkWidgetView view;
private Habit habit; private Habit habit;
@Before @Before
@ -45,7 +45,7 @@ public class CheckmarkViewTest extends ViewTest
super.setup(); super.setup();
habit = HabitFixtures.createShortHabit(); habit = HabitFixtures.createShortHabit();
view = new CheckmarkView(targetContext); view = new CheckmarkWidgetView(targetContext);
view.setHabit(habit); view.setHabit(habit);
refreshData(view); refreshData(view);
measureView(dpToPixels(100), dpToPixels(200), view); measureView(dpToPixels(100), dpToPixels(200), view);

@ -62,7 +62,7 @@ public class HabitScoreViewTest extends ViewTest
@Test @Test
public void testRender_withTransparentBackground() throws Throwable public void testRender_withTransparentBackground() throws Throwable
{ {
view.setIsBackgroundTransparent(true); view.setIsTransparencyEnabled(true);
assertRenders(view, "HabitScoreView/renderTransparent.png"); assertRenders(view, "HabitScoreView/renderTransparent.png");
} }

@ -19,6 +19,7 @@
package org.isoron.uhabits.unit.views; package org.isoron.uhabits.unit.views;
import android.graphics.Color;
import android.support.test.runner.AndroidJUnit4; import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.SmallTest;
@ -42,10 +43,11 @@ public class RingViewTest extends ViewTest
super.setup(); super.setup();
view = new RingView(targetContext); view = new RingView(targetContext);
view.setLabel("Hello world");
view.setPercentage(0.6f); view.setPercentage(0.6f);
view.setText("60%");
view.setColor(ColorHelper.CSV_PALETTE[0]); view.setColor(ColorHelper.CSV_PALETTE[0]);
view.setMaxDiameter(dpToPixels(100)); view.setBackgroundColor(Color.WHITE);
view.setThickness(dpToPixels(3));
} }
@Test @Test
@ -55,21 +57,10 @@ public class RingViewTest extends ViewTest
assertRenders(view, "RingView/render.png"); assertRenders(view, "RingView/render.png");
} }
@Test
public void testRender_withLongLabel() throws IOException
{
view.setLabel("The quick brown fox jumps over the lazy fox");
measureView(dpToPixels(100), dpToPixels(100), view);
assertRenders(view, "RingView/renderLongLabel.png");
}
@Test @Test
public void testRender_withDifferentParams() throws IOException public void testRender_withDifferentParams() throws IOException
{ {
view.setLabel("Habit Strength");
view.setPercentage(0.25f); view.setPercentage(0.25f);
view.setMaxDiameter(dpToPixels(50));
view.setColor(ColorHelper.CSV_PALETTE[5]); view.setColor(ColorHelper.CSV_PALETTE[5]);
measureView(dpToPixels(200), dpToPixels(200), view); measureView(dpToPixels(200), dpToPixels(200), view);

@ -133,7 +133,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
if(toolbar == null) return; if(toolbar == null) return;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
toolbar.setElevation(UIHelper.dpToPixels(this, 3)); toolbar.setElevation(UIHelper.dpToPixels(this, 2));
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -197,5 +197,8 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U
{ {
View view = findViewById(R.id.toolbarShadow); View view = findViewById(R.id.toolbarShadow);
if(view != null) view.setVisibility(View.GONE); if(view != null) view.setVisibility(View.GONE);
view = findViewById(R.id.headerShadow);
if(view != null) view.setVisibility(View.GONE);
} }
} }

@ -61,6 +61,7 @@ import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.HintManager; import org.isoron.uhabits.helpers.HintManager;
import org.isoron.uhabits.helpers.ListHabitsHelper; import org.isoron.uhabits.helpers.ListHabitsHelper;
import org.isoron.uhabits.helpers.ReminderHelper; import org.isoron.uhabits.helpers.ReminderHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.helpers.UIHelper.OnSavedListener; import org.isoron.uhabits.helpers.UIHelper.OnSavedListener;
import org.isoron.uhabits.loaders.HabitListLoader; import org.isoron.uhabits.loaders.HabitListLoader;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
@ -121,7 +122,7 @@ public class ListHabitsFragment extends Fragment
loader.setCheckmarkCount(helper.getButtonCount()); loader.setCheckmarkCount(helper.getButtonCount());
llHint.setOnClickListener(this); llHint.setOnClickListener(this);
tvStarEmpty.setTypeface(helper.getFontawesome()); tvStarEmpty.setTypeface(UIHelper.getFontAwesome(activity));
adapter = new HabitListAdapter(getActivity(), loader); adapter = new HabitListAdapter(getActivity(), loader);
adapter.setSelectedPositions(selectedPositions); adapter.setSelectedPositions(selectedPositions);

@ -42,6 +42,7 @@ import org.isoron.uhabits.commands.Command;
import org.isoron.uhabits.dialogs.EditHabitDialogFragment; import org.isoron.uhabits.dialogs.EditHabitDialogFragment;
import org.isoron.uhabits.dialogs.HistoryEditorDialog; import org.isoron.uhabits.dialogs.HistoryEditorDialog;
import org.isoron.uhabits.helpers.ColorHelper; import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DateHelper;
import org.isoron.uhabits.helpers.ReminderHelper; import org.isoron.uhabits.helpers.ReminderHelper;
import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
@ -78,6 +79,13 @@ public class ShowHabitFragment extends Fragment
private int previousScoreInterval; private int previousScoreInterval;
private float todayScore;
private float lastMonthScore;
private float lastYearScore;
private int activeColor;
private int inactiveColor;
@Override @Override
public void onStart() public void onStart()
{ {
@ -90,7 +98,12 @@ public class ShowHabitFragment extends Fragment
{ {
View view = inflater.inflate(R.layout.show_habit, container, false); View view = inflater.inflate(R.layout.show_habit, container, false);
activity = (ShowHabitActivity) getActivity(); activity = (ShowHabitActivity) getActivity();
habit = activity.getHabit(); habit = activity.getHabit();
activeColor = ColorHelper.getColor(getContext(), habit.color);
inactiveColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
updateHeader(view);
dataViews = new LinkedList<>(); dataViews = new LinkedList<>();
@ -105,7 +118,6 @@ public class ShowHabitFragment extends Fragment
previousScoreInterval = defaultScoreInterval; previousScoreInterval = defaultScoreInterval;
setScoreBucketSize(defaultScoreInterval); setScoreBucketSize(defaultScoreInterval);
sStrengthInterval.setSelection(defaultScoreInterval); sStrengthInterval.setSelection(defaultScoreInterval);
sStrengthInterval.setOnItemSelectedListener(this); sStrengthInterval.setOnItemSelectedListener(this);
@ -147,6 +159,46 @@ public class ShowHabitFragment extends Fragment
return view; return view;
} }
private void updateHeader(View view)
{
if(habit == null) return;
TextView questionLabel = (TextView) view.findViewById(R.id.questionLabel);
questionLabel.setTextColor(activeColor);
questionLabel.setText(habit.description);
TextView reminderLabel = (TextView) view.findViewById(R.id.reminderLabel);
if(habit.hasReminder())
reminderLabel.setText(DateHelper.formatTime(getActivity(), habit.reminderHour,
habit.reminderMin));
else
reminderLabel.setText(getResources().getString(R.string.reminder_off));
TextView frequencyLabel = (TextView) view.findViewById(R.id.frequencyLabel);
String freqText;
if(habit.freqNum.equals(habit.freqDen))
freqText = getResources().getString(R.string.every_day);
else if(habit.freqNum == 1 && habit.freqDen == 7)
freqText = getResources().getString(R.string.every_week);
else
{
String times_every;
if(habit.freqNum == 1)
times_every = getResources().getString(R.string.time_every);
else
times_every = getResources().getString(R.string.times_every);
freqText = String.format("%d %s %d %s", habit.freqNum, times_every, habit.freqDen,
getResources().getString(R.string.days));
}
frequencyLabel.setText(freqText);
if(habit.description.isEmpty())
questionLabel.setVisibility(View.GONE);
}
@Override @Override
public void onResume() public void onResume()
{ {
@ -154,18 +206,34 @@ public class ShowHabitFragment extends Fragment
refreshData(); refreshData();
} }
private void updateScoreRing(View view) private void updateScore(View view)
{ {
if(habit == null) return; if(habit == null) return;
if(view == null) return; if(view == null) return;
float todayValue = (float) habit.scores.getTodayValue(); float todayPercentage = todayScore / Score.MAX_VALUE;
float percentage = todayValue / Score.MAX_VALUE; float monthDiff = todayPercentage - (lastMonthScore / Score.MAX_VALUE);
float yearDiff = todayPercentage - (lastYearScore / Score.MAX_VALUE);
RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing); RingView scoreRing = (RingView) view.findViewById(R.id.scoreRing);
int androidColor = ColorHelper.getColor(getActivity(), habit.color); int androidColor = ColorHelper.getColor(getActivity(), habit.color);
scoreRing.setColor(androidColor); scoreRing.setColor(androidColor);
scoreRing.setPercentage(percentage); scoreRing.setPercentage(todayPercentage);
TextView scoreLabel = (TextView) view.findViewById(R.id.scoreLabel);
TextView monthDiffLabel = (TextView) view.findViewById(R.id.monthDiffLabel);
TextView yearDiffLabel = (TextView) view.findViewById(R.id.yearDiffLabel);
scoreLabel.setText(String.format("%.0f%%", todayPercentage * 100));
String minus = "\u2212";
monthDiffLabel.setText(String.format("%s%.0f%%", (monthDiff >= 0 ? "+" : minus),
Math.abs(monthDiff) * 100));
yearDiffLabel.setText(
String.format("%s%.0f%%", (yearDiff >= 0 ? "+" : minus), Math.abs(yearDiff) * 100));
monthDiffLabel.setTextColor(monthDiff >= 0 ? activeColor : inactiveColor);
yearDiffLabel.setTextColor(yearDiff >= 0 ? activeColor : inactiveColor);
} }
private void updateHeaders(View view) private void updateHeaders(View view)
@ -175,6 +243,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.scoreLabel);
} }
private void updateColor(View view, int viewId) private void updateColor(View view, int viewId)
@ -236,25 +305,32 @@ public class ShowHabitFragment extends Fragment
{ {
new BaseTask() new BaseTask()
{ {
float percentage;
@Override @Override
protected void doInBackground() protected void doInBackground()
{ {
if(habit == null) return;
if(dataViews == null) return; if(dataViews == null) return;
long today = DateHelper.getStartOfToday();
long lastMonth = today - 30 * DateHelper.millisecondsInOneDay;
long lastYear = today - 365 * DateHelper.millisecondsInOneDay;
todayScore = (float) habit.scores.getTodayValue();
lastMonthScore = (float) habit.scores.getValue(lastMonth);
lastYearScore = (float) habit.scores.getValue(lastYear);
int count = 0; int count = 0;
for(HabitDataView view : dataViews) for(HabitDataView view : dataViews)
{ {
view.refreshData(); view.refreshData();
onProgressUpdate(count++); publishProgress(count++);
} }
} }
@Override @Override
protected void onProgressUpdate(Integer... values) protected void onProgressUpdate(Integer... values)
{ {
updateScoreRing(getView()); updateScore(getView());
if(dataViews == null) return; if(dataViews == null) return;
dataViews.get(values[0]).postInvalidate(); dataViews.get(values[0]).postInvalidate();
} }

@ -29,19 +29,19 @@ public class ColorHelper
{ {
public static int CSV_PALETTE[] = public static int CSV_PALETTE[] =
{ {
Color.parseColor("#D32F2F"), // red Color.parseColor("#D32F2F"), // 0 red
Color.parseColor("#E64A19"), // orange Color.parseColor("#E64A19"), // 1 orange
Color.parseColor("#F9A825"), // yellow Color.parseColor("#F9A825"), // 2 yellow
Color.parseColor("#AFB42B"), // light green Color.parseColor("#AFB42B"), // 3 light green
Color.parseColor("#388E3C"), // dark green Color.parseColor("#388E3C"), // 4 dark green
Color.parseColor("#00897B"), // teal Color.parseColor("#00897B"), // 5 teal
Color.parseColor("#00ACC1"), // cyan Color.parseColor("#00ACC1"), // 6 cyan
Color.parseColor("#039BE5"), // blue Color.parseColor("#039BE5"), // 7 blue
Color.parseColor("#5E35B1"), // deep purple Color.parseColor("#5E35B1"), // 8 deep purple
Color.parseColor("#8E24AA"), // purple Color.parseColor("#8E24AA"), // 9 purple
Color.parseColor("#D81B60"), // pink Color.parseColor("#D81B60"), // 10 pink
Color.parseColor("#303030"), // dark grey Color.parseColor("#303030"), // 11 dark grey
Color.parseColor("#aaaaaa") // light grey Color.parseColor("#aaaaaa") // 12 light grey
}; };
public static int colorToPaletteIndex(Context context, int color) public static int colorToPaletteIndex(Context context, int color)
@ -112,6 +112,12 @@ public class ColorHelper
return setHSVParameter(color, newValue, 2); return setHSVParameter(color, newValue, 2);
} }
public static int setAlpha(int color, float newAlpha)
{
int intAlpha = (int) (newAlpha * 255);
return Color.argb(intAlpha, Color.red(color), Color.green(color), Color.blue(color));
}
public static int setMinValue(int color, float newValue) public static int setMinValue(int color, float newValue)
{ {
float hsv[] = new float[3]; float hsv[] = new float[3];

@ -20,7 +20,6 @@
package org.isoron.uhabits.helpers; package org.isoron.uhabits.helpers;
import android.content.Context; import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -33,6 +32,7 @@ import org.isoron.uhabits.R;
import org.isoron.uhabits.loaders.HabitListLoader; import org.isoron.uhabits.loaders.HabitListLoader;
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.RingView;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
@ -43,7 +43,6 @@ public class ListHabitsHelper
private final Context context; private final Context context;
private final HabitListLoader loader; private final HabitListLoader loader;
private Typeface fontawesome;
public ListHabitsHelper(Context context, HabitListLoader loader) public ListHabitsHelper(Context context, HabitListLoader loader)
{ {
@ -52,12 +51,6 @@ public class ListHabitsHelper
lowContrastColor = UIHelper.getStyledColor(context, R.attr.lowContrastTextColor); lowContrastColor = UIHelper.getStyledColor(context, R.attr.lowContrastTextColor);
mediumContrastColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor); mediumContrastColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor);
fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
}
public Typeface getFontawesome()
{
return fontawesome;
} }
public int getButtonCount() public int getButtonCount()
@ -105,46 +98,24 @@ public class ListHabitsHelper
public void initializeLabelAndIcon(View itemView) public void initializeLabelAndIcon(View itemView)
{ {
TextView tvStar = (TextView) itemView.findViewById(R.id.tvStar);
tvStar.setTypeface(getFontawesome());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getHabitNameWidth(), LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(getHabitNameWidth(),
LinearLayout.LayoutParams.WRAP_CONTENT, 1); LinearLayout.LayoutParams.WRAP_CONTENT, 1);
itemView.findViewById(R.id.label).setLayoutParams(params); itemView.findViewById(R.id.label).setLayoutParams(params);
} }
public void updateNameAndIcon(Habit habit, TextView tvStar, TextView tvName) public void updateNameAndIcon(Habit habit, RingView ring, TextView tvName)
{ {
int activeColor = getActiveColor(habit); int activeColor = getActiveColor(habit);
tvName.setText(habit.name); tvName.setText(habit.name);
tvName.setTextColor(activeColor); tvName.setTextColor(activeColor);
if (habit.isArchived())
{
tvStar.setText(context.getString(R.string.fa_archive));
tvStar.setTextColor(activeColor);
}
else
{
int score = loader.scores.get(habit.getId()); int score = loader.scores.get(habit.getId());
float percentage = (float) score / Score.MAX_VALUE;
if (score < Score.HALF_STAR_CUTOFF) ring.setColor(activeColor);
{ ring.setPercentage(percentage);
tvStar.setText(context.getString(R.string.fa_star_o)); ring.setPrecision(1.0f / 16);
tvStar.setTextColor(lowContrastColor);
}
else if (score < Score.FULL_STAR_CUTOFF)
{
tvStar.setText(context.getString(R.string.fa_star_half_o));
tvStar.setTextColor(lowContrastColor);
}
else
{
tvStar.setText(context.getString(R.string.fa_star));
tvStar.setTextColor(activeColor);
}
}
} }
public void updateCheckmark(int activeColor, TextView tvCheck, int check) public void updateCheckmark(int activeColor, TextView tvCheck, int check)
@ -184,7 +155,7 @@ public class ListHabitsHelper
public void updateHabitCard(View view, Habit habit, boolean selected) public void updateHabitCard(View view, Habit habit, boolean selected)
{ {
TextView tvStar = ((TextView) view.findViewById(R.id.tvStar)); RingView scoreRing = ((RingView) view.findViewById(R.id.scoreRing));
TextView tvName = (TextView) view.findViewById(R.id.label); TextView tvName = (TextView) view.findViewById(R.id.label);
LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner); LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner);
LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons); LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons);
@ -192,7 +163,7 @@ public class ListHabitsHelper
llInner.setTag(R.string.habit_key, habit.getId()); llInner.setTag(R.string.habit_key, habit.getId());
llInner.setOnTouchListener(new HotspotTouchListener()); llInner.setOnTouchListener(new HotspotTouchListener());
updateNameAndIcon(habit, tvStar, tvName); updateNameAndIcon(habit, scoreRing, tvName);
updateCheckmarkButtons(habit, llButtons); updateCheckmarkButtons(habit, llButtons);
updateHabitCardBackground(llInner, selected); updateHabitCardBackground(llInner, selected);
} }
@ -227,7 +198,7 @@ public class ListHabitsHelper
{ {
View check = inflater.inflate(R.layout.list_habits_item_check, null); View check = inflater.inflate(R.layout.list_habits_item_check, null);
TextView btCheck = (TextView) check.findViewById(R.id.tvCheck); TextView btCheck = (TextView) check.findViewById(R.id.tvCheck);
btCheck.setTypeface(fontawesome); btCheck.setTypeface(UIHelper.getFontAwesome(context));
btCheck.setOnLongClickListener(onLongClickListener); btCheck.setOnLongClickListener(onLongClickListener);
btCheck.setOnClickListener(onClickListener); btCheck.setOnClickListener(onClickListener);
btCheck.setHapticFeedbackEnabled(false); btCheck.setHapticFeedbackEnabled(false);

@ -50,13 +50,21 @@ public abstract class UIHelper
public static final int THEME_LIGHT = 0; public static final int THEME_LIGHT = 0;
public static final int THEME_DARK = 1; public static final int THEME_DARK = 1;
private static Typeface fontawesome; private static Typeface fontAwesome;
public interface OnSavedListener public interface OnSavedListener
{ {
void onSaved(Command command, Object savedObject); void onSaved(Command command, Object savedObject);
} }
public static Typeface getFontAwesome(Context context)
{
if(fontAwesome == null)
fontAwesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
return fontAwesome;
}
public static void showSoftKeyboard(View view) public static void showSoftKeyboard(View view)
{ {
InputMethodManager imm = (InputMethodManager) view.getContext() InputMethodManager imm = (InputMethodManager) view.getContext()
@ -94,6 +102,14 @@ public abstract class UIHelper
else return defaultValue; else return defaultValue;
} }
public static Integer getColorAttribute(Context context, AttributeSet attrs, String name,
Integer defaultValue)
{
int resId = attrs.getAttributeResourceValue(ISORON_NAMESPACE, name, 0);
if (resId != 0) return context.getResources().getColor(resId);
else return defaultValue;
}
public static int getIntAttribute(Context context, AttributeSet attrs, String name, public static int getIntAttribute(Context context, AttributeSet attrs, String name,
int defaultValue) int defaultValue)
{ {
@ -102,6 +118,14 @@ public abstract class UIHelper
else return defaultValue; else return defaultValue;
} }
public static boolean getBooleanAttribute(Context context, AttributeSet attrs, String name,
boolean defaultValue)
{
String boolText = getAttribute(context, attrs, name, null);
if(boolText != null) return Boolean.parseBoolean(boolText);
else return defaultValue;
}
public static float getFloatAttribute(Context context, AttributeSet attrs, String name, public static float getFloatAttribute(Context context, AttributeSet attrs, String name,
float defaultValue) float defaultValue)
{ {
@ -206,6 +230,16 @@ public abstract class UIHelper
return bool; return bool;
} }
public static float getStyledFloat(Context context, int attrId)
{
int[] attrs = new int[]{ attrId };
TypedArray ta = context.obtainStyledAttributes(attrs);
float f = ta.getFloat(0, 0);
ta.recycle();
return f;
}
static int getStyleResource(Context context, int attrId) static int getStyleResource(Context context, int attrId)
{ {
int[] attr = new int[] { attrId }; int[] attr = new int[] { attrId };

@ -1,203 +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.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.models.Habit;
public class CheckmarkView extends View implements HabitDataView
{
private Paint pCard;
private Paint pIcon;
private int primaryColor;
private int timesColor;
private int darkGrey;
private int width;
private int height;
private float leftMargin;
private float topMargin;
private float padding;
private String label;
private String fa_check;
private String fa_times;
private int check_status;
private Rect rect;
private TextPaint textPaint;
private StaticLayout labelLayout;
private Habit habit;
public CheckmarkView(Context context)
{
super(context);
init(context);
}
public CheckmarkView(Context context, AttributeSet attrs)
{
super(context, attrs);
init(context);
}
private void init(Context context)
{
Typeface fontawesome =
Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf");
pCard = new Paint();
pCard.setAntiAlias(true);
pIcon = new Paint();
pIcon.setAntiAlias(true);
pIcon.setTypeface(fontawesome);
pIcon.setTextAlign(Paint.Align.CENTER);
textPaint = new TextPaint();
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
fa_check = context.getString(R.string.fa_check);
fa_times = context.getString(R.string.fa_times);
primaryColor = ColorHelper.getColor(getContext(), 10);
timesColor = Color.argb(128, 255, 255, 255);
darkGrey = Color.argb(64, 0, 0, 0);
rect = new Rect();
check_status = 0;
label = "Habit";
}
public void setHabit(Habit habit)
{
this.habit = habit;
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
drawBackground(canvas);
drawCheckmark(canvas);
drawLabel(canvas);
}
private void drawBackground(Canvas canvas)
{
int color = (check_status == 2 ? primaryColor : darkGrey);
pCard.setColor(color);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
canvas.drawRoundRect(leftMargin, topMargin, width - leftMargin, height - topMargin, padding,
padding, pCard);
else
canvas.drawRect(leftMargin, topMargin, width - leftMargin, height - topMargin, pCard);
}
private void drawCheckmark(Canvas canvas)
{
String text = (check_status == 0 ? fa_times : fa_check);
int color = (check_status == 2 ? Color.WHITE : timesColor);
pIcon.setColor(color);
pIcon.setTextSize(width * 0.5f);
pIcon.getTextBounds(text, 0, 1, rect);
int y = (int) ((0.67f * height - rect.bottom - rect.top) / 2);
canvas.drawText(text, width / 2, y, pIcon);
}
private void drawLabel(Canvas canvas)
{
canvas.save();
float y;
int nLines = labelLayout.getLineCount();
if(nLines == 1)
y = height * 0.8f - padding;
else
y = height * 0.7f - padding;
canvas.translate(leftMargin + padding, y);
labelLayout.draw(canvas);
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, (int) (width * 1.25));
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
{
this.width = getMeasuredWidth();
this.height = getMeasuredHeight();
leftMargin = (width * 0.015f);
topMargin = (height * 0.015f);
padding = 8 * leftMargin;
textPaint.setTextSize(0.15f * width);
updateLabel();
}
public void refreshData()
{
this.check_status = habit.checkmarks.getTodayValue();
int color = ColorHelper.getColor(getContext(), habit.color);
this.primaryColor = Color.argb(230, Color.red(color), Color.green(color),
Color.blue(color));
this.label = habit.name;
updateLabel();
postInvalidate();
}
private void updateLabel()
{
textPaint.setColor(Color.WHITE);
labelLayout = new StaticLayout(label, textPaint,
(int) (width - 2 * leftMargin - 2 * padding),
Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
}
}

@ -0,0 +1,169 @@
/*
* 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.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Checkmark;
import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.models.Score;
public class CheckmarkWidgetView extends HabitWidgetView implements HabitDataView
{
private int activeColor;
private float percentage;
@Nullable
private String name;
@Nullable
private RingView ring;
private TextView label;
private int checkmarkValue;
public CheckmarkWidgetView(Context context)
{
super(context);
init();
}
public CheckmarkWidgetView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
ring = (RingView) findViewById(R.id.scoreRing);
label = (TextView) findViewById(R.id.label);
if(ring != null) ring.setIsTransparencyEnabled(true);
if(isInEditMode())
{
percentage = 0.75f;
name = "Wake up early";
activeColor = ColorHelper.CSV_PALETTE[6];
checkmarkValue = Checkmark.CHECKED_EXPLICITLY;
refresh();
}
}
@Override
public void setHabit(@NonNull Habit habit)
{
super.setHabit(habit);
this.name = habit.name;
this.activeColor = ColorHelper.getColor(getContext(), habit.color);
refresh();
}
public void refresh()
{
if (backgroundPaint == null || frame == null || ring == null) return;
Context context = getContext();
String text;
int backgroundColor;
int foregroundColor;
switch (checkmarkValue)
{
case Checkmark.CHECKED_EXPLICITLY:
text = getResources().getString(R.string.fa_check);
backgroundColor = activeColor;
foregroundColor =
UIHelper.getStyledColor(context, R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f);
rebuildBackground();
backgroundPaint.setColor(backgroundColor);
frame.setBackgroundDrawable(background);
break;
case Checkmark.CHECKED_IMPLICITLY:
text = getResources().getString(R.string.fa_check);
backgroundColor = UIHelper.getStyledColor(context, R.attr.cardBackgroundColor);
foregroundColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor);
break;
case Checkmark.UNCHECKED:
default:
text = getResources().getString(R.string.fa_times);
backgroundColor = UIHelper.getStyledColor(context, R.attr.cardBackgroundColor);
foregroundColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor);
break;
}
ring.setPercentage(percentage);
ring.setColor(foregroundColor);
ring.setBackgroundColor(backgroundColor);
ring.setText(text);
label.setText(name);
label.setTextColor(foregroundColor);
requestLayout();
postInvalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
float w = width;
float h = width * 1.25f;
float scale = Math.min(width / w, height / h);
w *= scale;
h *= scale;
widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) w, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) h, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void refreshData()
{
if(habit == null) return;
this.percentage = (float) habit.scores.getTodayValue() / Score.MAX_VALUE;
this.checkmarkValue = habit.checkmarks.getTodayValue();
refresh();
}
@NonNull
protected Integer getInnerLayoutId()
{
return R.layout.widget_checkmark;
}
}

@ -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.support.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit;
public class GraphWidgetView extends HabitWidgetView implements HabitDataView
{
private final HabitDataView dataView;
private TextView title;
public GraphWidgetView(Context context, HabitDataView dataView)
{
super(context);
this.dataView = dataView;
init();
}
private void init()
{
ViewGroup.LayoutParams params =
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
((View) dataView).setLayoutParams(params);
ViewGroup innerFrame = (ViewGroup) findViewById(R.id.innerFrame);
innerFrame.addView(((View) dataView));
title = (TextView) findViewById(R.id.title);
title.setVisibility(VISIBLE);
}
@Override
public void setHabit(@NonNull Habit habit)
{
super.setHabit(habit);
dataView.setHabit(habit);
title.setText(habit.name);
}
@Override
public void refreshData()
{
if(habit == null) return;
dataView.refreshData();
}
@NonNull
protected Integer getInnerLayoutId()
{
return R.layout.widget_graph;
}
}

@ -21,7 +21,6 @@ package org.isoron.uhabits.views;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas; import android.graphics.Canvas;
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.util.AttributeSet;
@ -104,22 +103,10 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV
this.primaryColor = ColorHelper.getColor(getContext(), habit.color); this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
} }
if (isBackgroundTransparent)
{
primaryColor = ColorHelper.setSaturation(primaryColor, 0.75f);
primaryColor = ColorHelper.setValue(primaryColor, 1.0f);
textColor = Color.argb(192, 255, 255, 255);
gridColor = Color.argb(128, 255, 255, 255);
}
else
{
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
}
colors = new int[4]; colors = new int[4];
colors[0] = gridColor; colors[0] = gridColor;
colors[3] = primaryColor; colors[3] = primaryColor;
colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f); colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f);

@ -20,6 +20,7 @@
package org.isoron.uhabits.views; package org.isoron.uhabits.views;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
@ -72,11 +73,14 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
private int[] scores; private int[] scores;
private int primaryColor; private int primaryColor;
private boolean isBackgroundTransparent;
private int bucketSize = 7; private int bucketSize = 7;
private int footerHeight; private int footerHeight;
private int backgroundColor; private int backgroundColor;
private Bitmap drawingCache;
private Canvas cacheCanvas;
private boolean isTransparencyEnabled;
public HabitScoreView(Context context) public HabitScoreView(Context context)
{ {
super(context); super(context);
@ -114,21 +118,10 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
if(habit != null) if(habit != null)
this.primaryColor = ColorHelper.getColor(getContext(), habit.color); this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
if (isBackgroundTransparent)
{
primaryColor = ColorHelper.setSaturation(primaryColor, 0.75f);
primaryColor = ColorHelper.setValue(primaryColor, 1.0f);
textColor = Color.argb(192, 255, 255, 255);
gridColor = Color.argb(128, 255, 255, 255);
}
else
{
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor);
backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor);
} }
}
protected void createPaints() protected void createPaints()
{ {
@ -180,6 +173,16 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
pGraph.setTextSize(baseSize * 0.5f); pGraph.setTextSize(baseSize * 0.5f);
pGraph.setStrokeWidth(baseSize * 0.1f); pGraph.setStrokeWidth(baseSize * 0.1f);
pGrid.setStrokeWidth(baseSize * 0.025f); pGrid.setStrokeWidth(baseSize * 0.025f);
if(isTransparencyEnabled)
initCache(width, height);
}
private void initCache(int width, int height)
{
if (drawingCache != null) drawingCache.recycle();
drawingCache = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(drawingCache);
} }
public void refreshData() public void refreshData()
@ -218,12 +221,26 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
protected void onDraw(Canvas canvas) protected void onDraw(Canvas canvas)
{ {
super.onDraw(canvas); super.onDraw(canvas);
Canvas activeCanvas;
if(isTransparencyEnabled)
{
if(drawingCache == null) initCache(getWidth(), getHeight());
activeCanvas = cacheCanvas;
drawingCache.eraseColor(Color.TRANSPARENT);
}
else
{
activeCanvas = canvas;
}
if (habit == null || scores == null) return; if (habit == null || scores == null) return;
rect.set(0, 0, nColumns * columnWidth, columnHeight); rect.set(0, 0, nColumns * columnWidth, columnHeight);
rect.offset(0, paddingTop); rect.offset(0, paddingTop);
drawGrid(canvas, rect); drawGrid(activeCanvas, rect);
pText.setColor(textColor); pText.setColor(textColor);
pGraph.setColor(primaryColor); pGraph.setColor(primaryColor);
@ -253,20 +270,23 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
if (!prevRect.isEmpty()) if (!prevRect.isEmpty())
{ {
drawLine(canvas, prevRect, rect); drawLine(activeCanvas, prevRect, rect);
drawMarker(canvas, prevRect); drawMarker(activeCanvas, prevRect);
} }
if (k == nColumns - 1) drawMarker(canvas, rect); if (k == nColumns - 1) drawMarker(activeCanvas, rect);
prevRect.set(rect); prevRect.set(rect);
rect.set(0, 0, columnWidth, columnHeight); rect.set(0, 0, columnWidth, columnHeight);
rect.offset(k * columnWidth, paddingTop); rect.offset(k * columnWidth, paddingTop);
drawFooter(canvas, rect, currentDate); drawFooter(activeCanvas, rect, currentDate);
currentDate += bucketSize * DateHelper.millisecondsInOneDay; currentDate += bucketSize * DateHelper.millisecondsInOneDay;
} }
if(activeCanvas != canvas)
canvas.drawBitmap(drawingCache, 0, 0, null);
} }
private int skipYear = 0; private int skipYear = 0;
@ -364,19 +384,20 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView
setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor); setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor);
canvas.drawOval(rect, pGraph); canvas.drawOval(rect, pGraph);
if(isBackgroundTransparent) if(isTransparencyEnabled)
pGraph.setXfermode(XFERMODE_SRC); pGraph.setXfermode(XFERMODE_SRC);
} }
public void setIsBackgroundTransparent(boolean isBackgroundTransparent) public void setIsTransparencyEnabled(boolean enabled)
{ {
this.isBackgroundTransparent = isBackgroundTransparent; this.isTransparencyEnabled = enabled;
createColors(); createColors();
requestLayout();
} }
private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color) private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color)
{ {
if(isBackgroundTransparent) if(isTransparencyEnabled)
p.setXfermode(mode); p.setXfermode(mode);
else else
p.setColor(color); p.setColor(color);

@ -127,28 +127,10 @@ public class HabitStreakView extends View implements HabitDataView
if(habit != null) if(habit != null)
this.primaryColor = ColorHelper.getColor(getContext(), habit.color); this.primaryColor = ColorHelper.getColor(getContext(), habit.color);
if(isBackgroundTransparent)
{
primaryColor = ColorHelper.setSaturation(primaryColor, 0.75f);
primaryColor = ColorHelper.setValue(primaryColor, 1.0f);
}
int red = Color.red(primaryColor); int red = Color.red(primaryColor);
int green = Color.green(primaryColor); int green = Color.green(primaryColor);
int blue = Color.blue(primaryColor); int blue = Color.blue(primaryColor);
if(isBackgroundTransparent)
{
colors = new int[4];
colors[3] = primaryColor;
colors[2] = Color.argb(213, red, green, blue);
colors[1] = Color.argb(170, red, green, blue);
colors[0] = Color.argb(128, red, green, blue);
textColor = Color.WHITE;
reverseTextColor = Color.WHITE;
}
else
{
colors = new int[4]; colors = new int[4];
colors[3] = primaryColor; colors[3] = primaryColor;
colors[2] = Color.argb(192, red, green, blue); colors[2] = Color.argb(192, red, green, blue);
@ -157,7 +139,6 @@ public class HabitStreakView extends View implements HabitDataView
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor); reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor);
} }
}
protected void createPaints() protected void createPaints()
{ {

@ -0,0 +1,118 @@
/*
* 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.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.UIHelper;
import org.isoron.uhabits.models.Habit;
import java.util.Arrays;
public abstract class HabitWidgetView extends FrameLayout implements HabitDataView
{
@Nullable
protected InsetDrawable background;
@Nullable
protected Paint backgroundPaint;
@Nullable
protected Habit habit;
protected ViewGroup frame;
public void setShadowAlpha(int shadowAlpha)
{
this.shadowAlpha = shadowAlpha;
}
private int shadowAlpha;
public HabitWidgetView(Context context)
{
super(context);
init();
}
public HabitWidgetView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
private void init()
{
inflate(getContext(), getInnerLayoutId(), this);
shadowAlpha = (int) (255 * UIHelper.getStyledFloat(getContext(), R.attr.widgetShadowAlpha));
rebuildBackground();
}
protected abstract @NonNull Integer getInnerLayoutId();
protected void rebuildBackground()
{
Context context = getContext();
context.setTheme(R.style.TransparentWidgetTheme);
int backgroundAlpha =
(int) (255 * UIHelper.getStyledFloat(context, R.attr.widgetBackgroundAlpha));
int shadowRadius = (int) UIHelper.dpToPixels(context, 2);
int shadowOffset = (int) UIHelper.dpToPixels(context, 1);
int shadowColor = Color.argb(shadowAlpha, 0, 0, 0);
float cornerRadius = UIHelper.dpToPixels(context, 5);
float[] radii = new float[8];
Arrays.fill(radii, cornerRadius);
RoundRectShape shape = new RoundRectShape(radii, null, null);
ShapeDrawable innerDrawable = new ShapeDrawable(shape);
int insetLeftTop = Math.max(shadowRadius - shadowOffset, 0);
int insetRightBottom = shadowRadius + shadowOffset;
background = new InsetDrawable(innerDrawable, insetLeftTop, insetLeftTop, insetRightBottom,
insetRightBottom);
backgroundPaint = innerDrawable.getPaint();
backgroundPaint.setShadowLayer(shadowRadius, shadowOffset, shadowOffset, shadowColor);
backgroundPaint.setColor(UIHelper.getStyledColor(context, R.attr.cardBackgroundColor));
backgroundPaint.setAlpha(backgroundAlpha);
frame = (ViewGroup) findViewById(R.id.frame);
if(frame != null) frame.setBackgroundDrawable(background);
}
@Override
public void setHabit(@NonNull Habit habit)
{
this.habit = habit;
}
}

@ -19,42 +19,59 @@
package org.isoron.uhabits.views; package org.isoron.uhabits.views;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF; import android.graphics.RectF;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint; import android.text.TextPaint;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.helpers.UIHelper;
public class RingView extends View public class RingView extends View
{ {
public static final PorterDuffXfermode XFERMODE_CLEAR =
new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
private int color; private int color;
private float precision;
private float percentage; private float percentage;
private float labelMarginTop; private int diameter;
private TextPaint pRing; private float thickness;
private String label;
private RectF rect; private RectF rect;
private StaticLayout labelLayout; private TextPaint pRing;
private int width; private Integer backgroundColor;
private int height; private Integer inactiveColor;
private float diameter;
private float maxDiameter; private float em;
private String text;
private float textSize; private float textSize;
private int textColor; private boolean enableFontAwesome;
private int backgroundColor;
private Bitmap drawingCache;
private Canvas cacheCanvas;
private boolean isTransparencyEnabled;
public RingView(Context context) public RingView(Context context)
{ {
super(context); super(context);
percentage = 0.0f;
precision = 0.01f;
color = ColorHelper.CSV_PALETTE[0];
thickness = UIHelper.dpToPixels(getContext(), 2);
text = "";
textSize = context.getResources().getDimension(R.dimen.smallTextSize);
init(); init();
} }
@ -62,9 +79,24 @@ public class RingView extends View
{ {
super(context, attrs); super(context, attrs);
this.label = UIHelper.getAttribute(context, attrs, "label", "Label"); percentage = UIHelper.getFloatAttribute(context, attrs, "percentage", 0);
this.maxDiameter = UIHelper.getFloatAttribute(context, attrs, "maxDiameter", 100); precision = UIHelper.getFloatAttribute(context, attrs, "precision", 0.01f);
this.maxDiameter = UIHelper.dpToPixels(context, maxDiameter);
color = UIHelper.getColorAttribute(context, attrs, "color", 0);
backgroundColor = UIHelper.getColorAttribute(context, attrs, "backgroundColor", null);
inactiveColor = UIHelper.getColorAttribute(context, attrs, "inactiveColor", null);
thickness = UIHelper.getFloatAttribute(context, attrs, "thickness", 0);
thickness = UIHelper.dpToPixels(context, thickness);
float defaultTextSize = context.getResources().getDimension(R.dimen.smallTextSize);
textSize = UIHelper.getFloatAttribute(context, attrs, "textSize", defaultTextSize);
textSize = UIHelper.spToPixels(context, textSize);
text = UIHelper.getAttribute(context, attrs, "text", "");
enableFontAwesome = UIHelper.getBooleanAttribute(context, attrs, "enableFontAwesome", false);
init(); init();
} }
@ -74,19 +106,34 @@ public class RingView extends View
postInvalidate(); postInvalidate();
} }
public void setMaxDiameter(float maxDiameter) @Override
public void setBackgroundColor(int backgroundColor)
{ {
this.maxDiameter = maxDiameter; this.backgroundColor = backgroundColor;
postInvalidate();
} }
public void setLabel(String label) public void setPercentage(float percentage)
{ {
this.label = label; this.percentage = percentage;
postInvalidate();
} }
public void setPercentage(float percentage) public void setPrecision(float precision)
{ {
this.percentage = percentage; this.precision = precision;
postInvalidate();
}
public void setThickness(float thickness)
{
this.thickness = thickness;
postInvalidate();
}
public void setText(String text)
{
this.text = text;
postInvalidate(); postInvalidate();
} }
@ -97,61 +144,94 @@ public class RingView extends View
pRing.setColor(color); pRing.setColor(color);
pRing.setTextAlign(Paint.Align.CENTER); pRing.setTextAlign(Paint.Align.CENTER);
if(backgroundColor == null)
backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor);
textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor);
textSize = getResources().getDimension(R.dimen.smallTextSize); if(inactiveColor == null)
inactiveColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastTextColor);
inactiveColor = ColorHelper.setAlpha(inactiveColor, 0.1f);
rect = new RectF(); rect = new RectF();
} }
@Override @Override
@SuppressLint("DrawAllocation")
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{ {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec);
diameter = Math.min(height, width);
diameter = Math.min(maxDiameter, width);
pRing.setTextSize(textSize); pRing.setTextSize(textSize);
labelMarginTop = textSize * 0.80f; em = pRing.measureText("M");
labelLayout = new StaticLayout(label, pRing, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f,
false);
width = Math.max(width, labelLayout.getWidth()); setMeasuredDimension(diameter, diameter);
height = (int) (diameter + labelLayout.getHeight() + labelMarginTop); }
setMeasuredDimension(width, height); @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
super.onSizeChanged(w, h, oldw, oldh);
if(isTransparencyEnabled)
{
if (drawingCache != null) drawingCache.recycle();
drawingCache = Bitmap.createBitmap(diameter, diameter, Bitmap.Config.ARGB_8888);
cacheCanvas = new Canvas(drawingCache);
}
} }
@Override @Override
protected void onDraw(Canvas canvas) protected void onDraw(Canvas canvas)
{ {
super.onDraw(canvas); super.onDraw(canvas);
float thickness = diameter * 0.15f; Canvas activeCanvas;
if(isTransparencyEnabled)
{
activeCanvas = cacheCanvas;
drawingCache.eraseColor(Color.TRANSPARENT);
}
else
{
activeCanvas = canvas;
}
pRing.setColor(color); pRing.setColor(color);
rect.set(0, 0, diameter, diameter); rect.set(0, 0, diameter, diameter);
rect.offset((width - diameter) / 2, 0);
canvas.drawArc(rect, -90, 360 * percentage, true, pRing);
int grey = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); float angle = 360 * Math.round(percentage / precision) * precision;
pRing.setColor(grey);
canvas.drawArc(rect, 360 * percentage - 90 + 2, 360 * (1 - percentage) - 4, true, pRing); activeCanvas.drawArc(rect, -90, angle, true, pRing);
pRing.setColor(inactiveColor);
activeCanvas.drawArc(rect, angle - 90, 360 - angle, true, pRing);
if(thickness > 0)
{
if(isTransparencyEnabled)
pRing.setXfermode(XFERMODE_CLEAR);
else
pRing.setColor(backgroundColor); pRing.setColor(backgroundColor);
rect.inset(thickness, thickness); rect.inset(thickness, thickness);
canvas.drawArc(rect, -90, 360, true, pRing); activeCanvas.drawArc(rect, 0, 360, true, pRing);
pRing.setXfermode(null);
pRing.setColor(textColor); pRing.setColor(color);
pRing.setTextSize(textSize);
float lineHeight = pRing.getFontSpacing();
canvas.drawText(String.format("%.0f%%", percentage * 100), rect.centerX(),
rect.centerY() + lineHeight / 3, pRing);
pRing.setTextSize(textSize); pRing.setTextSize(textSize);
canvas.translate(width / 2, diameter + labelMarginTop); if(enableFontAwesome) pRing.setTypeface(UIHelper.getFontAwesome(getContext()));
labelLayout.draw(canvas); activeCanvas.drawText(text, rect.centerX(), rect.centerY() + 0.4f * em, pRing);
}
if(activeCanvas != canvas)
canvas.drawBitmap(drawingCache, 0, 0, null);
}
public void setIsTransparencyEnabled(boolean isTransparencyEnabled)
{
this.isTransparencyEnabled = isTransparencyEnabled;
} }
} }

@ -33,6 +33,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.TextView;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.helpers.UIHelper;
@ -123,23 +124,27 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
protected abstract void refreshCustomViewData(View widgetView); protected abstract void refreshCustomViewData(View widgetView);
private void savePreview(Context context, int widgetId, Bitmap widgetCache) private void savePreview(Context context, int widgetId, Bitmap widgetCache, int width,
int height, String label)
{ {
try try
{ {
LayoutInflater inflater = LayoutInflater.from(context); LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(getLayoutId(), null); View view = inflater.inflate(getLayoutId(), null);
TextView tvLabel = (TextView) view.findViewById(R.id.label);
if(tvLabel != null) tvLabel.setText(label);
ImageView iv = (ImageView) view.findViewById(R.id.imageView); ImageView iv = (ImageView) view.findViewById(R.id.imageView);
iv.setImageBitmap(widgetCache); if(iv != null) iv.setImageBitmap(widgetCache);
view.measure(portraitWidth, portraitHeight); view.measure(width, height);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.setDrawingCacheEnabled(true); view.setDrawingCacheEnabled(true);
view.buildDrawingCache(); view.buildDrawingCache();
Bitmap previewCache = view.getDrawingCache(); Bitmap previewCache = view.getDrawingCache();
String filename = String.format("%s/%d.png", context.getExternalCacheDir(), widgetId); String filename = String.format("%s/%d_%d.png", context.getExternalCacheDir(), widgetId, width);
Log.d("BaseWidgetProvider", String.format("Writing %s", filename)); Log.d("BaseWidgetProvider", String.format("Writing %s", filename));
FileOutputStream out = new FileOutputStream(filename); FileOutputStream out = new FileOutputStream(filename);
@ -254,8 +259,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
{ {
try try
{ {
buildRemoteViews(portraitWidgetView, portraitRemoteViews); buildRemoteViews(portraitWidgetView, portraitRemoteViews, portraitWidth, portraitHeight);
buildRemoteViews(landscapeWidgetView, landscapeRemoteViews); buildRemoteViews(landscapeWidgetView, landscapeRemoteViews, landscapeWidth, landscapeHeight);
updateAppWidget(); updateAppWidget();
} }
catch (Exception e) catch (Exception e)
@ -267,7 +272,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
super.onPostExecute(aVoid); super.onPostExecute(aVoid);
} }
private void buildRemoteViews(View widgetView, RemoteViews remoteViews) private void buildRemoteViews(View widgetView, RemoteViews remoteViews, int width, int height)
{ {
widgetView.invalidate(); widgetView.invalidate();
widgetView.setDrawingCacheEnabled(true); widgetView.setDrawingCacheEnabled(true);
@ -276,11 +281,29 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider
remoteViews.setTextViewText(R.id.label, habit.name); remoteViews.setTextViewText(R.id.label, habit.name);
remoteViews.setImageViewBitmap(R.id.imageView, drawingCache); remoteViews.setImageViewBitmap(R.id.imageView, drawingCache);
//savePreview(context, widgetId, drawingCache); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
int imageWidth = widgetView.getMeasuredWidth();
int imageHeight = widgetView.getMeasuredHeight();
int p[] = getPadding(width, height, imageWidth, imageHeight);
remoteViews.setViewPadding(R.id.buttonOverlay, p[0], p[1], p[2], p[3]);
}
//savePreview(context, widgetId, drawingCache, width, height, habit.name);
PendingIntent onClickIntent = getOnClickPendingIntent(context, habit); PendingIntent onClickIntent = getOnClickPendingIntent(context, habit);
if (onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.imageView, if (onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.button,
onClickIntent); onClickIntent);
} }
} }
private int[] getPadding(int entireWidth, int entireHeight, int imageWidth,
int imageHeight)
{
int w = (int) (((float) entireWidth - imageWidth) / 2);
int h = (int) (((float) entireHeight - imageHeight) / 2);
return new int[]{ w, h, w, h };
}
} }

@ -25,7 +25,7 @@ import android.view.View;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.CheckmarkView; import org.isoron.uhabits.views.CheckmarkWidgetView;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
public class CheckmarkWidgetProvider extends BaseWidgetProvider public class CheckmarkWidgetProvider extends BaseWidgetProvider
@ -33,7 +33,7 @@ public class CheckmarkWidgetProvider extends BaseWidgetProvider
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
CheckmarkView view = new CheckmarkView(context); CheckmarkWidgetView view = new CheckmarkWidgetView(context);
view.setHabit(habit); view.setHabit(habit);
return view; return view;
} }
@ -65,7 +65,7 @@ public class CheckmarkWidgetProvider extends BaseWidgetProvider
@Override @Override
protected int getLayoutId() protected int getLayoutId()
{ {
return R.layout.widget_checkmark; return R.layout.widget_wrapper;
} }

@ -26,6 +26,7 @@ import android.view.View;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.GraphWidgetView;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitFrequencyView; import org.isoron.uhabits.views.HabitFrequencyView;
@ -34,8 +35,8 @@ public class FrequencyWidgetProvider extends BaseWidgetProvider
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitFrequencyView view = new HabitFrequencyView(context, null); HabitFrequencyView dataView = new HabitFrequencyView(context);
view.setIsBackgroundTransparent(true); GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;
} }
@ -67,6 +68,6 @@ public class FrequencyWidgetProvider extends BaseWidgetProvider
@Override @Override
protected int getLayoutId() protected int getLayoutId()
{ {
return R.layout.widget_graph; return R.layout.widget_wrapper;
} }
} }

@ -25,6 +25,7 @@ import android.view.View;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.GraphWidgetView;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitHistoryView; import org.isoron.uhabits.views.HabitHistoryView;
@ -33,9 +34,9 @@ public class HistoryWidgetProvider extends BaseWidgetProvider
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitHistoryView view = new HabitHistoryView(context, null); HabitHistoryView dataView = new HabitHistoryView(context);
GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
view.setIsBackgroundTransparent(true);
return view; return view;
} }
@ -66,6 +67,6 @@ public class HistoryWidgetProvider extends BaseWidgetProvider
@Override @Override
protected int getLayoutId() protected int getLayoutId()
{ {
return R.layout.widget_graph; return R.layout.widget_wrapper;
} }
} }

@ -25,6 +25,7 @@ import android.view.View;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.GraphWidgetView;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitScoreView; import org.isoron.uhabits.views.HabitScoreView;
@ -33,8 +34,9 @@ public class ScoreWidgetProvider extends BaseWidgetProvider
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitScoreView view = new HabitScoreView(context, null); HabitScoreView dataView = new HabitScoreView(context);
view.setIsBackgroundTransparent(true); dataView.setIsTransparencyEnabled(true);
GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;
} }
@ -66,6 +68,6 @@ public class ScoreWidgetProvider extends BaseWidgetProvider
@Override @Override
protected int getLayoutId() protected int getLayoutId()
{ {
return R.layout.widget_graph; return R.layout.widget_wrapper;
} }
} }

@ -25,6 +25,7 @@ import android.view.View;
import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.HabitBroadcastReceiver;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Habit;
import org.isoron.uhabits.views.GraphWidgetView;
import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitDataView;
import org.isoron.uhabits.views.HabitStreakView; import org.isoron.uhabits.views.HabitStreakView;
@ -33,8 +34,8 @@ public class StreakWidgetProvider extends BaseWidgetProvider
@Override @Override
protected View buildCustomView(Context context, Habit habit) protected View buildCustomView(Context context, Habit habit)
{ {
HabitStreakView view = new HabitStreakView(context, null); HabitStreakView dataView = new HabitStreakView(context);
view.setIsBackgroundTransparent(true); GraphWidgetView view = new GraphWidgetView(context, dataView);
view.setHabit(habit); view.setHabit(habit);
return view; return view;
} }
@ -66,6 +67,6 @@ public class StreakWidgetProvider extends BaseWidgetProvider
@Override @Override
protected int getLayoutId() protected int getLayoutId()
{ {
return R.layout.widget_graph; return R.layout.widget_wrapper;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

@ -0,0 +1,39 @@
<!--
~ 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/>.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="1dp"
android:left="1dp"
android:bottom="3dp"
android:right="3dp">
<ripple
android:color="#60ffffff">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
<solid android:color="?android:colorPrimary"/>
</shape>
<color android:color="@color/white"/>
</item>
</ripple>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

@ -0,0 +1,34 @@
<!--
~ 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/>.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:state_pressed="true">
<layer-list>
<item android:bottom="3dp"
android:left="1dp"
android:right="3dp"
android:top="1dp">
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
<solid android:color="#30ffffff"/>
</shape>
</item>
</layer-list>
</item>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

@ -19,6 +19,7 @@
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:habit="http://isoron.org/android"
android:id="@+id/llOuter" android:id="@+id/llOuter"
style="@style/ListHabits.Item"> style="@style/ListHabits.Item">
@ -26,9 +27,14 @@
android:id="@+id/llInner" android:id="@+id/llInner"
style="@style/ListHabits.HabitCard"> style="@style/ListHabits.HabitCard">
<TextView <org.isoron.uhabits.views.RingView
android:id="@+id/tvStar" android:layout_height="15dp"
style="@style/ListHabits.Star" /> android:layout_width="15dp"
android:id="@+id/scoreRing"
habit:thickness="3"
android:layout_marginTop="0dp"
android:layout_marginRight="10dp"
android:layout_marginLeft="8dp"/>
<TextView <TextView
android:id="@+id/label" android:id="@+id/label"

@ -17,20 +17,102 @@
~ with this program. If not, see <http://www.gnu.org/licenses/>. ~ with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView
xmlns:app="http://isoron.org/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:habit="http://isoron.org/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?windowBackgroundColor" android:background="?windowBackgroundColor"
android:clipToPadding="false"
android:fillViewport="true"> android:fillViewport="true">
<LinearLayout <LinearLayout
style="@style/CardList" style="@style/CardList"
android:clipToPadding="false"
tools:context="org.isoron.uhabits.ShowHabitActivity"> tools:context="org.isoron.uhabits.ShowHabitActivity">
<LinearLayout
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?headerBackgroundColor"
android:elevation="2dp"
android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingLeft="60dp"
android:paddingStart="60dp"
android:paddingRight="10dp"
android:paddingEnd="10dp"
android:paddingTop="15dp">
<TextView
android:id="@+id/questionLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textColor="?mediumContrastTextColor"
android:textSize="@dimen/regularTextSize"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/frequencyIcon"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:alpha="0.3"
android:src="?iconFrequency"
/>
<TextView
android:id="@+id/frequencyLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/every_day"
android:textColor="?mediumContrastTextColor"
android:textSize="@dimen/smallTextSize"
/>
<ImageView
android:id="@+id/reminderIcon"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginRight="5dp"
android:layout_marginEnd="5dp"
android:alpha="0.3"
android:src="?iconReminder"
/>
<TextView
android:id="@+id/reminderLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="1dp"
android:textColor="?mediumContrastTextColor"
android:textSize="@dimen/smallTextSize"
/>
</LinearLayout>
</LinearLayout>
<View
android:id="@+id/headerShadow"
style="@style/ToolbarShadow"/>
<LinearLayout <LinearLayout
style="@style/Card" style="@style/Card"
android:paddingTop="12dp"
android:gravity="start"> android:gravity="start">
<TextView <TextView
@ -45,16 +127,80 @@
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
<FrameLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5">
<org.isoron.uhabits.views.RingView <org.isoron.uhabits.views.RingView
android:id="@+id/scoreRing" android:id="@+id/scoreRing"
style="@style/SmallDataView" android:layout_width="30dp"
android:layout_width="100dp" android:layout_height="30dp"
app:label="@string/strength" android:layout_gravity="center"
app:maxDiameter="80" habit:percentage="0"
app:textSize="@dimen/smallTextSize"/> habit:textSize="12"
habit:thickness="5"/>
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical">
<TextView
android:id="@+id/scoreLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/score"
android:textColor="?mediumContrastTextColor"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical">
<TextView
android:id="@+id/monthDiffLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/month"
android:textColor="?mediumContrastTextColor"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:orientation="vertical">
<TextView
android:id="@+id/yearDiffLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/year"
android:textColor="?mediumContrastTextColor"/>
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
<RelativeLayout <RelativeLayout
@ -65,20 +211,20 @@
android:id="@+id/sStrengthInterval" android:id="@+id/sStrengthInterval"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="22dp" android:layout_height="22dp"
android:entries="@array/strengthIntervalNames"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:entries="@array/strengthIntervalNames"
android:theme="@style/SmallSpinner" android:theme="@style/SmallSpinner"
/> />
<TextView <TextView
android:id="@+id/tvStrength" android:id="@+id/tvStrength"
style="@style/CardHeader" style="@style/CardHeader"
android:text="@string/habit_strength"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/> android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:text="@string/habit_strength"/>
<org.isoron.uhabits.views.HabitScoreView <org.isoron.uhabits.views.HabitScoreView
android:id="@+id/scoreView" android:id="@+id/scoreView"

@ -17,10 +17,11 @@
~ with this program. If not, see <http://www.gnu.org/licenses/>. ~ with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container" android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
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"
@ -29,18 +30,17 @@
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
app:popupTheme="?toolbarPopupTheme" style="@style/Toolbar"
app:popupTheme="?toolbarPopupTheme"/>
style="@style/Toolbar"/>
<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_below="@id/toolbar"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_below="@id/toolbar"/> tools:layout="@layout/show_habit"/>
<View <View
android:id="@+id/toolbarShadow" android:id="@+id/toolbarShadow"

@ -19,18 +19,42 @@
--> -->
<LinearLayout <LinearLayout
android:id="@+id/frame"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:habit="http://isoron.org/android"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical">
android:padding="0dp">
<ImageView <org.isoron.uhabits.views.RingView
android:id="@+id/imageView" android:id="@+id/scoreRing"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
android:adjustViewBounds="true" android:layout_weight="1"
/> habit:thickness="2"
habit:textSize="16"
habit:enableFontAwesome="true"
android:layout_marginTop="8dp"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"/>
<TextView
android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:textSize="12sp"
android:textColor="@color/white"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:gravity="center"
android:scrollHorizontally="true"
android:ellipsize="end"
android:maxLines="2"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:fontFamily="sans-serif-condensed"
android:breakStrategy="balanced" />
</LinearLayout> </LinearLayout>

@ -18,29 +18,33 @@
~ with this program. If not, see <http://www.gnu.org/licenses/>. ~ with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<LinearLayout <FrameLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frame"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/widget_background"
android:gravity="center" android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/innerFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:padding="4dp"> android:paddingTop="4dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingBottom="4dp"
tools:ignore="UselessParent">
<TextView <TextView
android:id="@+id/label" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:textColor="#ffffff"/> android:textColor="@color/white"/>
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:adjustViewBounds="true"
/>
</LinearLayout>
</LinearLayout> </FrameLayout>

@ -18,19 +18,32 @@
~ with this program. If not, see <http://www.gnu.org/licenses/>. ~ with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<LinearLayout <RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:padding="0dp">
android:padding="4dp">
<org.isoron.uhabits.views.CheckmarkView <ImageView
android:id="@+id/imageView" android:id="@+id/imageView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:adjustViewBounds="true" android:adjustViewBounds="true"
/> />
</LinearLayout> <FrameLayout
android:id="@+id/buttonOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/widget_button_background"
/>
</FrameLayout>
</RelativeLayout>

@ -41,9 +41,14 @@
<attr name="iconEdit" format="reference"/> <attr name="iconEdit" format="reference"/>
<attr name="iconUnarchive" format="reference"/> <attr name="iconUnarchive" format="reference"/>
<attr name="dialogIconChangeColor" format="reference"/> <attr name="dialogIconChangeColor" format="reference"/>
<attr name="iconReminder" format="reference"/>
<attr name="iconFrequency" format="reference"/>
<attr name="toolbarPopupTheme" format="reference"/> <attr name="toolbarPopupTheme" format="reference"/>
<attr name="widgetShadowAlpha" format="float"/>
<attr name="widgetBackgroundAlpha" format="float"/>
<!-- Pre-Lollipop --> <!-- Pre-Lollipop -->
<attr name="cardBackground" format="reference"/> <attr name="cardBackground" format="reference"/>
<attr name="headerBackground" format="reference"/> <attr name="headerBackground" format="reference"/>

@ -48,6 +48,22 @@
<item>@color/grey_500</item> <item>@color/grey_500</item>
</array> </array>
<array name="transparentWidgetPalette">
<item>@color/red_800</item>
<item>@color/deep_orange_800</item>
<item>@color/yellow_800</item>
<item>@color/lime_800</item>
<item>@color/green_700</item>
<item>@color/teal_700</item>
<item>@color/cyan_700</item>
<item>@color/light_blue_700</item>
<item>@color/deep_purple_700</item>
<item>@color/purple_700</item>
<item>@color/pink_700</item>
<item>@color/black_aa</item>
<item>@color/black_aa</item>
</array>
<!-- Time and Date picker --> <!-- Time and Date picker -->
<color name="circle_background">#f2f2f2</color> <color name="circle_background">#f2f2f2</color>
<color name="line_background">#cccccc</color> <color name="line_background">#cccccc</color>
@ -355,4 +371,22 @@
<color name="white">#ffffff</color> <color name="white">#ffffff</color>
<color name="black">#000000</color> <color name="black">#000000</color>
<color name="black_ae">#ef000000</color>
<color name="black_ac">#cf000000</color>
<color name="black_aa">#af000000</color>
<color name="black_a8">#8f000000</color>
<color name="black_a6">#6f000000</color>
<color name="black_a4">#4f000000</color>
<color name="black_a2">#2f000000</color>
<color name="black_a0">#0f000000</color>
<color name="white_ae">#efffffff</color>
<color name="white_ac">#cfffffff</color>
<color name="white_aa">#afffffff</color>
<color name="white_a8">#8fffffff</color>
<color name="white_a6">#6fffffff</color>
<color name="white_a4">#4fffffff</color>
<color name="white_a2">#2fffffff</color>
<color name="white_a0">#0fffffff</color>
</resources> </resources>

@ -156,6 +156,7 @@
<string name="bug_report_failed">Failed to generate bug report.</string> <string name="bug_report_failed">Failed to generate bug report.</string>
<string name="generate_bug_report">Generate bug report</string> <string name="generate_bug_report">Generate bug report</string>
<string name="troubleshooting">Troubleshooting</string> <string name="troubleshooting">Troubleshooting</string>
<string name="help_translate">Help translate this app</string> <string name="help_translate">Help translate this app</string>
<string name="night_mode">Night mode</string> <string name="night_mode">Night mode</string>
<string name="use_pure_black">Pure black for night mode</string> <string name="use_pure_black">Pure black for night mode</string>
@ -167,4 +168,12 @@
<string name="month">Month</string> <string name="month">Month</string>
<string name="quarter">Quarter</string> <string name="quarter">Quarter</string>
<string name="year">Year</string> <string name="year">Year</string>
<!-- Middle part of the sentence '1 time in xx days' -->
<string name="time_every">time in</string>
<string name="every_x_days">Every %d days</string>
<string name="every_x_weeks">Every %d weeks</string>
<string name="every_x_months">Every %d months</string>
<string name="score">Score</string>
</resources> </resources>

@ -56,10 +56,14 @@
<item name="iconEdit">@drawable/ic_action_edit_dark</item> <item name="iconEdit">@drawable/ic_action_edit_dark</item>
<item name="iconUnarchive">@drawable/ic_action_unarchive_dark</item> <item name="iconUnarchive">@drawable/ic_action_unarchive_dark</item>
<item name="iconChangeColor">@drawable/ic_action_color_dark</item> <item name="iconChangeColor">@drawable/ic_action_color_dark</item>
<item name="iconFrequency">@drawable/ic_repeat_black</item>
<item name="iconReminder">@drawable/ic_alarm_black</item>
<item name="dialogIconChangeColor">@drawable/ic_action_color_light</item> <item name="dialogIconChangeColor">@drawable/ic_action_color_light</item>
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item> <item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
<item name="aboutScreenColor">@color/blue_800</item> <item name="aboutScreenColor">@color/blue_800</item>
<item name="widgetShadowAlpha">0.25</item>
<item name="widgetBackgroundAlpha">1</item>
</style> </style>
<style name="SmallSpinner"> <style name="SmallSpinner">
@ -95,7 +99,7 @@
<item name="lowContrastTextColor">@color/grey_800</item> <item name="lowContrastTextColor">@color/grey_800</item>
<item name="highContrastReverseTextColor">@color/grey_900</item> <item name="highContrastReverseTextColor">@color/grey_900</item>
<item name="mediumContrastReverseTextColor">@color/grey_700</item> <item name="mediumContrastReverseTextColor">@color/grey_750</item>
<item name="lowContrastReverseTextColor">@color/grey_300</item> <item name="lowContrastReverseTextColor">@color/grey_300</item>
<item name="iconAdd">@drawable/ic_action_add_dark</item> <item name="iconAdd">@drawable/ic_action_add_dark</item>
@ -104,11 +108,17 @@
<item name="iconUnarchive">@drawable/ic_action_unarchive_dark</item> <item name="iconUnarchive">@drawable/ic_action_unarchive_dark</item>
<item name="iconChangeColor">@drawable/ic_action_color_dark</item> <item name="iconChangeColor">@drawable/ic_action_color_dark</item>
<item name="dialogIconChangeColor">@drawable/ic_action_color_dark</item> <item name="dialogIconChangeColor">@drawable/ic_action_color_dark</item>
<item name="iconFrequency">@drawable/ic_repeat_white</item>
<item name="iconReminder">@drawable/ic_alarm_white</item>
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat</item> <item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat</item>
<item name="palette">@array/darkPalette</item> <item name="palette">@array/darkPalette</item>
<item name="aboutScreenColor">@color/blue_300</item> <item name="aboutScreenColor">@color/blue_300</item>
<item name="widgetShadowAlpha">0.25</item>
<item name="widgetBackgroundAlpha">1</item>
</style> </style>
<style name="AppBaseThemeDark.PureBlack"> <style name="AppBaseThemeDark.PureBlack">
@ -127,6 +137,23 @@
<item name="highContrastReverseTextColor">@color/black</item> <item name="highContrastReverseTextColor">@color/black</item>
</style> </style>
<style name="TransparentWidgetTheme" parent="AppBaseThemeDark">
<item name="cardBackgroundColor">@color/black</item>
<item name="highContrastTextColor">@color/white</item>
<item name="mediumContrastTextColor">@color/white_ac</item>
<item name="lowContrastTextColor">@color/white_a0</item>
<item name="highContrastReverseTextColor">@color/white</item>
<item name="mediumContrastReverseTextColor">@color/grey_500</item>
<item name="lowContrastReverseTextColor">@color/grey_800</item>
<item name="palette">@array/transparentWidgetPalette</item>
<item name="widgetShadowAlpha">0</item>
<item name="widgetBackgroundAlpha">0.25</item>
</style>
<style name="time_label"> <style name="time_label">
<item name="android:textSize">@dimen/time_label_size</item> <item name="android:textSize">@dimen/time_label_size</item>
<item name="android:textColor">@color/numbers_text_color</item> <item name="android:textColor">@color/numbers_text_color</item>
@ -222,9 +249,9 @@
<style name="ToolbarShadow"> <style name="ToolbarShadow">
<item name="android:layout_width">match_parent</item> <item name="android:layout_width">match_parent</item>
<item name="android:layout_height">3dp</item> <item name="android:layout_height">2dp</item>
<item name="android:background">@drawable/toolbar_shadow</item> <item name="android:background">@drawable/toolbar_shadow</item>
<item name="android:alpha">0.25</item> <item name="android:alpha">0.2</item>
<item name="android:layout_below">@id/toolbar</item> <item name="android:layout_below">@id/toolbar</item>
</style> </style>
</resources> </resources>

@ -45,6 +45,10 @@
<item name="android:layout_width">0dp</item> <item name="android:layout_width">0dp</item>
<item name="android:layout_weight">1</item> <item name="android:layout_weight">1</item>
<item name="android:layout_height">wrap_content</item> <item name="android:layout_height">wrap_content</item>
<item name="android:breakStrategy">balanced</item>
<item name="android:maxLines">2</item>
<item name="android:ellipsize">end</item>
<item name="android:scrollHorizontally">true</item>
</style> </style>
<style name="ListHabits.CheckmarkPanel"> <style name="ListHabits.CheckmarkPanel">

@ -21,7 +21,7 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minHeight="40dp" android:minHeight="40dp"
android:minWidth="40dp" android:minWidth="40dp"
android:initialLayout="@layout/widget_checkmark" android:initialLayout="@layout/widget_wrapper"
android:previewImage="@drawable/widget_preview_checkmark" android:previewImage="@drawable/widget_preview_checkmark"
android:resizeMode="none" android:resizeMode="none"
android:updatePeriodMillis="3600000" android:updatePeriodMillis="3600000"

@ -40,6 +40,7 @@ grep -q "FAILURES\!\!\!" ${OUTPUT_DIR}/runner.txt && failed=1
info "Fetching failed generated files..." info "Fetching failed generated files..."
mkdir -p ${OUTPUT_DIR}/failed mkdir -p ${OUTPUT_DIR}/failed
adb pull /mnt/sdcard/test-screenshots/ ${OUTPUT_DIR}/failed >> $LOG 2>> $LOG
adb pull /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ \ adb pull /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ \
${OUTPUT_DIR}/failed >> $LOG 2>> $LOG ${OUTPUT_DIR}/failed >> $LOG 2>> $LOG
adb shell rm -r /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ >> $LOG 2>> $LOG adb shell rm -r /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ >> $LOG 2>> $LOG

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Loading…
Cancel
Save