From c0d100d165254265432d4ed85bb65cfba5aea361 Mon Sep 17 00:00:00 2001 From: Phillip Hsu Date: Mon, 22 Aug 2016 03:45:58 -0700 Subject: [PATCH] Numpad looking good --- app/build.gradle | 3 + .../com/philliphsu/clock2/MainActivity.java | 5 ++ .../editalarm/BaseTimePickerDialog.java | 51 +++++++++++++ .../clock2/editalarm/GridLayoutNumpad.java | 26 +++++++ .../editalarm/NumberGridTimePickerDialog.java | 7 ++ .../clock2/editalarm/NumpadTimePicker.java | 75 ++++++++++++++++++- .../editalarm/NumpadTimePickerDialog.java | 34 ++++++++- app/src/main/res/color/fab_icon_color.xml | 6 ++ app/src/main/res/color/icon_color.xml | 5 ++ app/src/main/res/color/icon_color_dark.xml | 5 ++ .../res/color/numeric_keypad_button_text.xml | 6 ++ .../color/numeric_keypad_button_text_dark.xml | 6 ++ .../res/color/numeric_keypad_fab_color.xml | 5 ++ .../color/numeric_keypad_fab_color_dark.xml | 5 ++ .../main/res/drawable/ic_backspace_24dp.xml | 2 +- app/src/main/res/layout/activity_main.xml | 2 +- .../content_grid_layout_numpad_dark.xml | 54 +++++++++++++ .../res/layout/content_numpad_time_picker.xml | 5 +- .../content_numpad_time_picker_dark.xml | 33 ++++++++ .../res/layout/dialog_time_picker_numpad.xml | 8 +- .../res/values/aosp_datetimepicker_colors.xml | 13 ++++ app/src/main/res/values/styles.xml | 8 +- 22 files changed, 351 insertions(+), 13 deletions(-) create mode 100644 app/src/main/res/color/fab_icon_color.xml create mode 100644 app/src/main/res/color/icon_color.xml create mode 100644 app/src/main/res/color/icon_color_dark.xml create mode 100644 app/src/main/res/color/numeric_keypad_button_text.xml create mode 100644 app/src/main/res/color/numeric_keypad_button_text_dark.xml create mode 100644 app/src/main/res/color/numeric_keypad_fab_color.xml create mode 100644 app/src/main/res/color/numeric_keypad_fab_color_dark.xml create mode 100644 app/src/main/res/layout/content_grid_layout_numpad_dark.xml create mode 100644 app/src/main/res/layout/content_numpad_time_picker_dark.xml diff --git a/app/build.gradle b/app/build.gradle index eadc27e..03915ba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,6 +10,9 @@ android { targetSdkVersion 23 versionCode 1 versionName "1.0" + // Disabled for now because we're not ready to + // completely port over to vector drawables +// vectorDrawables.useSupportLibrary = true } buildTypes { release { diff --git a/app/src/main/java/com/philliphsu/clock2/MainActivity.java b/app/src/main/java/com/philliphsu/clock2/MainActivity.java index abd86cd..6049991 100644 --- a/app/src/main/java/com/philliphsu/clock2/MainActivity.java +++ b/app/src/main/java/com/philliphsu/clock2/MainActivity.java @@ -52,6 +52,11 @@ public class MainActivity extends BaseActivity { @Bind(R.id.fab) FloatingActionButton mFab; +// // https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.141274xy8 +// // This is needed to load vector drawables from 23.4.0 +// static { +// AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); +// } @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/BaseTimePickerDialog.java b/app/src/main/java/com/philliphsu/clock2/editalarm/BaseTimePickerDialog.java index 0425216..5604d96 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/BaseTimePickerDialog.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/BaseTimePickerDialog.java @@ -14,6 +14,7 @@ import butterknife.ButterKnife; * Created by Phillip Hsu on 7/16/2016. */ public abstract class BaseTimePickerDialog extends BottomSheetDialogFragment { + private static final String TAG = "BaseTimePickerDialog"; // TODO: Consider private access, and then writing package/protected API that subclasses // can use to interface with this field. @@ -53,9 +54,59 @@ public abstract class BaseTimePickerDialog extends BottomSheetDialogFragment { // getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); final View view = inflater.inflate(contentLayout(), container, false); ButterKnife.bind(this, view); + + // TODO: We could move this to onCreateDialog() if we cared. + // + // onShow() is called immediately as this DialogFragment is showing, so the + // FAB's animation will barely be noticeable. +// getDialog().setOnShowListener(new DialogInterface.OnShowListener() { +// @Override +// public void onShow(DialogInterface dialog) { +// Log.i(TAG, "onShow()"); +// // Animate the FAB into view +// View v = view.findViewById(R.id.fab); +// if (v != null) { +// FloatingActionButton fab = (FloatingActionButton) v; +// fab.show(); +// } +// } +// }); + return view; } +// @Override +// public void onResume() { +// super.onResume(); +// final View view = getView(); +// final BottomSheetBehavior behavior = BottomSheetBehavior.from((View) view.getParent()); +// // Copy over the internal callback logic, and also implement our own +// // +// // This callback is set AFTER this Fragment has become visible, so is useless for what +// // you wanted to do (show the FAB during the settling phase). +// behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { +// @Override +// public void onStateChanged(@NonNull View bottomSheet, int newState) { +// Log.i(TAG, "onStateChanged(): " + newState); +// if (newState == BottomSheetBehavior.STATE_HIDDEN) { +// dismiss(); +// } +// // My logic below +// else if (newState == BottomSheetBehavior.STATE_SETTLING) { +// View fab = view.findViewById(R.id.fab); +// if (fab != null) { +// ((FloatingActionButton) fab).show(); +// } +// } +// } +// +// @Override +// public void onSlide(@NonNull View bottomSheet, float slideOffset) { +// +// } +// }); +// } + @Override public void onDestroyView() { super.onDestroyView(); diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/GridLayoutNumpad.java b/app/src/main/java/com/philliphsu/clock2/editalarm/GridLayoutNumpad.java index 4fc5fb1..a40bf72 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/GridLayoutNumpad.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/GridLayoutNumpad.java @@ -1,8 +1,10 @@ package com.philliphsu.clock2.editalarm; import android.content.Context; +import android.content.res.ColorStateList; import android.support.annotation.CallSuper; import android.support.annotation.LayoutRes; +import android.support.v4.content.ContextCompat; import android.support.v7.widget.GridLayout; import android.util.AttributeSet; import android.view.View; @@ -23,6 +25,10 @@ import butterknife.OnClick; * Unlike Numpad, this class only manages the logic for number button clicks * and not the backspace button. However, we do provide an API for removing * digits from the input. + * + * TODO: Is NumpadTimePicker the only subclass? If so, why do we need this + * superclass? If we move the contents of this class to NumpadTimePicker, + * the implementation of setTheme() would make more sense. */ public abstract class GridLayoutNumpad extends GridLayout { // TODO: change to private? @@ -33,6 +39,8 @@ public abstract class GridLayoutNumpad extends GridLayout { private int mCount = 0; private OnInputChangeListener mOnInputChangeListener; + ColorStateList mColors; + @Bind({ R.id.zero, R.id.one, R.id.two, R.id.three, R.id.four, R.id.five, R.id.six, R.id.seven, R.id.eight, R.id.nine }) TextView[] mButtons; @@ -64,6 +72,24 @@ public abstract class GridLayoutNumpad extends GridLayout { init(); } + void setTheme(Context context, boolean themeDark) { + // Since the Dialog class already set the background color of its entire view tree, + // our background is already colored. Why did we set it in the Dialog class? Because + // we use margins around the numpad, and if we had instead set the background on + // this numpad here, the margins will not be colored. Why not use padding instead + // of margins? It turns out we tried that--replacing each margin attribute + // with the padding counterpart--but we lost the pre-21 FAB inherent bottom margin. + + // The buttons are actually of type Button, but we kept references + // to them as TextViews... which is fine since TextView is the superclass + // of Button. + mColors = ContextCompat.getColorStateList(context, + themeDark? R.color.numeric_keypad_button_text_dark : R.color.numeric_keypad_button_text); + for (TextView b : mButtons) { + b.setTextColor(mColors); + } + } + /** * @return the number of digits we can input */ diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/NumberGridTimePickerDialog.java b/app/src/main/java/com/philliphsu/clock2/editalarm/NumberGridTimePickerDialog.java index 9f4443e..19b744b 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/NumberGridTimePickerDialog.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/NumberGridTimePickerDialog.java @@ -470,6 +470,13 @@ public class NumberGridTimePickerDialog extends BaseTimePickerDialog implements // Set the color on the FAB // http://stackoverflow.com/a/32031019/5055032 + // ***************************************************************************************** + // NOTE: IF YOU DECIDE TO MOVE THE FAB AND THE HALF DAY TOGGLES TO THE GRIDSELECTORLAYOUT + // CLASS, YOU SHOULD CHANGE THE CONTEXT PASSED TO GridSelectorLayout#setTheme() FROM THE + // APPLICATION CONTEXT TO THE LOCAL CONTEXT. OTHERWISE, IT WOULD NOT BE ABLE TO RETRIEVE + // THE CORRECT ACCENT COLOR. WE ALREADY FACED THIS ISSUE WITH THE NUMPADTIMEPICKERDIALOG. + // DO A CTRL+F FOR mTimePicker.setTheme FOR THE CODE IN DISCUSSION. + // ***************************************************************************************** // Color in normal state mDoneButton.setBackgroundTintList(ColorStateList.valueOf(accentColor)); // Color in pressed state. A ripple expands outwards from the point of contact throughout diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePicker.java b/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePicker.java index 3558e0d..6de090f 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePicker.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePicker.java @@ -1,8 +1,12 @@ package com.philliphsu.clock2.editalarm; import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.drawable.Drawable; import android.support.annotation.IntDef; import android.support.design.widget.FloatingActionButton; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.drawable.DrawableCompat; import android.text.format.DateFormat; import android.util.AttributeSet; import android.widget.Button; @@ -10,6 +14,8 @@ import android.widget.ImageButton; import android.widget.TextView; import com.philliphsu.clock2.R; +import com.philliphsu.clock2.aospdatetimepicker.Utils; +import com.philliphsu.clock2.util.ConversionUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -55,6 +61,11 @@ public class NumpadTimePicker extends GridLayoutNumpad { @Bind(R.id.fab) FloatingActionButton mFab; @Bind(R.id.backspace) ImageButton mBackspace; + private boolean mThemeDark; + private int mAccentColor; + private int mFabDisabledColorDark; + private int mFabDisabledColorLight; + /** * Provides additional APIs to configure clients' display output. */ @@ -75,7 +86,53 @@ public class NumpadTimePicker extends GridLayoutNumpad { super(context, attrs); init(); } - + + @Override + void setTheme(Context context, boolean themeDark) { + super.setTheme(context, themeDark); + mThemeDark = themeDark; + + // So, we kept the 0-9 buttons as TextViews, but here we kept + // the alt buttons as actual Buttons... + for (Button b : mAltButtons) { + b.setTextColor(mColors); + } + + // Get a mutable instance of the drawable, so we only affect this instance. + // This is especially useful when you need to modify properties of drawables loaded from + // resources. By default, all drawables instances loaded from the same resource share a + // common state; if you modify the state of one instance, all the other instances will + // receive the same modification. + // TODO: What is the VectorDrawable counterpart for this process? + Drawable backspaceDrawable = mBackspace.getDrawable().mutate(); + // Wrap drawable so that it may be used for tinting across the different + // API levels, via the tinting methods in this class. + backspaceDrawable = DrawableCompat.wrap(backspaceDrawable); + // Prepare the tints + ColorStateList colorBackspace = ContextCompat.getColorStateList(context, + themeDark? R.color.icon_color_dark : R.color.icon_color); + DrawableCompat.setTintList(backspaceDrawable, colorBackspace); + mBackspace.setImageDrawable(backspaceDrawable); + + // TODO: What is the VectorDrawable counterpart for this process? + Drawable iconDrawable = mFab.getDrawable().mutate(); + iconDrawable = DrawableCompat.wrap(iconDrawable); + ColorStateList colorIcon = ContextCompat.getColorStateList(context, + themeDark? R.color.icon_color_dark : R.color.fab_icon_color); + DrawableCompat.setTintList(iconDrawable, colorIcon); + mFab.setImageDrawable(iconDrawable); + + // this.getContext() ==> default teal accent color + // application context ==> white + // The Context that was passed in is NumpadTimePickerDialog.getContext() which + // is probably the host Activity. I have no idea what this.getContext() returns, + // but its probably some internal type that isn't tied to any of our application + // components. + mAccentColor = Utils.getThemeAccentColor(context); + // Make sure the dark theme disabled color shows up initially + updateFabState(); + } + @Override public int capacity() { return MAX_DIGITS; @@ -255,6 +312,9 @@ public class NumpadTimePicker extends GridLayoutNumpad { } private void init() { + mFabDisabledColorDark = ContextCompat.getColor(getContext(), R.color.fab_disabled_dark); + mFabDisabledColorLight = ContextCompat.getColor(getContext(), R.color.fab_disabled_light); + // TODO: We should have the user pass in is24HourMode when they create an instance of the dialog. if (DateFormat.is24HourFormat(getContext())) { mAltButtons[0].setText(R.string.left_alt_24hr); mAltButtons[1].setText(R.string.right_alt_24hr); @@ -383,6 +443,19 @@ public class NumpadTimePicker extends GridLayoutNumpad { private void updateFabState() { mFab.setEnabled(checkTimeValid()); + // Workaround for mFab.setBackgroundTintList() because I don't know how to reference the + // correct accent color in XML. Also because I don't want to programmatically create a + // ColorStateList. + int color; + // TODO: Animate elevation property "compatElevation" + if (mFab.isEnabled()) { + color = mAccentColor; + mFab.setCompatElevation(ConversionUtils.dpToPx(getContext(), 6)); + } else { + color = mThemeDark? mFabDisabledColorDark : mFabDisabledColorLight; + mFab.setCompatElevation(0); + } + mFab.setBackgroundTintList(ColorStateList.valueOf(color)); } private void updateBackspaceState() { diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePickerDialog.java b/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePickerDialog.java index fc1ccd9..3ff9de5 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePickerDialog.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/NumpadTimePickerDialog.java @@ -1,12 +1,14 @@ package com.philliphsu.clock2.editalarm; import android.os.Bundle; +import android.support.v4.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.philliphsu.clock2.R; +import com.philliphsu.clock2.aospdatetimepicker.Utils; import butterknife.Bind; import butterknife.OnClick; @@ -36,6 +38,7 @@ public class NumpadTimePickerDialog extends BaseTimePickerDialog * depends on the dialog to save its state. */ private int[] mInputtedDigits; + private boolean mThemeDark; // Don't need to keep a reference to the dismiss ImageButton @Bind(R.id.input_time) TextView mInputField; @@ -54,7 +57,9 @@ public class NumpadTimePickerDialog extends BaseTimePickerDialog // TODO: is24HourMode param public static NumpadTimePickerDialog newInstance(OnTimeSetListener callback) { NumpadTimePickerDialog ret = new NumpadTimePickerDialog(); + // TODO: Do these in initialize() ret.setOnTimeSetListener(callback); + ret.mThemeDark = false; return ret; } @@ -67,6 +72,17 @@ public class NumpadTimePickerDialog extends BaseTimePickerDialog mIs24HourMode = is24HourMode; } + /** + * Set a dark or light theme. NOTE: this will only take effect for the next onCreateView. + */ + public void setThemeDark(boolean dark) { + mThemeDark = dark; + } + + public boolean isThemeDark() { + return mThemeDark; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -84,8 +100,24 @@ public class NumpadTimePickerDialog extends BaseTimePickerDialog mNumpad.insertDigits(mInputtedDigits); // TOneverDO: before mNumpad.setOnInputChangeListener(this); // Show the cursor immediately // mInputField.requestFocus(); - // TODO: Disabled color //updateInputText(""); // Primarily to disable 'OK' + + // Prepare colors + int accentColor = Utils.getThemeAccentColor(getContext()); + int lightGray = ContextCompat.getColor(getContext(), R.color.light_gray); + int darkGray = ContextCompat.getColor(getContext(), R.color.dark_gray); + int white = ContextCompat.getColor(getContext(), android.R.color.white); + + // Set background color of entire view + view.setBackgroundColor(mThemeDark? darkGray : white); + + TextView inputTime = (TextView) view.findViewById(R.id.input_time); + inputTime.setBackgroundColor(mThemeDark? lightGray : accentColor); + inputTime.setTextColor(ContextCompat.getColor(getContext(), android.R.color.white)); + + mNumpad.setTheme(getContext()/*DO NOT GIVE THE APPLICATION CONTEXT, OR ELSE THE NUMPAD + CAN'T GET THE CORRECT ACCENT COLOR*/, mThemeDark); + return view; } diff --git a/app/src/main/res/color/fab_icon_color.xml b/app/src/main/res/color/fab_icon_color.xml new file mode 100644 index 0000000..32e32d4 --- /dev/null +++ b/app/src/main/res/color/fab_icon_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/icon_color.xml b/app/src/main/res/color/icon_color.xml new file mode 100644 index 0000000..3ff0ce5 --- /dev/null +++ b/app/src/main/res/color/icon_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/icon_color_dark.xml b/app/src/main/res/color/icon_color_dark.xml new file mode 100644 index 0000000..ce0656d --- /dev/null +++ b/app/src/main/res/color/icon_color_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/numeric_keypad_button_text.xml b/app/src/main/res/color/numeric_keypad_button_text.xml new file mode 100644 index 0000000..280d18b --- /dev/null +++ b/app/src/main/res/color/numeric_keypad_button_text.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/numeric_keypad_button_text_dark.xml b/app/src/main/res/color/numeric_keypad_button_text_dark.xml new file mode 100644 index 0000000..c82c02f --- /dev/null +++ b/app/src/main/res/color/numeric_keypad_button_text_dark.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/numeric_keypad_fab_color.xml b/app/src/main/res/color/numeric_keypad_fab_color.xml new file mode 100644 index 0000000..65fafd5 --- /dev/null +++ b/app/src/main/res/color/numeric_keypad_fab_color.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/numeric_keypad_fab_color_dark.xml b/app/src/main/res/color/numeric_keypad_fab_color_dark.xml new file mode 100644 index 0000000..f4a65f0 --- /dev/null +++ b/app/src/main/res/color/numeric_keypad_fab_color_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_backspace_24dp.xml b/app/src/main/res/drawable/ic_backspace_24dp.xml index 54ad8c1..a2da261 100644 --- a/app/src/main/res/drawable/ic_backspace_24dp.xml +++ b/app/src/main/res/drawable/ic_backspace_24dp.xml @@ -4,6 +4,6 @@ android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 665232e..2fcac21 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -43,7 +43,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" - android:src="@drawable/ic_add_24dp" + app:srcCompat="@drawable/ic_add_24dp" android:layout_margin="@dimen/fab_margin" android:tint="@android:color/white"/> diff --git a/app/src/main/res/layout/content_grid_layout_numpad_dark.xml b/app/src/main/res/layout/content_grid_layout_numpad_dark.xml new file mode 100644 index 0000000..765db8e --- /dev/null +++ b/app/src/main/res/layout/content_grid_layout_numpad_dark.xml @@ -0,0 +1,54 @@ + + +