package com.beardedhen.androidbootstrap;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import com.beardedhen.androidbootstrap.api.attributes.BootstrapBrand;
import com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition;
import com.beardedhen.androidbootstrap.api.defaults.ButtonMode;
import com.beardedhen.androidbootstrap.api.defaults.DefaultBootstrapBrand;
import com.beardedhen.androidbootstrap.api.defaults.DefaultBootstrapSize;
import com.beardedhen.androidbootstrap.api.view.BootstrapBrandView;
import com.beardedhen.androidbootstrap.api.view.BootstrapSizeView;
import com.beardedhen.androidbootstrap.api.view.ButtonModeView;
import com.beardedhen.androidbootstrap.api.view.OutlineableView;
import com.beardedhen.androidbootstrap.api.view.RoundableView;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.BOTTOM;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.END;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.MIDDLE_HORI;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.MIDDLE_VERT;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.SOLO;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.START;
import static com.beardedhen.androidbootstrap.api.attributes.ViewGroupPosition.TOP;
/**
* BootstrapButtonGroups are a LinearLayout which exclusively holds BootstrapButtons. It is possible
* to set the properties of all children with one method call to this view. Options include
* BootstrapBrand colors, roundable corners, 'outlineable' mode and different selection modes
* e.g. Checkbox/Radio group.
* If button mode is set to radio only one button is a button group may be selected at a time.
*/
public class BootstrapButtonGroup extends BootstrapGroup implements BootstrapSizeView,
OutlineableView, RoundableView, BootstrapBrandView, ButtonModeView {
private static final String TAG = "com.beardedhen.androidbootstrap.BootstrapButtonGroup";
private static final String KEY_MODE = "com.beardedhen.androidbootstrap.BootstrapButtonGroup.MODE";
private float bootstrapSize;
private ButtonMode buttonMode;
private BootstrapBrand bootstrapBrand;
private boolean rounded;
private boolean outline;
private int checkedButtonId = 0;
public BootstrapButtonGroup(Context context) {
super(context);
initialise(null);
}
public BootstrapButtonGroup(Context context, AttributeSet attrs) {
super(context, attrs);
initialise(attrs);
}
public BootstrapButtonGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialise(attrs);
}
protected void initialise(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.BootstrapButtonGroup);
try {
this.rounded = a.getBoolean(R.styleable.BootstrapButtonGroup_roundedCorners, false);
this.outline = a.getBoolean(R.styleable.BootstrapButtonGroup_showOutline, false);
int typeOrdinal = a.getInt(R.styleable.BootstrapButtonGroup_buttonMode, -1);
int brandOrdinal = a.getInt(R.styleable.BootstrapButtonGroup_bootstrapBrand, -1);
int sizeOrdinal = a.getInt(R.styleable.BootstrapButtonGroup_bootstrapSize, -1);
this.checkedButtonId = a.getResourceId(R.styleable.BootstrapButtonGroup_checkedButton, 0);
this.buttonMode = ButtonMode.fromAttributeValue(typeOrdinal);
this.bootstrapBrand = DefaultBootstrapBrand.fromAttributeValue(brandOrdinal);
this.bootstrapSize = DefaultBootstrapSize.fromAttributeValue(sizeOrdinal).scaleFactor();
}
finally {
a.recycle();
}
updateBootstrapGroup();
}
@Override public Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(TAG, super.onSaveInstanceState());
bundle.putSerializable(KEY_MODE, buttonMode);
bundle.putSerializable(BootstrapBrand.KEY, bootstrapBrand);
bundle.putBoolean(RoundableView.KEY, rounded);
bundle.putBoolean(OutlineableView.KEY, outline);
return bundle;
}
@Override public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
outline = bundle.getBoolean(OutlineableView.KEY);
rounded = bundle.getBoolean(RoundableView.KEY);
Serializable brand = bundle.getSerializable(BootstrapBrand.KEY);
Serializable m = bundle.getSerializable(KEY_MODE);
if (m instanceof ButtonMode) {
buttonMode = (ButtonMode) m;
}
if (brand instanceof BootstrapBrand) {
bootstrapBrand = (BootstrapBrand) brand;
}
state = bundle.getParcelable(TAG);
}
super.onRestoreInstanceState(state);
updateBootstrapGroup();
}
@Override
protected void onBootstrapViewAdded() {
updateBootstrapGroup();
}
@Override
protected void onBootstrapViewRemoved() {
updateBootstrapGroup();
}
protected void updateBootstrapGroup() {
int childCount = getChildCount();
int orientation = getOrientation();
// tell children their position so they can draw backgrounds appropriately
if (childCount == 0) {
return;
}
else if (childCount == 1) {
BootstrapButton button = retrieveButtonChild(0);
button.setViewGroupPosition(SOLO, 0);
}
List<BootstrapButton> buttonList = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
BootstrapButton button = retrieveButtonChild(i);
if (button.getVisibility() == VISIBLE) {
buttonList.add(button);
}
}
final int size = buttonList.size();
for (int i = 0; i < size; i++) {
BootstrapButton button = buttonList.get(i);
ViewGroupPosition position;
if (i == 0) { // first view
position = orientation == HORIZONTAL ? START : TOP;
}
else if (i == size - 1) { // last view
position = orientation == HORIZONTAL ? END : BOTTOM;
}
else {
position = orientation == HORIZONTAL ? MIDDLE_HORI : MIDDLE_VERT;
}
button.setViewGroupPosition(position, i);
button.updateFromParent(bootstrapBrand, bootstrapSize, buttonMode, outline, rounded);
if (buttonMode == ButtonMode.RADIO && button.isMustBeSelected()) {
button.setSelected(true);
onRadioToggle(i);
checkedButtonId = 0; //BootstrapButton "checked" attribute is preferable
}
else if (buttonMode == ButtonMode.RADIO && button.getId() == checkedButtonId) {
button.setSelected(true);
onRadioToggle(i);
}
}
}
private BootstrapButton retrieveButtonChild(int i) {
View view = getChildAt(i);
if ((view instanceof BootstrapButton)) {
return (BootstrapButton) view;
}
else {
throw new IllegalStateException("All child view of BootstrapButtonGroup must be BootstrapButtons");
}
}
/**
* Used for Radio Group Mode - resets all children to an unselected state,
* apart from the calling Button.
*
* @param index the index of the button becoming selected
*/
void onRadioToggle(int index) {
for (int i = 0; i < getChildCount(); i++) {
if (i != index) {
BootstrapButton b = retrieveButtonChild(i);
b.setSelected(false);
}
}
}
/*
* Getters / Setters
*/
public void check(@IdRes int id) {
this.checkedButtonId = id;
}
@Override public float getBootstrapSize() {
return bootstrapSize;
}
@Override public void setBootstrapSize(DefaultBootstrapSize bootstrapSize) {
setBootstrapSize(bootstrapSize.scaleFactor());
}
@Override public void setBootstrapSize(float bootstrapSize) {
this.bootstrapSize = bootstrapSize;
for (int i = 0; i < getChildCount(); i++) {
BootstrapButton button = retrieveButtonChild(i);
button.setBootstrapSize(this.bootstrapSize);
}
}
@NonNull public ButtonMode getButtonMode() {
return buttonMode;
}
public void setButtonMode(@NonNull ButtonMode buttonMode) {
this.buttonMode = buttonMode;
for (int i = 0; i < getChildCount(); i++) {
BootstrapButton button = retrieveButtonChild(i);
button.setButtonMode(buttonMode);
}
}
@Override public void setBootstrapBrand(@NonNull BootstrapBrand bootstrapBrand) {
this.bootstrapBrand = bootstrapBrand;
for (int i = 0; i < getChildCount(); i++) {
BootstrapButton button = retrieveButtonChild(i);
button.setBootstrapBrand(bootstrapBrand);
}
}
@NonNull @Override public BootstrapBrand getBootstrapBrand() {
return bootstrapBrand;
}
@Override public void setShowOutline(boolean showOutline) {
this.outline = showOutline;
for (int i = 0; i < getChildCount(); i++) {
BootstrapButton button = retrieveButtonChild(i);
button.setShowOutline(outline);
}
}
@Override public boolean isShowOutline() {
return outline;
}
@Override public void setRounded(boolean rounded) {
this.rounded = rounded;
for (int i = 0; i < getChildCount(); i++) {
BootstrapButton button = retrieveButtonChild(i);
button.setRounded(rounded);
}
}
@Override public boolean isRounded() {
return rounded;
}
}