From 7bf9f88ee37fe5516a6a6e2bb23bd7761426cc92 Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Thu, 23 Mar 2017 18:26:58 -0400 Subject: [PATCH] Implement NumberButtonView and related classes --- .../list/views/CheckmarkButtonViewTest.java | 93 ------- .../list/views/CheckmarkPanelViewTest.java | 2 +- .../habits/list/ListHabitsComponent.java | 10 +- .../controllers/NumberButtonController.java | 102 +++++++ .../list/views/CheckmarkButtonView.java | 24 +- .../habits/list/views/CheckmarkPanelView.java | 121 +++++---- .../habits/list/views/HabitCardView.java | 4 +- .../habits/list/views/NumberButtonView.java | 131 +++++++++ .../habits/list/views/NumberPanelView.java | 255 ++++++++++++++++++ .../uhabits/utils/AttributeSetUtils.java | 10 + .../res/layout/list_habits_button_preview.xml | 67 +++++ .../res/layout/list_habits_panel_preview.xml | 80 ++++++ 12 files changed, 748 insertions(+), 151 deletions(-) create mode 100644 app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/NumberButtonController.java create mode 100644 app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java create mode 100644 app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java create mode 100644 app/src/main/res/layout/list_habits_button_preview.xml create mode 100644 app/src/main/res/layout/list_habits_panel_preview.xml diff --git a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java index b8bbc0bac..e30669414 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonViewTest.java @@ -91,97 +91,4 @@ public class CheckmarkButtonViewTest extends BaseViewTest { assertRenders(view, PATH + "render_unchecked.png"); } - -// @Test -// public void testLongClick() throws Exception -// { -// setOnToggleListener(); -// view.performLongClick(); -// waitForLatch(); -// assertRendersCheckedExplicitly(); -// } -// -// @Test -// public void testClick_withShortToggle_fromUnchecked() throws Exception -// { -// Preferences.getInstance().setShortToggleEnabled(true); -// view.setValue(Checkmark.UNCHECKED); -// setOnToggleListenerAndPerformClick(); -// assertRendersCheckedExplicitly(); -// } -// -// @Test -// public void testClick_withShortToggle_fromChecked() throws Exception -// { -// Preferences.getInstance().setShortToggleEnabled(true); -// view.setValue(Checkmark.CHECKED_EXPLICITLY); -// setOnToggleListenerAndPerformClick(); -// assertRendersUnchecked(); -// } -// -// @Test -// public void testClick_withShortToggle_withoutListener() throws Exception -// { -// Preferences.getInstance().setShortToggleEnabled(true); -// view.setValue(Checkmark.CHECKED_EXPLICITLY); -// view.setController(null); -// view.performClick(); -// assertRendersUnchecked(); -// } -// -// protected void setOnToggleListenerAndPerformClick() throws InterruptedException -// { -// setOnToggleListener(); -// view.performClick(); -// waitForLatch(); -// } -// -// @Test -// public void testClick_withoutShortToggle() throws Exception -// { -// Preferences.getInstance().setShortToggleEnabled(false); -// setOnInvalidToggleListener(); -// view.performClick(); -// waitForLatch(); -// assertRendersUnchecked(); -// } - -// protected void setOnInvalidToggleListener() -// { -// view.setController(new CheckmarkButtonView.Controller() -// { -// @Override -// public void onToggleCheckmark(CheckmarkButtonView view, long timestamp) -// { -// fail(); -// } -// -// @Override -// public void onInvalidToggle(CheckmarkButtonView v) -// { -// assertThat(v, equalTo(view)); -// latch.countDown(); -// } -// }); -// } - -// protected void setOnToggleListener() -// { -// view.setController(new CheckmarkButtonView.Controller() -// { -// @Override -// public void onToggleCheckmark(CheckmarkButtonView v, long t) -// { -// assertThat(v, equalTo(view)); -// assertThat(t, equalTo(DateUtils.getStartOfToday())); -// latch.countDown(); -// } -// -// @Override -// public void onInvalidToggle(CheckmarkButtonView view) -// { -// fail(); -// } -// }); -// } } \ No newline at end of file diff --git a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java index 30e225a7a..8be616ef9 100644 --- a/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java +++ b/app/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelViewTest.java @@ -59,7 +59,7 @@ public class CheckmarkPanelViewTest extends BaseViewTest view = new CheckmarkPanelView(targetContext); view.setHabit(habit); - view.setCheckmarkValues(checkmarks); + view.setValues(checkmarks); view.setButtonCount(4); view.setColor(ColorUtils.getAndroidTestColor(7)); diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java index 554c22a3b..4f8161d40 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsComponent.java @@ -32,19 +32,21 @@ import dagger.*; dependencies = { AppComponent.class }) public interface ListHabitsComponent { - CheckmarkButtonControllerFactory getCheckmarkButtonControllerFactory(); - HabitCardListAdapter getAdapter(); + CheckmarkButtonControllerFactory getCheckmarkButtonControllerFactory(); + ListHabitsController getController(); ListHabitsMenu getMenu(); + MidnightTimer getMidnightTimer(); + + NumberButtonControllerFactory getNumberButtonControllerFactory(); + ListHabitsRootView getRootView(); ListHabitsScreen getScreen(); ListHabitsSelectionMenu getSelectionMenu(); - - MidnightTimer getMidnightTimer(); } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/NumberButtonController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/NumberButtonController.java new file mode 100644 index 000000000..0cd31fe20 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/controllers/NumberButtonController.java @@ -0,0 +1,102 @@ +/* + * 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.activities.habits.list.controllers; + +import android.support.annotation.*; + +import com.google.auto.factory.*; + +import org.isoron.uhabits.activities.habits.list.views.*; +import org.isoron.uhabits.models.*; +import org.isoron.uhabits.preferences.*; + +@AutoFactory +public class NumberButtonController +{ + @Nullable + private NumberButtonView view; + + @Nullable + private Listener listener; + + @NonNull + private final Preferences prefs; + + @NonNull + private Habit habit; + + private long timestamp; + + public NumberButtonController(@Provided @NonNull Preferences prefs, + @NonNull Habit habit, + long timestamp) + { + this.habit = habit; + this.timestamp = timestamp; + this.prefs = prefs; + } + + public void onClick() + { + if (prefs.isShortToggleEnabled()) performEdit(); + else performInvalidToggle(); + } + + public boolean onLongClick() + { + performEdit(); + return true; + } + + public void performInvalidToggle() + { + if (listener != null) listener.onInvalidEdit(); + } + + public void performEdit() + { + if (listener != null) listener.onEdit(habit, timestamp); + } + + public void setListener(@Nullable Listener listener) + { + this.listener = listener; + } + + public void setView(@Nullable NumberButtonView view) + { + this.view = view; + } + + public interface Listener + { + /** + * Called when the user's attempt to edit the value is rejected. + */ + void onInvalidEdit(); + + /** + * Called when a the user's attempt to edit the value has been accepted. + * @param habit the habit being edited + * @param timestamp the timestamp being edited + */ + void onEdit(@NonNull Habit habit, long timestamp); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java index 97d0c9fca..acc0e8b7e 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.java @@ -20,6 +20,8 @@ package org.isoron.uhabits.activities.habits.list.views; import android.content.*; +import android.support.annotation.*; +import android.util.*; import android.view.*; import android.widget.*; @@ -28,6 +30,9 @@ import org.isoron.uhabits.activities.habits.list.controllers.*; import org.isoron.uhabits.models.*; import org.isoron.uhabits.utils.*; +import static org.isoron.uhabits.utils.AttributeSetUtils.*; +import static org.isoron.uhabits.utils.ColorUtils.*; + public class CheckmarkButtonView extends TextView { private int color; @@ -36,16 +41,31 @@ public class CheckmarkButtonView extends TextView private StyledResources res; - public CheckmarkButtonView(Context context) + public CheckmarkButtonView(@Nullable Context context) { super(context); init(); } + public CheckmarkButtonView(@Nullable Context context, + @Nullable AttributeSet attrs) + { + super(context, attrs); + init(); + + if (context != null && attrs != null) + { + int color = getIntAttribute(context, attrs, "color", 0); + int value = getIntAttribute(context, attrs, "value", 0); + setColor(getAndroidTestColor(color)); + setValue(value); + } + } + public void setColor(int color) { this.color = color; - postInvalidate(); + updateText(); } public void setController(final CheckmarkButtonController controller) diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java index b569f9208..1f206ad4b 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.java @@ -31,18 +31,23 @@ import org.isoron.uhabits.models.*; import org.isoron.uhabits.preferences.*; import org.isoron.uhabits.utils.*; +import java.util.*; + import static android.view.View.MeasureSpec.*; +import static org.isoron.uhabits.utils.AttributeSetUtils.*; +import static org.isoron.uhabits.utils.ColorUtils.*; -public class CheckmarkPanelView extends LinearLayout implements Preferences.Listener +public class CheckmarkPanelView extends LinearLayout + implements Preferences.Listener { - private static final int CHECKMARK_LEFT_TO_RIGHT = 0; + private static final int LEFT_TO_RIGHT = 0; - private static final int CHECKMARK_RIGHT_TO_LEFT = 1; + private static final int RIGHT_TO_LEFT = 1; @Nullable private Preferences prefs; - private int checkmarkValues[]; + private int values[]; private int nButtons; @@ -61,61 +66,89 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List init(); } - public CheckmarkPanelView(Context context, AttributeSet attrs) + public CheckmarkPanelView(Context ctx, AttributeSet attrs) { - super(context, attrs); + super(ctx, attrs); init(); + + if (ctx != null && attrs != null) + { + int paletteColor = getIntAttribute(ctx, attrs, "color", 0); + setColor(getAndroidTestColor(paletteColor)); + setButtonCount(getIntAttribute(ctx, attrs, "button_count", 5)); + } + + if (isInEditMode()) initEditMode(); } public CheckmarkButtonView indexToButton(int i) { int position = i; - if (getCheckmarkOrder() == CHECKMARK_RIGHT_TO_LEFT) - position = nButtons - i - 1; + if (getCheckmarkOrder() == RIGHT_TO_LEFT) position = nButtons - i - 1; return (CheckmarkButtonView) getChildAt(position); } + @Override + public void onCheckmarkOrderChanged() + { + setupButtons(); + } + public void setButtonCount(int newButtonCount) { - if(nButtons != newButtonCount) + if (nButtons != newButtonCount) { nButtons = newButtonCount; - addCheckmarkButtons(); + addButtons(); } - setupCheckmarkButtons(); - } - - public void setCheckmarkValues(int[] checkmarkValues) - { - this.checkmarkValues = checkmarkValues; - setupCheckmarkButtons(); + setupButtons(); } public void setColor(int color) { this.color = color; - setupCheckmarkButtons(); + setupButtons(); } public void setController(Controller controller) { this.controller = controller; - setupCheckmarkButtons(); + setupButtons(); } public void setDataOffset(int dataOffset) { this.dataOffset = dataOffset; - setupCheckmarkButtons(); + setupButtons(); } public void setHabit(@NonNull Habit habit) { this.habit = habit; - setupCheckmarkButtons(); + setupButtons(); + } + + public void setValues(int[] values) + { + this.values = values; + setupButtons(); + } + + @Override + protected void onAttachedToWindow() + { + super.onAttachedToWindow(); + if (prefs != null) prefs.addListener(this); + } + + @Override + protected void onDetachedFromWindow() + { + if (prefs != null) prefs.removeListener(this); + super.onDetachedFromWindow(); } @Override @@ -133,7 +166,7 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List super.onMeasure(widthSpec, heightSpec); } - private void addCheckmarkButtons() + private void addButtons() { removeAllViews(); @@ -143,21 +176,31 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List private int getCheckmarkOrder() { - if (prefs == null) return CHECKMARK_LEFT_TO_RIGHT; - return prefs.shouldReverseCheckmarks() ? CHECKMARK_RIGHT_TO_LEFT : - CHECKMARK_LEFT_TO_RIGHT; + if (prefs == null) return LEFT_TO_RIGHT; + return prefs.shouldReverseCheckmarks() ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; } private void init() { Context appContext = getContext().getApplicationContext(); - if(appContext instanceof HabitsApplication) + if (appContext instanceof HabitsApplication) { HabitsApplication app = (HabitsApplication) appContext; prefs = app.getComponent().getPreferences(); } setWillNotDraw(false); + values = new int[0]; + } + + private void initEditMode() + { + int values[] = new int[nButtons]; + + for (int i = 0; i < nButtons; i++) + values[i] = new Random().nextInt(3); + + setValues(values); } private void setupButtonControllers(long timestamp, @@ -178,7 +221,7 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List buttonView.setController(buttonController); } - private void setupCheckmarkButtons() + private void setupButtons() { long timestamp = DateUtils.getStartOfToday(); long day = DateUtils.millisecondsInOneDay; @@ -187,34 +230,14 @@ public class CheckmarkPanelView extends LinearLayout implements Preferences.List for (int i = 0; i < nButtons; i++) { CheckmarkButtonView buttonView = indexToButton(i); - if(i + dataOffset >= checkmarkValues.length) break; - buttonView.setValue(checkmarkValues[i + dataOffset]); + if (i + dataOffset >= values.length) break; + buttonView.setValue(values[i + dataOffset]); buttonView.setColor(color); setupButtonControllers(timestamp, buttonView); timestamp -= day; } } - @Override - protected void onAttachedToWindow() - { - super.onAttachedToWindow(); - if(prefs != null) prefs.addListener(this); - } - - @Override - protected void onDetachedFromWindow() - { - if(prefs != null) prefs.removeListener(this); - super.onDetachedFromWindow(); - } - - @Override - public void onCheckmarkOrderChanged() - { - setupCheckmarkButtons(); - } - public interface Controller extends CheckmarkButtonController.Listener { diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java index d57e0a71c..e703ba18c 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java @@ -99,7 +99,7 @@ public class HabitCardView extends FrameLayout public void setCheckmarkValues(int checkmarks[]) { - checkmarkPanel.setCheckmarkValues(checkmarks); + checkmarkPanel.setValues(checkmarks); postInvalidate(); } @@ -213,7 +213,7 @@ public class HabitCardView extends FrameLayout scoreRing.setColor(color); scoreRing.setPercentage(rand.nextFloat()); checkmarkPanel.setColor(color); - checkmarkPanel.setCheckmarkValues(values); + checkmarkPanel.setValues(values); } private void refresh() diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java new file mode 100644 index 000000000..1d4d4f103 --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java @@ -0,0 +1,131 @@ +/* + * 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.activities.habits.list.views; + +import android.content.*; +import android.graphics.*; +import android.support.annotation.*; +import android.util.*; +import android.view.*; +import android.widget.*; + +import org.isoron.uhabits.*; +import org.isoron.uhabits.activities.habits.list.controllers.*; +import org.isoron.uhabits.utils.*; + +import static org.isoron.uhabits.utils.AttributeSetUtils.*; +import static org.isoron.uhabits.utils.ColorUtils.*; + +public class NumberButtonView extends TextView +{ + private static Typeface TYPEFACE = + Typeface.create("sans-serif-condensed", Typeface.BOLD); + + private int color; + + private int value; + + private int threshold; + + private StyledResources res; + + public NumberButtonView(@Nullable Context context) + { + super(context); + init(); + } + + public NumberButtonView(@Nullable Context context, + @Nullable AttributeSet attrs) + { + super(context, attrs); + init(); + + if (context != null && attrs != null) + { + int color = getIntAttribute(context, attrs, "color", 0); + int value = getIntAttribute(context, attrs, "value", 0); + int threshold = getIntAttribute(context, attrs, "threshold", 1); + setColor(getAndroidTestColor(color)); + setThreshold(threshold); + setValue(value); + } + } + + private static String formatValue(int v) + { + double fv = (double) v; + if(v >= 1e9) return String.format("%.2fG", fv / 1e9); + if(v >= 1e8) return String.format("%.0fM", fv / 1e6); + if(v >= 1e7) return String.format("%.1fM", fv / 1e6); + if(v >= 1e6) return String.format("%.2fM", fv / 1e6); + if(v >= 1e5) return String.format("%.0fk", fv / 1e3); + if(v >= 1e4) return String.format("%.1fk", fv / 1e3); + if(v >= 1e3) return String.format("%.2fk", fv / 1e3); + return String.format("%d", v); + } + + public void setColor(int color) + { + this.color = color; + postInvalidate(); + } + + public void setController(final NumberButtonController controller) + { + setOnClickListener(v -> controller.onClick()); + setOnLongClickListener(v -> controller.onLongClick()); + } + + public void setThreshold(int threshold) + { + this.threshold = threshold; + updateText(); + } + + public void setValue(int value) + { + this.value = value; + updateText(); + } + + private void init() + { + res = new StyledResources(getContext()); + + setWillNotDraw(false); + + setMinHeight( + getResources().getDimensionPixelSize(R.dimen.checkmarkHeight)); + setMinWidth( + getResources().getDimensionPixelSize(R.dimen.checkmarkWidth)); + + setFocusable(false); + setGravity(Gravity.CENTER); + setTypeface(TYPEFACE); + } + + private void updateText() + { + int lowColor = res.getColor(R.attr.lowContrastTextColor); + setTextColor(value >= threshold ? color : lowColor); + setText(formatValue(value)); + } +} diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java new file mode 100644 index 000000000..16ac11e9a --- /dev/null +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java @@ -0,0 +1,255 @@ +/* + * 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.activities.habits.list.views; + +import android.content.*; +import android.support.annotation.*; +import android.util.*; +import android.widget.*; + +import org.isoron.uhabits.*; +import org.isoron.uhabits.activities.habits.list.*; +import org.isoron.uhabits.activities.habits.list.controllers.*; +import org.isoron.uhabits.models.*; +import org.isoron.uhabits.preferences.*; +import org.isoron.uhabits.utils.*; + +import java.util.*; + +import static android.view.View.MeasureSpec.*; +import static org.isoron.uhabits.utils.AttributeSetUtils.*; +import static org.isoron.uhabits.utils.ColorUtils.*; + +public class NumberPanelView extends LinearLayout + implements Preferences.Listener +{ + private static final int LEFT_TO_RIGHT = 0; + + private static final int RIGHT_TO_LEFT = 1; + + @Nullable + private Preferences prefs; + + private int values[]; + + private int threshold; + + private int nButtons; + + private int color; + + private Controller controller; + + @NonNull + private Habit habit; + + private int dataOffset; + + public NumberPanelView(Context context) + { + super(context); + init(); + } + + public NumberPanelView(Context ctx, AttributeSet attrs) + { + super(ctx, attrs); + init(); + + if (ctx != null && attrs != null) + { + int paletteColor = getIntAttribute(ctx, attrs, "color", 0); + setColor(getAndroidTestColor(paletteColor)); + setButtonCount(getIntAttribute(ctx, attrs, "button_count", 5)); + setThreshold(getIntAttribute(ctx, attrs, "threshold", 1)); + } + + if(isInEditMode()) initEditMode(); + } + + private void initEditMode() + { + int values[] = new int[nButtons]; + + for(int i = 0; i < nButtons; i++) + values[i] = new Random().nextInt(threshold * 3); + + setValues(values); + } + + public NumberButtonView indexToButton(int i) + { + int position = i; + + if (getCheckmarkOrder() == RIGHT_TO_LEFT) position = nButtons - i - 1; + + return (NumberButtonView) getChildAt(position); + } + + @Override + public void onCheckmarkOrderChanged() + { + setupButtons(); + } + + public void setButtonCount(int newButtonCount) + { + if (nButtons != newButtonCount) + { + nButtons = newButtonCount; + addButtons(); + } + + setupButtons(); + } + + public void setColor(int color) + { + this.color = color; + setupButtons(); + } + + public void setController(Controller controller) + { + this.controller = controller; + setupButtons(); + } + + public void setDataOffset(int dataOffset) + { + this.dataOffset = dataOffset; + setupButtons(); + } + + public void setHabit(@NonNull Habit habit) + { + this.habit = habit; + setupButtons(); + } + + public void setThreshold(int threshold) + { + this.threshold = threshold; + setupButtons(); + } + + public void setValues(int[] values) + { + this.values = values; + setupButtons(); + } + + @Override + protected void onAttachedToWindow() + { + super.onAttachedToWindow(); + if (prefs != null) prefs.addListener(this); + } + + @Override + protected void onDetachedFromWindow() + { + if (prefs != null) prefs.removeListener(this); + super.onDetachedFromWindow(); + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) + { + float buttonWidth = getResources().getDimension(R.dimen.checkmarkWidth); + float buttonHeight = + getResources().getDimension(R.dimen.checkmarkHeight); + + float width = buttonWidth * nButtons; + + widthSpec = makeMeasureSpec((int) width, EXACTLY); + heightSpec = makeMeasureSpec((int) buttonHeight, EXACTLY); + + super.onMeasure(widthSpec, heightSpec); + } + + private void addButtons() + { + removeAllViews(); + + for (int i = 0; i < nButtons; i++) + addView(new NumberButtonView(getContext())); + } + + private int getCheckmarkOrder() + { + if (prefs == null) return LEFT_TO_RIGHT; + return prefs.shouldReverseCheckmarks() ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; + } + + private void init() + { + Context appContext = getContext().getApplicationContext(); + if (appContext instanceof HabitsApplication) + { + HabitsApplication app = (HabitsApplication) appContext; + prefs = app.getComponent().getPreferences(); + } + + setWillNotDraw(false); + values = new int[0]; + } + + private void setupButtonControllers(long timestamp, + NumberButtonView buttonView) + { + if (controller == null) return; + if (!(getContext() instanceof ListHabitsActivity)) return; + + ListHabitsActivity activity = (ListHabitsActivity) getContext(); + NumberButtonControllerFactory buttonControllerFactory = activity + .getListHabitsComponent() + .getNumberButtonControllerFactory(); + + NumberButtonController buttonController = + buttonControllerFactory.create(habit, timestamp); + buttonController.setListener(controller); + buttonController.setView(buttonView); + buttonView.setController(buttonController); + } + + private void setupButtons() + { + long timestamp = DateUtils.getStartOfToday(); + long day = DateUtils.millisecondsInOneDay; + timestamp -= day * dataOffset; + + for (int i = 0; i < nButtons; i++) + { + NumberButtonView buttonView = indexToButton(i); + if (i + dataOffset >= values.length) break; + buttonView.setValue(values[i + dataOffset]); + buttonView.setColor(color); + buttonView.setThreshold(threshold); + setupButtonControllers(timestamp, buttonView); + timestamp -= day; + } + } + + public interface Controller extends NumberButtonController.Listener + { + + } +} diff --git a/app/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java b/app/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java index c633a9b72..67c9de531 100644 --- a/app/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java +++ b/app/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.java @@ -74,4 +74,14 @@ public class AttributeSetUtils if (number != null) return Float.parseFloat(number); else return defaultValue; } + + public static int getIntAttribute(@NonNull Context context, + @NonNull AttributeSet attrs, + @NonNull String name, + int defaultValue) + { + String number = getAttribute(context, attrs, name, null); + if (number != null) return Integer.parseInt(number); + else return defaultValue; + } } diff --git a/app/src/main/res/layout/list_habits_button_preview.xml b/app/src/main/res/layout/list_habits_button_preview.xml new file mode 100644 index 000000000..5f2724a07 --- /dev/null +++ b/app/src/main/res/layout/list_habits_button_preview.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_habits_panel_preview.xml b/app/src/main/res/layout/list_habits_panel_preview.xml new file mode 100644 index 000000000..54393cad1 --- /dev/null +++ b/app/src/main/res/layout/list_habits_panel_preview.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file