diff --git a/app/src/androidTest/assets/views-v21/CheckmarkView/checked.png b/app/src/androidTest/assets/views-v21/CheckmarkView/checked.png deleted file mode 100644 index b54e5707d..000000000 Binary files a/app/src/androidTest/assets/views-v21/CheckmarkView/checked.png and /dev/null differ diff --git a/app/src/androidTest/assets/views-v21/CheckmarkView/implicitly_checked.png b/app/src/androidTest/assets/views-v21/CheckmarkView/implicitly_checked.png deleted file mode 100644 index 39d8e87f3..000000000 Binary files a/app/src/androidTest/assets/views-v21/CheckmarkView/implicitly_checked.png and /dev/null differ diff --git a/app/src/androidTest/assets/views-v21/CheckmarkView/large_size.png b/app/src/androidTest/assets/views-v21/CheckmarkView/large_size.png deleted file mode 100644 index 99e439e72..000000000 Binary files a/app/src/androidTest/assets/views-v21/CheckmarkView/large_size.png and /dev/null differ diff --git a/app/src/androidTest/assets/views-v21/CheckmarkView/unchecked.png b/app/src/androidTest/assets/views-v21/CheckmarkView/unchecked.png deleted file mode 100644 index 2dc0f531a..000000000 Binary files a/app/src/androidTest/assets/views-v21/CheckmarkView/unchecked.png and /dev/null differ diff --git a/app/src/androidTest/assets/views/CheckmarkView/checked.png b/app/src/androidTest/assets/views/CheckmarkView/checked.png index 7884c804f..37b14c980 100644 Binary files a/app/src/androidTest/assets/views/CheckmarkView/checked.png and b/app/src/androidTest/assets/views/CheckmarkView/checked.png differ diff --git a/app/src/androidTest/assets/views/CheckmarkView/implicitly_checked.png b/app/src/androidTest/assets/views/CheckmarkView/implicitly_checked.png index 3096be180..d17171132 100644 Binary files a/app/src/androidTest/assets/views/CheckmarkView/implicitly_checked.png and b/app/src/androidTest/assets/views/CheckmarkView/implicitly_checked.png differ diff --git a/app/src/androidTest/assets/views/CheckmarkView/large_size.png b/app/src/androidTest/assets/views/CheckmarkView/large_size.png index 79152fb18..437e8a0e2 100644 Binary files a/app/src/androidTest/assets/views/CheckmarkView/large_size.png and b/app/src/androidTest/assets/views/CheckmarkView/large_size.png differ diff --git a/app/src/androidTest/assets/views/CheckmarkView/unchecked.png b/app/src/androidTest/assets/views/CheckmarkView/unchecked.png index b0d90c5c0..581f5b603 100644 Binary files a/app/src/androidTest/assets/views/CheckmarkView/unchecked.png and b/app/src/androidTest/assets/views/CheckmarkView/unchecked.png differ diff --git a/app/src/androidTest/assets/views/HabitFrequencyView/renderTransparent.png b/app/src/androidTest/assets/views/HabitFrequencyView/renderTransparent.png index 6de22cf86..70ec73c84 100644 Binary files a/app/src/androidTest/assets/views/HabitFrequencyView/renderTransparent.png and b/app/src/androidTest/assets/views/HabitFrequencyView/renderTransparent.png differ diff --git a/app/src/androidTest/assets/views/HabitScoreView/renderTransparent.png b/app/src/androidTest/assets/views/HabitScoreView/renderTransparent.png index f50bd2685..0c9e18712 100644 Binary files a/app/src/androidTest/assets/views/HabitScoreView/renderTransparent.png and b/app/src/androidTest/assets/views/HabitScoreView/renderTransparent.png differ diff --git a/app/src/androidTest/assets/views/HabitStreakView/renderTransparent.png b/app/src/androidTest/assets/views/HabitStreakView/renderTransparent.png index 2255c156d..4bab05b52 100644 Binary files a/app/src/androidTest/assets/views/HabitStreakView/renderTransparent.png and b/app/src/androidTest/assets/views/HabitStreakView/renderTransparent.png differ diff --git a/app/src/androidTest/assets/views/RingView/render.png b/app/src/androidTest/assets/views/RingView/render.png index b951f0316..0bf125778 100644 Binary files a/app/src/androidTest/assets/views/RingView/render.png and b/app/src/androidTest/assets/views/RingView/render.png differ diff --git a/app/src/androidTest/assets/views/RingView/renderDifferentParams.png b/app/src/androidTest/assets/views/RingView/renderDifferentParams.png index 356bae29d..87874ba92 100644 Binary files a/app/src/androidTest/assets/views/RingView/renderDifferentParams.png and b/app/src/androidTest/assets/views/RingView/renderDifferentParams.png differ diff --git a/app/src/androidTest/assets/views/RingView/renderLongLabel.png b/app/src/androidTest/assets/views/RingView/renderLongLabel.png deleted file mode 100644 index e8e832499..000000000 Binary files a/app/src/androidTest/assets/views/RingView/renderLongLabel.png and /dev/null differ diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkWidgetViewTest.java similarity index 92% rename from app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkViewTest.java rename to app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkWidgetViewTest.java index 637edb5ec..cc367b52f 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkViewTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/views/CheckmarkWidgetViewTest.java @@ -25,7 +25,7 @@ import android.test.suitebuilder.annotation.SmallTest; import org.isoron.uhabits.helpers.DateHelper; import org.isoron.uhabits.models.Habit; 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.Test; import org.junit.runner.RunWith; @@ -34,9 +34,9 @@ import java.io.IOException; @RunWith(AndroidJUnit4.class) @SmallTest -public class CheckmarkViewTest extends ViewTest +public class CheckmarkWidgetViewTest extends ViewTest { - private CheckmarkView view; + private CheckmarkWidgetView view; private Habit habit; @Before @@ -45,7 +45,7 @@ public class CheckmarkViewTest extends ViewTest super.setup(); habit = HabitFixtures.createShortHabit(); - view = new CheckmarkView(targetContext); + view = new CheckmarkWidgetView(targetContext); view.setHabit(habit); refreshData(view); measureView(dpToPixels(100), dpToPixels(200), view); diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/views/HabitScoreViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/views/HabitScoreViewTest.java index 3dd19bb4d..a7f1228b9 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/views/HabitScoreViewTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/views/HabitScoreViewTest.java @@ -62,7 +62,7 @@ public class HabitScoreViewTest extends ViewTest @Test public void testRender_withTransparentBackground() throws Throwable { - view.setIsBackgroundTransparent(true); + view.setIsTransparencyEnabled(true); assertRenders(view, "HabitScoreView/renderTransparent.png"); } diff --git a/app/src/androidTest/java/org/isoron/uhabits/unit/views/RingViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/unit/views/RingViewTest.java index 6d85136e1..9f831ba49 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/unit/views/RingViewTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/unit/views/RingViewTest.java @@ -19,6 +19,7 @@ package org.isoron.uhabits.unit.views; +import android.graphics.Color; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.SmallTest; @@ -42,10 +43,11 @@ public class RingViewTest extends ViewTest super.setup(); view = new RingView(targetContext); - view.setLabel("Hello world"); view.setPercentage(0.6f); + view.setText("60%"); view.setColor(ColorHelper.CSV_PALETTE[0]); - view.setMaxDiameter(dpToPixels(100)); + view.setBackgroundColor(Color.WHITE); + view.setThickness(dpToPixels(3)); } @Test @@ -55,21 +57,10 @@ public class RingViewTest extends ViewTest 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 public void testRender_withDifferentParams() throws IOException { - view.setLabel("Habit Strength"); view.setPercentage(0.25f); - view.setMaxDiameter(dpToPixels(50)); view.setColor(ColorHelper.CSV_PALETTE[5]); measureView(dpToPixels(200), dpToPixels(200), view); diff --git a/app/src/main/java/org/isoron/uhabits/BaseActivity.java b/app/src/main/java/org/isoron/uhabits/BaseActivity.java index 38d822d57..1444f228a 100644 --- a/app/src/main/java/org/isoron/uhabits/BaseActivity.java +++ b/app/src/main/java/org/isoron/uhabits/BaseActivity.java @@ -133,7 +133,7 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U if(toolbar == null) return; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - toolbar.setElevation(UIHelper.dpToPixels(this, 3)); + toolbar.setElevation(UIHelper.dpToPixels(this, 2)); setSupportActionBar(toolbar); @@ -197,5 +197,8 @@ abstract public class BaseActivity extends AppCompatActivity implements Thread.U { View view = findViewById(R.id.toolbarShadow); if(view != null) view.setVisibility(View.GONE); + + view = findViewById(R.id.headerShadow); + if(view != null) view.setVisibility(View.GONE); } } diff --git a/app/src/main/java/org/isoron/uhabits/fragments/ListHabitsFragment.java b/app/src/main/java/org/isoron/uhabits/fragments/ListHabitsFragment.java index 178f84954..9ab74a709 100644 --- a/app/src/main/java/org/isoron/uhabits/fragments/ListHabitsFragment.java +++ b/app/src/main/java/org/isoron/uhabits/fragments/ListHabitsFragment.java @@ -61,6 +61,7 @@ import org.isoron.uhabits.helpers.DateHelper; import org.isoron.uhabits.helpers.HintManager; import org.isoron.uhabits.helpers.ListHabitsHelper; import org.isoron.uhabits.helpers.ReminderHelper; +import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.helpers.UIHelper.OnSavedListener; import org.isoron.uhabits.loaders.HabitListLoader; import org.isoron.uhabits.models.Habit; @@ -121,7 +122,7 @@ public class ListHabitsFragment extends Fragment loader.setCheckmarkCount(helper.getButtonCount()); llHint.setOnClickListener(this); - tvStarEmpty.setTypeface(helper.getFontawesome()); + tvStarEmpty.setTypeface(UIHelper.getFontAwesome(activity)); adapter = new HabitListAdapter(getActivity(), loader); adapter.setSelectedPositions(selectedPositions); diff --git a/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java b/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java index a89d23e29..a95afd8fa 100644 --- a/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java +++ b/app/src/main/java/org/isoron/uhabits/fragments/ShowHabitFragment.java @@ -42,6 +42,7 @@ import org.isoron.uhabits.commands.Command; import org.isoron.uhabits.dialogs.EditHabitDialogFragment; import org.isoron.uhabits.dialogs.HistoryEditorDialog; import org.isoron.uhabits.helpers.ColorHelper; +import org.isoron.uhabits.helpers.DateHelper; import org.isoron.uhabits.helpers.ReminderHelper; import org.isoron.uhabits.helpers.UIHelper; import org.isoron.uhabits.models.Habit; @@ -78,6 +79,13 @@ public class ShowHabitFragment extends Fragment private int previousScoreInterval; + private float todayScore; + private float lastMonthScore; + private float lastYearScore; + + private int activeColor; + private int inactiveColor; + @Override public void onStart() { @@ -90,7 +98,12 @@ public class ShowHabitFragment extends Fragment { View view = inflater.inflate(R.layout.show_habit, container, false); activity = (ShowHabitActivity) getActivity(); + habit = activity.getHabit(); + activeColor = ColorHelper.getColor(getContext(), habit.color); + inactiveColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); + + updateHeader(view); dataViews = new LinkedList<>(); @@ -105,7 +118,6 @@ public class ShowHabitFragment extends Fragment previousScoreInterval = defaultScoreInterval; setScoreBucketSize(defaultScoreInterval); - sStrengthInterval.setSelection(defaultScoreInterval); sStrengthInterval.setOnItemSelectedListener(this); @@ -147,6 +159,46 @@ public class ShowHabitFragment extends Fragment 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 public void onResume() { @@ -154,18 +206,34 @@ public class ShowHabitFragment extends Fragment refreshData(); } - private void updateScoreRing(View view) + private void updateScore(View view) { if(habit == null) return; if(view == null) return; - float todayValue = (float) habit.scores.getTodayValue(); - float percentage = todayValue / Score.MAX_VALUE; + float todayPercentage = todayScore / 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); int androidColor = ColorHelper.getColor(getActivity(), habit.color); 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) @@ -175,6 +243,7 @@ public class ShowHabitFragment extends Fragment updateColor(view, R.id.tvStrength); updateColor(view, R.id.tvStreaks); updateColor(view, R.id.tvWeekdayFreq); + updateColor(view, R.id.scoreLabel); } private void updateColor(View view, int viewId) @@ -236,25 +305,32 @@ public class ShowHabitFragment extends Fragment { new BaseTask() { - float percentage; - @Override protected void doInBackground() { + if(habit == 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; for(HabitDataView view : dataViews) { view.refreshData(); - onProgressUpdate(count++); + publishProgress(count++); } } @Override protected void onProgressUpdate(Integer... values) { - updateScoreRing(getView()); + updateScore(getView()); if(dataViews == null) return; dataViews.get(values[0]).postInvalidate(); } diff --git a/app/src/main/java/org/isoron/uhabits/helpers/ColorHelper.java b/app/src/main/java/org/isoron/uhabits/helpers/ColorHelper.java index 8f6dd8480..d64f4ac3d 100644 --- a/app/src/main/java/org/isoron/uhabits/helpers/ColorHelper.java +++ b/app/src/main/java/org/isoron/uhabits/helpers/ColorHelper.java @@ -29,19 +29,19 @@ public class ColorHelper { public static int CSV_PALETTE[] = { - Color.parseColor("#D32F2F"), // red - Color.parseColor("#E64A19"), // orange - Color.parseColor("#F9A825"), // yellow - Color.parseColor("#AFB42B"), // light green - Color.parseColor("#388E3C"), // dark green - Color.parseColor("#00897B"), // teal - Color.parseColor("#00ACC1"), // cyan - Color.parseColor("#039BE5"), // blue - Color.parseColor("#5E35B1"), // deep purple - Color.parseColor("#8E24AA"), // purple - Color.parseColor("#D81B60"), // pink - Color.parseColor("#303030"), // dark grey - Color.parseColor("#aaaaaa") // light grey + Color.parseColor("#D32F2F"), // 0 red + Color.parseColor("#E64A19"), // 1 orange + Color.parseColor("#F9A825"), // 2 yellow + Color.parseColor("#AFB42B"), // 3 light green + Color.parseColor("#388E3C"), // 4 dark green + Color.parseColor("#00897B"), // 5 teal + Color.parseColor("#00ACC1"), // 6 cyan + Color.parseColor("#039BE5"), // 7 blue + Color.parseColor("#5E35B1"), // 8 deep purple + Color.parseColor("#8E24AA"), // 9 purple + Color.parseColor("#D81B60"), // 10 pink + Color.parseColor("#303030"), // 11 dark grey + Color.parseColor("#aaaaaa") // 12 light grey }; public static int colorToPaletteIndex(Context context, int color) @@ -112,6 +112,12 @@ public class ColorHelper 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) { float hsv[] = new float[3]; diff --git a/app/src/main/java/org/isoron/uhabits/helpers/ListHabitsHelper.java b/app/src/main/java/org/isoron/uhabits/helpers/ListHabitsHelper.java index 385cce4b7..009333d1b 100644 --- a/app/src/main/java/org/isoron/uhabits/helpers/ListHabitsHelper.java +++ b/app/src/main/java/org/isoron/uhabits/helpers/ListHabitsHelper.java @@ -20,7 +20,6 @@ package org.isoron.uhabits.helpers; import android.content.Context; -import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -33,6 +32,7 @@ import org.isoron.uhabits.R; import org.isoron.uhabits.loaders.HabitListLoader; import org.isoron.uhabits.models.Habit; import org.isoron.uhabits.models.Score; +import org.isoron.uhabits.views.RingView; import java.util.GregorianCalendar; @@ -43,7 +43,6 @@ public class ListHabitsHelper private final Context context; private final HabitListLoader loader; - private Typeface fontawesome; public ListHabitsHelper(Context context, HabitListLoader loader) { @@ -52,12 +51,6 @@ public class ListHabitsHelper lowContrastColor = UIHelper.getStyledColor(context, R.attr.lowContrastTextColor); mediumContrastColor = UIHelper.getStyledColor(context, R.attr.mediumContrastTextColor); - fontawesome = Typeface.createFromAsset(context.getAssets(), "fontawesome-webfont.ttf"); - } - - public Typeface getFontawesome() - { - return fontawesome; } public int getButtonCount() @@ -105,46 +98,24 @@ public class ListHabitsHelper 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.WRAP_CONTENT, 1); 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); tvName.setText(habit.name); 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()); - - if (score < Score.HALF_STAR_CUTOFF) - { - tvStar.setText(context.getString(R.string.fa_star_o)); - 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); - } - } + int score = loader.scores.get(habit.getId()); + float percentage = (float) score / Score.MAX_VALUE; + + ring.setColor(activeColor); + ring.setPercentage(percentage); + ring.setPrecision(1.0f / 16); } 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) { - TextView tvStar = ((TextView) view.findViewById(R.id.tvStar)); + RingView scoreRing = ((RingView) view.findViewById(R.id.scoreRing)); TextView tvName = (TextView) view.findViewById(R.id.label); LinearLayout llInner = (LinearLayout) view.findViewById(R.id.llInner); LinearLayout llButtons = (LinearLayout) view.findViewById(R.id.llButtons); @@ -192,7 +163,7 @@ public class ListHabitsHelper llInner.setTag(R.string.habit_key, habit.getId()); llInner.setOnTouchListener(new HotspotTouchListener()); - updateNameAndIcon(habit, tvStar, tvName); + updateNameAndIcon(habit, scoreRing, tvName); updateCheckmarkButtons(habit, llButtons); updateHabitCardBackground(llInner, selected); } @@ -227,7 +198,7 @@ public class ListHabitsHelper { View check = inflater.inflate(R.layout.list_habits_item_check, null); TextView btCheck = (TextView) check.findViewById(R.id.tvCheck); - btCheck.setTypeface(fontawesome); + btCheck.setTypeface(UIHelper.getFontAwesome(context)); btCheck.setOnLongClickListener(onLongClickListener); btCheck.setOnClickListener(onClickListener); btCheck.setHapticFeedbackEnabled(false); diff --git a/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java b/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java index a081e6aef..04b03f4e7 100644 --- a/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java +++ b/app/src/main/java/org/isoron/uhabits/helpers/UIHelper.java @@ -50,13 +50,21 @@ public abstract class UIHelper public static final int THEME_LIGHT = 0; public static final int THEME_DARK = 1; - private static Typeface fontawesome; + private static Typeface fontAwesome; public interface OnSavedListener { 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) { InputMethodManager imm = (InputMethodManager) view.getContext() @@ -94,6 +102,14 @@ public abstract class UIHelper 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, int defaultValue) { @@ -102,6 +118,14 @@ public abstract class UIHelper 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, float defaultValue) { @@ -206,6 +230,16 @@ public abstract class UIHelper 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) { int[] attr = new int[] { attrId }; diff --git a/app/src/main/java/org/isoron/uhabits/views/CheckmarkView.java b/app/src/main/java/org/isoron/uhabits/views/CheckmarkView.java deleted file mode 100644 index 535c14cb6..000000000 --- a/app/src/main/java/org/isoron/uhabits/views/CheckmarkView.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.views; - -import android.content.Context; -import android.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); - } -} diff --git a/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java b/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java new file mode 100644 index 000000000..01cf98a19 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/CheckmarkWidgetView.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.views; + +import android.content.Context; +import android.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; + } +} diff --git a/app/src/main/java/org/isoron/uhabits/views/GraphWidgetView.java b/app/src/main/java/org/isoron/uhabits/views/GraphWidgetView.java new file mode 100644 index 000000000..bb142ca7d --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/GraphWidgetView.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.views; + +import android.content.Context; +import android.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; + } +} diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java b/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java index b1603552d..7890757dd 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitFrequencyView.java @@ -21,7 +21,6 @@ package org.isoron.uhabits.views; import android.content.Context; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; @@ -104,22 +103,10 @@ public class HabitFrequencyView extends ScrollableDataView implements HabitDataV 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); - gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); - } + textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); + gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); colors = new int[4]; - colors[0] = gridColor; colors[3] = primaryColor; colors[1] = ColorHelper.mixColors(colors[0], colors[3], 0.66f); diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java index 55ec55806..1579f29d3 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitScoreView.java @@ -20,6 +20,7 @@ package org.isoron.uhabits.views; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; @@ -72,11 +73,14 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView private int[] scores; private int primaryColor; - private boolean isBackgroundTransparent; private int bucketSize = 7; private int footerHeight; private int backgroundColor; + private Bitmap drawingCache; + private Canvas cacheCanvas; + private boolean isTransparencyEnabled; + public HabitScoreView(Context context) { super(context); @@ -114,20 +118,9 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView if(habit != null) 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); - gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); - backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); - } + textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); + gridColor = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); + backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); } protected void createPaints() @@ -180,6 +173,16 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView pGraph.setTextSize(baseSize * 0.5f); pGraph.setStrokeWidth(baseSize * 0.1f); 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() @@ -218,12 +221,26 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView protected void onDraw(Canvas 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; rect.set(0, 0, nColumns * columnWidth, columnHeight); rect.offset(0, paddingTop); - drawGrid(canvas, rect); + drawGrid(activeCanvas, rect); pText.setColor(textColor); pGraph.setColor(primaryColor); @@ -253,20 +270,23 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView if (!prevRect.isEmpty()) { - drawLine(canvas, prevRect, rect); - drawMarker(canvas, prevRect); + drawLine(activeCanvas, prevRect, rect); + drawMarker(activeCanvas, prevRect); } - if (k == nColumns - 1) drawMarker(canvas, rect); + if (k == nColumns - 1) drawMarker(activeCanvas, rect); prevRect.set(rect); rect.set(0, 0, columnWidth, columnHeight); rect.offset(k * columnWidth, paddingTop); - drawFooter(canvas, rect, currentDate); + drawFooter(activeCanvas, rect, currentDate); currentDate += bucketSize * DateHelper.millisecondsInOneDay; } + + if(activeCanvas != canvas) + canvas.drawBitmap(drawingCache, 0, 0, null); } private int skipYear = 0; @@ -364,19 +384,20 @@ public class HabitScoreView extends ScrollableDataView implements HabitDataView setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor); canvas.drawOval(rect, pGraph); - if(isBackgroundTransparent) + if(isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC); } - public void setIsBackgroundTransparent(boolean isBackgroundTransparent) + public void setIsTransparencyEnabled(boolean enabled) { - this.isBackgroundTransparent = isBackgroundTransparent; + this.isTransparencyEnabled = enabled; createColors(); + requestLayout(); } private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color) { - if(isBackgroundTransparent) + if(isTransparencyEnabled) p.setXfermode(mode); else p.setColor(color); diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java index 5d3cc0043..74fc6c518 100644 --- a/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java +++ b/app/src/main/java/org/isoron/uhabits/views/HabitStreakView.java @@ -127,36 +127,17 @@ public class HabitStreakView extends View implements HabitDataView if(habit != null) 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 green = Color.green(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[3] = primaryColor; - colors[2] = Color.argb(192, red, green, blue); - colors[1] = Color.argb(96, red, green, blue); - colors[0] = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); - textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); - reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor); - } + colors = new int[4]; + colors[3] = primaryColor; + colors[2] = Color.argb(192, red, green, blue); + colors[1] = Color.argb(96, red, green, blue); + colors[0] = UIHelper.getStyledColor(getContext(), R.attr.lowContrastTextColor); + textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); + reverseTextColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastReverseTextColor); } protected void createPaints() diff --git a/app/src/main/java/org/isoron/uhabits/views/HabitWidgetView.java b/app/src/main/java/org/isoron/uhabits/views/HabitWidgetView.java new file mode 100644 index 000000000..fc561dfc1 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/views/HabitWidgetView.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.views; + +import android.content.Context; +import android.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; + } +} diff --git a/app/src/main/java/org/isoron/uhabits/views/RingView.java b/app/src/main/java/org/isoron/uhabits/views/RingView.java index db1cc1a58..de7ee345a 100644 --- a/app/src/main/java/org/isoron/uhabits/views/RingView.java +++ b/app/src/main/java/org/isoron/uhabits/views/RingView.java @@ -19,42 +19,59 @@ package org.isoron.uhabits.views; -import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; -import android.text.Layout; -import android.text.StaticLayout; import android.text.TextPaint; import android.util.AttributeSet; import android.view.View; import org.isoron.uhabits.R; +import org.isoron.uhabits.helpers.ColorHelper; import org.isoron.uhabits.helpers.UIHelper; public class RingView extends View { + public static final PorterDuffXfermode XFERMODE_CLEAR = + new PorterDuffXfermode(PorterDuff.Mode.CLEAR); + private int color; + private float precision; private float percentage; - private float labelMarginTop; - private TextPaint pRing; - private String label; + private int diameter; + private float thickness; + private RectF rect; - private StaticLayout labelLayout; + private TextPaint pRing; - private int width; - private int height; - private float diameter; + private Integer backgroundColor; + private Integer inactiveColor; - private float maxDiameter; + private float em; + private String text; private float textSize; - private int textColor; - private int backgroundColor; + private boolean enableFontAwesome; + + private Bitmap drawingCache; + private Canvas cacheCanvas; + private boolean isTransparencyEnabled; public RingView(Context 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(); } @@ -62,9 +79,24 @@ public class RingView extends View { super(context, attrs); - this.label = UIHelper.getAttribute(context, attrs, "label", "Label"); - this.maxDiameter = UIHelper.getFloatAttribute(context, attrs, "maxDiameter", 100); - this.maxDiameter = UIHelper.dpToPixels(context, maxDiameter); + percentage = UIHelper.getFloatAttribute(context, attrs, "percentage", 0); + precision = UIHelper.getFloatAttribute(context, attrs, "precision", 0.01f); + + 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(); } @@ -74,19 +106,34 @@ public class RingView extends View 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(); } @@ -97,61 +144,94 @@ public class RingView extends View pRing.setColor(color); pRing.setTextAlign(Paint.Align.CENTER); - backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); - textColor = UIHelper.getStyledColor(getContext(), R.attr.mediumContrastTextColor); - textSize = getResources().getDimension(R.dimen.smallTextSize); + if(backgroundColor == null) + backgroundColor = UIHelper.getStyledColor(getContext(), R.attr.cardBackgroundColor); + + if(inactiveColor == null) + inactiveColor = UIHelper.getStyledColor(getContext(), R.attr.highContrastTextColor); + + inactiveColor = ColorHelper.setAlpha(inactiveColor, 0.1f); rect = new RectF(); } @Override - @SuppressLint("DrawAllocation") protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - width = MeasureSpec.getSize(widthMeasureSpec); - height = MeasureSpec.getSize(heightMeasureSpec); - - diameter = Math.min(maxDiameter, width); + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + diameter = Math.min(height, width); pRing.setTextSize(textSize); - labelMarginTop = textSize * 0.80f; - labelLayout = new StaticLayout(label, pRing, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0f, - false); + em = pRing.measureText("M"); - width = Math.max(width, labelLayout.getWidth()); - height = (int) (diameter + labelLayout.getHeight() + labelMarginTop); + setMeasuredDimension(diameter, diameter); + } - 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 protected void onDraw(Canvas 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); 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); - pRing.setColor(grey); - canvas.drawArc(rect, 360 * percentage - 90 + 2, 360 * (1 - percentage) - 4, true, pRing); + float angle = 360 * Math.round(percentage / precision) * precision; - pRing.setColor(backgroundColor); - rect.inset(thickness, thickness); - canvas.drawArc(rect, -90, 360, true, pRing); + activeCanvas.drawArc(rect, -90, angle, true, pRing); - pRing.setColor(textColor); - pRing.setTextSize(textSize); - float lineHeight = pRing.getFontSpacing(); - canvas.drawText(String.format("%.0f%%", percentage * 100), rect.centerX(), - rect.centerY() + lineHeight / 3, pRing); - pRing.setTextSize(textSize); - canvas.translate(width / 2, diameter + labelMarginTop); - labelLayout.draw(canvas); + 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); + + rect.inset(thickness, thickness); + activeCanvas.drawArc(rect, 0, 360, true, pRing); + pRing.setXfermode(null); + + pRing.setColor(color); + pRing.setTextSize(textSize); + if(enableFontAwesome) pRing.setTypeface(UIHelper.getFontAwesome(getContext())); + 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; } } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java index f2ea24c1e..d430db009 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/BaseWidgetProvider.java @@ -33,6 +33,7 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.RemoteViews; +import android.widget.TextView; import org.isoron.uhabits.R; import org.isoron.uhabits.helpers.UIHelper; @@ -123,23 +124,27 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider 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 { LayoutInflater inflater = LayoutInflater.from(context); 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); - 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.setDrawingCacheEnabled(true); view.buildDrawingCache(); 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)); FileOutputStream out = new FileOutputStream(filename); @@ -254,8 +259,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { try { - buildRemoteViews(portraitWidgetView, portraitRemoteViews); - buildRemoteViews(landscapeWidgetView, landscapeRemoteViews); + buildRemoteViews(portraitWidgetView, portraitRemoteViews, portraitWidth, portraitHeight); + buildRemoteViews(landscapeWidgetView, landscapeRemoteViews, landscapeWidth, landscapeHeight); updateAppWidget(); } catch (Exception e) @@ -267,7 +272,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider super.onPostExecute(aVoid); } - private void buildRemoteViews(View widgetView, RemoteViews remoteViews) + private void buildRemoteViews(View widgetView, RemoteViews remoteViews, int width, int height) { widgetView.invalidate(); widgetView.setDrawingCacheEnabled(true); @@ -276,11 +281,29 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider remoteViews.setTextViewText(R.id.label, habit.name); 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); - if (onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.imageView, + if (onClickIntent != null) remoteViews.setOnClickPendingIntent(R.id.button, 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 }; + } } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java index bd04e8eb0..42ac2408b 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.java @@ -25,7 +25,7 @@ import android.view.View; import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; -import org.isoron.uhabits.views.CheckmarkView; +import org.isoron.uhabits.views.CheckmarkWidgetView; import org.isoron.uhabits.views.HabitDataView; public class CheckmarkWidgetProvider extends BaseWidgetProvider @@ -33,7 +33,7 @@ public class CheckmarkWidgetProvider extends BaseWidgetProvider @Override protected View buildCustomView(Context context, Habit habit) { - CheckmarkView view = new CheckmarkView(context); + CheckmarkWidgetView view = new CheckmarkWidgetView(context); view.setHabit(habit); return view; } @@ -65,7 +65,7 @@ public class CheckmarkWidgetProvider extends BaseWidgetProvider @Override protected int getLayoutId() { - return R.layout.widget_checkmark; + return R.layout.widget_wrapper; } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.java index 2cac07c06..2fdbedb71 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.java @@ -26,6 +26,7 @@ import android.view.View; import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.views.GraphWidgetView; import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitFrequencyView; @@ -34,8 +35,8 @@ public class FrequencyWidgetProvider extends BaseWidgetProvider @Override protected View buildCustomView(Context context, Habit habit) { - HabitFrequencyView view = new HabitFrequencyView(context, null); - view.setIsBackgroundTransparent(true); + HabitFrequencyView dataView = new HabitFrequencyView(context); + GraphWidgetView view = new GraphWidgetView(context, dataView); view.setHabit(habit); return view; } @@ -67,6 +68,6 @@ public class FrequencyWidgetProvider extends BaseWidgetProvider @Override protected int getLayoutId() { - return R.layout.widget_graph; + return R.layout.widget_wrapper; } } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.java index e02cb608c..7e728b112 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.java @@ -25,6 +25,7 @@ import android.view.View; import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.views.GraphWidgetView; import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitHistoryView; @@ -33,9 +34,9 @@ public class HistoryWidgetProvider extends BaseWidgetProvider @Override 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.setIsBackgroundTransparent(true); return view; } @@ -66,6 +67,6 @@ public class HistoryWidgetProvider extends BaseWidgetProvider @Override protected int getLayoutId() { - return R.layout.widget_graph; + return R.layout.widget_wrapper; } } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.java index 456491efe..0e43a60c1 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.java @@ -25,16 +25,18 @@ import android.view.View; import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.views.GraphWidgetView; import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitScoreView; -public class ScoreWidgetProvider extends BaseWidgetProvider +public class ScoreWidgetProvider extends BaseWidgetProvider { @Override protected View buildCustomView(Context context, Habit habit) { - HabitScoreView view = new HabitScoreView(context, null); - view.setIsBackgroundTransparent(true); + HabitScoreView dataView = new HabitScoreView(context); + dataView.setIsTransparencyEnabled(true); + GraphWidgetView view = new GraphWidgetView(context, dataView); view.setHabit(habit); return view; } @@ -66,6 +68,6 @@ public class ScoreWidgetProvider extends BaseWidgetProvider @Override protected int getLayoutId() { - return R.layout.widget_graph; + return R.layout.widget_wrapper; } } diff --git a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java b/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java index f5d81d4f6..f0455d00a 100644 --- a/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java +++ b/app/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.java @@ -25,6 +25,7 @@ import android.view.View; import org.isoron.uhabits.HabitBroadcastReceiver; import org.isoron.uhabits.R; import org.isoron.uhabits.models.Habit; +import org.isoron.uhabits.views.GraphWidgetView; import org.isoron.uhabits.views.HabitDataView; import org.isoron.uhabits.views.HabitStreakView; @@ -33,8 +34,8 @@ public class StreakWidgetProvider extends BaseWidgetProvider @Override protected View buildCustomView(Context context, Habit habit) { - HabitStreakView view = new HabitStreakView(context, null); - view.setIsBackgroundTransparent(true); + HabitStreakView dataView = new HabitStreakView(context); + GraphWidgetView view = new GraphWidgetView(context, dataView); view.setHabit(habit); return view; } @@ -66,6 +67,6 @@ public class StreakWidgetProvider extends BaseWidgetProvider @Override protected int getLayoutId() { - return R.layout.widget_graph; + return R.layout.widget_wrapper; } } diff --git a/app/src/main/res/drawable-hdpi/ic_alarm_black.png b/app/src/main/res/drawable-hdpi/ic_alarm_black.png new file mode 100644 index 000000000..907491104 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_alarm_black.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_alarm_white.png b/app/src/main/res/drawable-hdpi/ic_alarm_white.png new file mode 100644 index 000000000..6dc94d2b5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_alarm_white.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_repeat_black.png b/app/src/main/res/drawable-hdpi/ic_repeat_black.png new file mode 100644 index 000000000..d8b42bbe4 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_repeat_black.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_repeat_white.png b/app/src/main/res/drawable-hdpi/ic_repeat_white.png new file mode 100644 index 000000000..81c5be793 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_repeat_white.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_alarm_black.png b/app/src/main/res/drawable-mdpi/ic_alarm_black.png new file mode 100644 index 000000000..ed2f90aee Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_alarm_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_alarm_white.png b/app/src/main/res/drawable-mdpi/ic_alarm_white.png new file mode 100644 index 000000000..ca4f94707 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_alarm_white.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_repeat_black.png b/app/src/main/res/drawable-mdpi/ic_repeat_black.png new file mode 100644 index 000000000..c00a24ebf Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_repeat_black.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_repeat_white.png b/app/src/main/res/drawable-mdpi/ic_repeat_white.png new file mode 100644 index 000000000..b1c2e04ab Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_repeat_white.png differ diff --git a/app/src/main/res/drawable-nodpi/widget_preview_checkmark.png b/app/src/main/res/drawable-nodpi/widget_preview_checkmark.png new file mode 100644 index 000000000..0cbac62e6 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview_checkmark.png differ diff --git a/app/src/main/res/drawable-nodpi/widget_preview_frequency.png b/app/src/main/res/drawable-nodpi/widget_preview_frequency.png new file mode 100644 index 000000000..561afb45c Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview_frequency.png differ diff --git a/app/src/main/res/drawable-nodpi/widget_preview_history.png b/app/src/main/res/drawable-nodpi/widget_preview_history.png new file mode 100644 index 000000000..95297b6ee Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview_history.png differ diff --git a/app/src/main/res/drawable-nodpi/widget_preview_score.png b/app/src/main/res/drawable-nodpi/widget_preview_score.png new file mode 100644 index 000000000..8d9b3baa5 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview_score.png differ diff --git a/app/src/main/res/drawable-nodpi/widget_preview_streaks.png b/app/src/main/res/drawable-nodpi/widget_preview_streaks.png new file mode 100644 index 000000000..b1fe031e6 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/widget_preview_streaks.png differ diff --git a/app/src/main/res/drawable-v21/widget_button_background.xml b/app/src/main/res/drawable-v21/widget_button_background.xml new file mode 100644 index 000000000..fdeb02bcd --- /dev/null +++ b/app/src/main/res/drawable-v21/widget_button_background.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/ic_alarm_black.png b/app/src/main/res/drawable-xhdpi/ic_alarm_black.png new file mode 100644 index 000000000..e37eab0e4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_alarm_black.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_alarm_white.png b/app/src/main/res/drawable-xhdpi/ic_alarm_white.png new file mode 100644 index 000000000..280e09df3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_alarm_white.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_repeat_black.png b/app/src/main/res/drawable-xhdpi/ic_repeat_black.png new file mode 100644 index 000000000..75ecb0462 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_repeat_black.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_repeat_white.png b/app/src/main/res/drawable-xhdpi/ic_repeat_white.png new file mode 100644 index 000000000..ad8b8c0df Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_repeat_white.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_alarm_black.png b/app/src/main/res/drawable-xxhdpi/ic_alarm_black.png new file mode 100644 index 000000000..eb1d08d7a Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_alarm_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_alarm_white.png b/app/src/main/res/drawable-xxhdpi/ic_alarm_white.png new file mode 100644 index 000000000..75e5a46ee Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_alarm_white.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_repeat_black.png b/app/src/main/res/drawable-xxhdpi/ic_repeat_black.png new file mode 100644 index 000000000..965a319ff Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_repeat_black.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_repeat_white.png b/app/src/main/res/drawable-xxhdpi/ic_repeat_white.png new file mode 100644 index 000000000..5de7a2951 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_repeat_white.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_alarm_black.png b/app/src/main/res/drawable-xxxhdpi/ic_alarm_black.png new file mode 100644 index 000000000..04b6c71d7 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_alarm_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_alarm_white.png b/app/src/main/res/drawable-xxxhdpi/ic_alarm_white.png new file mode 100644 index 000000000..aa8102fd2 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_alarm_white.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_repeat_black.png b/app/src/main/res/drawable-xxxhdpi/ic_repeat_black.png new file mode 100644 index 000000000..fd4d0c028 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_repeat_black.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_repeat_white.png b/app/src/main/res/drawable-xxxhdpi/ic_repeat_white.png new file mode 100644 index 000000000..c7f3072ee Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_repeat_white.png differ diff --git a/app/src/main/res/drawable/widget_button_background.xml b/app/src/main/res/drawable/widget_button_background.xml new file mode 100644 index 000000000..a50eaa160 --- /dev/null +++ b/app/src/main/res/drawable/widget_button_background.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/widget_preview_checkmark.png b/app/src/main/res/drawable/widget_preview_checkmark.png deleted file mode 100644 index ceb7d6541..000000000 Binary files a/app/src/main/res/drawable/widget_preview_checkmark.png and /dev/null differ diff --git a/app/src/main/res/drawable/widget_preview_frequency.png b/app/src/main/res/drawable/widget_preview_frequency.png deleted file mode 100644 index a3fc86505..000000000 Binary files a/app/src/main/res/drawable/widget_preview_frequency.png and /dev/null differ diff --git a/app/src/main/res/drawable/widget_preview_history.png b/app/src/main/res/drawable/widget_preview_history.png deleted file mode 100644 index bcc829bbc..000000000 Binary files a/app/src/main/res/drawable/widget_preview_history.png and /dev/null differ diff --git a/app/src/main/res/drawable/widget_preview_score.png b/app/src/main/res/drawable/widget_preview_score.png deleted file mode 100644 index 101569dbc..000000000 Binary files a/app/src/main/res/drawable/widget_preview_score.png and /dev/null differ diff --git a/app/src/main/res/drawable/widget_preview_streaks.png b/app/src/main/res/drawable/widget_preview_streaks.png deleted file mode 100644 index b7771c2b8..000000000 Binary files a/app/src/main/res/drawable/widget_preview_streaks.png and /dev/null differ diff --git a/app/src/main/res/layout/list_habits_item.xml b/app/src/main/res/layout/list_habits_item.xml index bcd2d4785..63a766d35 100644 --- a/app/src/main/res/layout/list_habits_item.xml +++ b/app/src/main/res/layout/list_habits_item.xml @@ -19,16 +19,22 @@ --> + xmlns:habit="http://isoron.org/android" + android:id="@+id/llOuter" + style="@style/ListHabits.Item"> - + . --> - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -65,20 +211,20 @@ android:id="@+id/sStrengthInterval" android:layout_width="wrap_content" android:layout_height="22dp" - android:entries="@array/strengthIntervalNames" - android:layout_alignParentTop="true" - android:layout_alignParentRight="true" android:layout_alignParentEnd="true" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:entries="@array/strengthIntervalNames" android:theme="@style/SmallSpinner" /> + android:layout_alignParentStart="true" + android:layout_alignParentTop="true" + android:text="@string/habit_strength"/> - \ No newline at end of file + diff --git a/app/src/main/res/layout/show_habit_activity.xml b/app/src/main/res/layout/show_habit_activity.xml index a0571eb94..2df9d424b 100644 --- a/app/src/main/res/layout/show_habit_activity.xml +++ b/app/src/main/res/layout/show_habit_activity.xml @@ -17,30 +17,30 @@ ~ with this program. If not, see . --> - + + style="@style/Toolbar" + app:popupTheme="?toolbarPopupTheme"/> + tools:layout="@layout/show_habit"/> + android:orientation="vertical"> - + android:layout_height="0dp" + 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"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_graph.xml b/app/src/main/res/layout/widget_graph.xml index b107384c8..60c4b3bae 100644 --- a/app/src/main/res/layout/widget_graph.xml +++ b/app/src/main/res/layout/widget_graph.xml @@ -18,29 +18,33 @@ ~ with this program. If not, see . --> - + android:orientation="vertical"> - + android:layout_height="match_parent" + android:orientation="vertical" + android:paddingTop="4dp" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:paddingBottom="4dp" + tools:ignore="UselessParent"> - + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/small_widget_preview.xml b/app/src/main/res/layout/widget_wrapper.xml similarity index 71% rename from app/src/main/res/layout/small_widget_preview.xml rename to app/src/main/res/layout/widget_wrapper.xml index d77cbc468..1d739750d 100644 --- a/app/src/main/res/layout/small_widget_preview.xml +++ b/app/src/main/res/layout/widget_wrapper.xml @@ -18,19 +18,32 @@ ~ with this program. If not, see . --> - + android:padding="0dp"> - - \ No newline at end of file + + +