package org.xdty.preference;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.Preference;
import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.xdty.preference.colorpicker.ColorPickerDialog;
import org.xdty.preference.colorpicker.ColorPickerSwatch;
import org.xdty.preference.colorpicker.R;
/**
* A preference showing a {@link ColorPickerDialog} to allow the user to select a color to save as {@link Preference}.
*/
public class ColorPreference extends Preference implements ColorPickerSwatch
.OnColorSelectedListener {
private static final int DEFAULT_VALUE = Color.BLACK;
private int mTitle = R.string.color_picker_default_title;
private int mCurrentValue;
private int[] mColors;
private int mColumns;
private boolean mMaterial;
private View mColorView;
public ColorPreference(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ColorPreference, 0, 0);
try {
int id = a.getResourceId(R.styleable.ColorPreference_colorDialogColors, R.array.default_rainbow);
if (id != 0) {
mColors = getContext().getResources().getIntArray(id);
}
id = a.getResourceId(R.styleable.ColorPreference_colorDialogTitle, 0);
if (id != 0) {
mTitle = a.getResourceId(R.styleable.ColorPreference_colorDialogTitle, R.string.color_picker_default_title);
}
mColumns = a.getInt(R.styleable.ColorPreference_colorDialogColumns, 5);
mMaterial = a.getBoolean(R.styleable.ColorPreference_colorDialogMaterial, true);
} finally {
a.recycle();
}
}
@Override protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInteger(index, DEFAULT_VALUE);
}
@Override protected View onCreateView(ViewGroup parent) {
View s = super.onCreateView(parent);
mColorView = new View(getContext());
int size = (int) dpToPx(32);
mColorView.setLayoutParams(new ViewGroup.LayoutParams(size, size));
updateShownColor();
ViewGroup w = (ViewGroup) s.findViewById(android.R.id.widget_frame);
w.setVisibility(View.VISIBLE);
w.addView(mColorView);
return s;
}
@Override protected void onBindView(View view) {
super.onBindView(view);
if (mMaterial) {
TextView textTitle = (TextView) view.findViewById(android.R.id.title);
TextView textSummary = (TextView) view.findViewById(android.R.id.summary);
textTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
textSummary.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
textTitle.setTextColor(getColor(android.R.attr.textColorPrimary));
textSummary.setTextColor(getColor(android.R.attr.textColorSecondary));
View parent = (View) textSummary.getParent().getParent();
parent.setPadding((int) dpToPx(16), 0, (int) dpToPx(16), 0);
}
}
@Override protected void onClick() {
int[] colors = mColors.length != 0 ? mColors : new int[]{
Color.BLACK, Color.WHITE, Color
.RED, Color.GREEN, Color.BLUE
};
ColorPickerDialog d = ColorPickerDialog.newInstance(mTitle,
colors, mCurrentValue, mColumns,
ColorPickerDialog.SIZE_SMALL);
d.setOnColorSelectedListener(this);
d.show(((AppCompatActivity) getContext()).getSupportFragmentManager(), "ColorPickerDialog");
}
@Override protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
if (restorePersistedValue) {
// Restore existing state
mCurrentValue = this.getPersistedInt(DEFAULT_VALUE);
} else {
// Set default state from the XML attribute
mCurrentValue = (Integer) defaultValue;
persistInt(mCurrentValue);
}
}
@Override protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
// Check whether this Preference is persistent (continually saved)
if (isPersistent()) {
// No need to save instance state since it's persistent,
// use superclass state
return superState;
}
// Create instance of custom BaseSavedState
final SavedState myState = new SavedState(superState);
// Set the state's value with the class member that holds current
// setting value
myState.current = mCurrentValue;
myState.colors = mColors;
myState.columns = mColumns;
return myState;
}
@Override protected void onRestoreInstanceState(Parcelable state) {
// Check whether we saved the state in onSaveInstanceState
if (state == null || !state.getClass().equals(SavedState.class)) {
// Didn't save the state, so call superclass
super.onRestoreInstanceState(state);
return;
}
// Cast state to custom BaseSavedState and pass to superclass
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
// Update own values
mCurrentValue = myState.current;
mColors = myState.colors;
mColumns = myState.columns;
// Update shown color
updateShownColor();
// Set this Preference's widget to reflect the restored state
//mNumberPicker.setValue(myState.value);
}
@Override public void onColorSelected(int color) {
persistInt(color);
mCurrentValue = color;
updateShownColor();
}
private void updateShownColor() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mColorView.setBackground(new ShapeDrawable(new OvalShape()));
((ShapeDrawable) mColorView.getBackground()).getPaint().setColor(mCurrentValue);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mColorView.setBackground(new ColorCircleDrawable(mCurrentValue));
} else {
mColorView.setBackground(new ColorCircleDrawable(mCurrentValue));
}
mColorView.invalidate();
}
/**
* Convert a dp size to pixel. Useful for specifying view sizes in code.
*
* @param dp
* The size in density-independent pixels.
* @return {@code px} - The size in generic pixels (density-dependent).
*/
private float dpToPx(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
getContext().getResources().getDisplayMetrics());
}
private int getColor(int attrId) {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = getContext().getTheme();
theme.resolveAttribute(attrId, typedValue, true);
TypedArray arr = getContext().obtainStyledAttributes(typedValue.data, new int[]{attrId});
int color = arr.getColor(0, -1);
arr.recycle();
return color;
}
private static class SavedState extends BaseSavedState {
// Standard creator object using an instance of this class
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
// Member that holds the preference's values
int current;
int[] colors;
int columns;
public SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
// Get the current preference's values
current = source.readInt();
source.readIntArray(colors);
columns = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Write the preference's values
dest.writeInt(current);
dest.writeIntArray(colors);
dest.writeInt(columns);
}
}
}