package org.droidplanner.android.view.adapterViews;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import com.o3dr.services.android.lib.drone.property.Parameter;
import org.droidplanner.android.R;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Date: 2013-12-08 Time: 11:00 PM
*/
public class ParamsAdapter extends FilterableArrayAdapter<ParamsAdapterItem> {
public interface OnInfoListener {
void onHelp(int position, EditText valueView);
}
public interface OnParametersChangeListener {
void onParametersChange(int dirtyCount);
}
private final static DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance();
static {
formatter.applyPattern("0.###");
}
private int dirtyCount = 0;
private final int resource;
private final int colorAltRow;
private final LayoutInflater mInflater;
private View focusView;
private OnInfoListener onInfoListener;
private OnParametersChangeListener onParametersChangeListener;
public ParamsAdapter(Context context, int resource) {
this(context, resource, new ArrayList<ParamsAdapterItem>());
}
public ParamsAdapter(Context context, int resource, List<ParamsAdapterItem> objects) {
super(context, resource, objects);
this.resource = resource;
colorAltRow = context.getResources().getColor(R.color.paramAltRow);
mInflater = LayoutInflater.from(context);
}
public void clearFocus() {
if (focusView != null) {
clearFocus(focusView);
focusView = null;
}
}
public void setOnInfoListener(OnInfoListener onInfoListener) {
this.onInfoListener = onInfoListener;
}
public void setOnParametersChangeListener(OnParametersChangeListener onParametersChangeListener){
this.onParametersChangeListener = onParametersChangeListener;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View view;
final ParamTag paramTag;
if (convertView == null) {
// create new view
view = mInflater.inflate(resource, parent, false);
paramTag = new ParamTag();
paramTag.setContainerView(view);
paramTag.setNameView((TextView) view.findViewById(R.id.params_row_name));
paramTag.setDescView((TextView) view.findViewById(R.id.params_row_desc));
paramTag.setValueView((EditText) view.findViewById(R.id.params_row_value));
view.setTag(paramTag);
} else {
// recycle view
view = convertView;
paramTag = (ParamTag) convertView.getTag();
// remove focus
final EditText valueView = paramTag.getValueView();
if (valueView.hasFocus())
clearFocus(valueView);
// detatch listeners
valueView.removeTextChangedListener(paramTag);
valueView.setOnFocusChangeListener(null);
}
// populate fields, set appearance
final ParamsAdapterItem item = getItem(position);
final Parameter param = item.getParameter();
paramTag.setPosition(position);
paramTag.getNameView().setText(param.getName());
paramTag.getDescView().setText(getDescription(param));
paramTag.setAppearance(item);
final EditText valueView = paramTag.getValueView();
valueView.setText(param.getDisplayValue());
// attach listeners
view.setOnClickListener(paramTag);
valueView.addTextChangedListener(paramTag);
valueView.setOnFocusChangeListener(paramTag);
return view;
}
public void updateParameters(Map<String, Parameter> parameters){
if(parameters == null || parameters.isEmpty())
return;
final int parametersCount = getCount();
for(int i = 0; i < parametersCount; i++){
ParamsAdapterItem item = getItem(i);
Parameter update = parameters.remove(item.getParameter().getName());
if(update != null){
boolean dirtyValue = item.isDirty();
item.setDirtyValue(update.getDisplayValue());
if(dirtyValue && !item.isDirty()){
dirtyCount--;
}else if(!dirtyValue && item.isDirty()){
dirtyCount++;
}
}
}
if(!parameters.isEmpty()){
for(Map.Entry<String, Parameter> entry : parameters.entrySet()){
addParameter(entry.getKey(), entry.getValue(), true);
}
}
notifyDataSetChanged();
if(onParametersChangeListener != null) {
onParametersChangeListener.onParametersChange(dirtyCount);
}
}
public void loadParameters(Map<String, Parameter> parameters) {
clear();
for (Map.Entry<String, Parameter> entry : parameters.entrySet()) {
addParameter(entry.getKey(), entry.getValue());
}
dirtyCount = 0;
if(onParametersChangeListener != null) {
onParametersChangeListener.onParametersChange(dirtyCount);
}
}
private void addParameter(String name, Parameter parameter) {
addParameter(name, parameter, false);
}
private void addParameter(String name, Parameter parameter, boolean isDirty){
try {
if(isDirty){
dirtyCount++;
}
ParamsAdapterItem item = new ParamsAdapterItem(parameter);
item.setDirtyValue(parameter.getDisplayValue(), isDirty);
add(item);
} catch (Exception ex) {
// eat it
}
}
private String getDescription(Parameter parameter) {
String desc = "";
if (parameter != null) {
// display-name (units)
desc = parameter.getDisplayName();
if (parameter.getUnits() != null)
desc += " (" + parameter.getUnits() + ")";
}
return desc;
}
private void clearFocus(View view) {
if (view != null) {
view.clearFocus();
final InputMethodManager inputMethodManager = (InputMethodManager) getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
private class ParamTag implements TextWatcher, View.OnFocusChangeListener, View.OnClickListener {
private int position;
private TextView nameView;
private TextView descView;
private EditText valueView;
private View containerView;
public void setPosition(int position) {
this.position = position;
}
public TextView getNameView() {
return nameView;
}
public void setNameView(TextView nameView) {
this.nameView = nameView;
}
public TextView getDescView() {
return descView;
}
public void setDescView(TextView descView) {
this.descView = descView;
}
public EditText getValueView() {
return valueView;
}
public void setValueView(EditText valueView) {
this.valueView = valueView;
}
public double getValue() {
try {
return formatter.parse(valueView.getText().toString()).doubleValue();
} catch (ParseException ex) {
// invalid number, return 0
return 0;
}
}
public void setAppearance(ParamsAdapterItem item) {
final int resid;
if (item.isDirty()) {
final ParamsAdapterItem.Validation validation = item.getValidation();
switch (validation) {
case VALID:
resid = R.style.paramValueValid;
break;
case INVALID:
resid = R.style.paramValueInvalid;
break;
default:
resid = R.style.paramValueChanged;
break;
}
containerView.setBackgroundResource(R.drawable.dirty_params_row_bg);
} else {
containerView.setBackgroundResource(R.drawable.params_row_bg);
resid = R.style.paramValueUnchanged;
}
valueView.setTextAppearance(getContext(), resid);
}
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
// nop
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
// nop
}
@Override
public void afterTextChanged(Editable editable) {
// During reload text may change as valueView looses focus
// after underlying data has been invalidated - avoid this
if (position >= getCount())
return;
final ParamsAdapterItem item = getItem(position);
boolean dirtyValue = item.isDirty();
item.setDirtyValue(editable.toString());
if(dirtyValue && !item.isDirty()){
dirtyCount--;
}else if(!dirtyValue && item.isDirty()){
dirtyCount++;
}
if(onParametersChangeListener != null) {
onParametersChangeListener.onParametersChange(dirtyCount);
}
setAppearance(item);
}
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (!hasFocus) {
// refresh value on leaving view - show results of rounding etc.
focusView = null;
} else {
focusView = view;
}
}
@Override
public void onClick(View view) {
clearFocus();
if (onInfoListener != null)
onInfoListener.onHelp(position, valueView);
}
public void setContainerView(View view) {
containerView = view;
}
}
}