package org.azavea.otm.fields; import android.app.Activity; import android.content.Intent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import com.google.common.base.Joiner; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Ordering; import com.google.common.primitives.Doubles; import org.azavea.otm.App; import org.azavea.otm.R; import org.azavea.otm.data.Plot; import org.azavea.otm.data.UDFCollectionDefinition; import org.azavea.otm.fields.FieldGroup.DisplayMode; import org.azavea.otm.ui.TreeEditDisplay; import org.azavea.otm.ui.UDFCollectionEditActivity; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.collect.Lists.newArrayList; import static org.azavea.helpers.DateButtonListener.formatTimestampForDisplay; public class UDFCollectionValueField extends Field implements Comparable<UDFCollectionValueField> { private static final int DEFAULT_DIGITS = 2; private static final AtomicInteger seq = new AtomicInteger(0); // Every UDF needs a unique tag, so that edits can be associated with the correct UDF // This tag is returned by getTag() private final int tag = seq.incrementAndGet(); private final HashMap<String, JSONObject> subFieldDefinitionsByName; private final String sortKey; private final JSONObject value; private final UDFCollectionDefinition udfDef; public UDFCollectionValueField(UDFCollectionDefinition udfDefinition, String sortKey, JSONObject value) { super(udfDefinition.getCollectionKey(), udfDefinition.getLabel()); this.sortKey = sortKey; this.value = value; this.udfDef = udfDefinition; this.subFieldDefinitionsByName = udfDefinition.groupTypesByName(); } @Override public View renderForDisplay(LayoutInflater inflater, Plot plot, Activity activity, ViewGroup parent) throws JSONException { return render(inflater, activity, parent, DisplayMode.VIEW); } @Override public View renderForEdit(LayoutInflater inflater, Plot plot, Activity activity, ViewGroup parent) { return render(inflater, activity, parent, DisplayMode.EDIT); } public View renderForDisplay(LayoutInflater inflater, Activity activity, ViewGroup parent) throws JSONException { return render(inflater, activity, parent, DisplayMode.VIEW); } public View renderForEdit(LayoutInflater inflater, Activity activity, ViewGroup parent) { return render(inflater, activity, parent, DisplayMode.EDIT); } private View render(LayoutInflater inflater, Activity activity, ViewGroup parent, DisplayMode mode) { View container = inflater.inflate(R.layout.collection_udf_element_row, parent, false); TextView labelView = (TextView) container.findViewById(R.id.primary_text); TextView secondaryTextView = (TextView) container.findViewById(R.id.secondary_text); TextView sortTextView = (TextView) container.findViewById(R.id.sort_key_field); labelView.setText(label); List<String> secondaryText = new ArrayList<>(); for (String key : subFieldDefinitionsByName.keySet()) { String formattedValue = formatSubValue(key); if (sortKey.equals(key)) { sortTextView.setText(formattedValue); } else { secondaryText.add(formattedValue); } } secondaryTextView.setText(Joiner.on('\n').join(secondaryText)); View chevron = container.findViewById(R.id.chevron); if (udfDef.isEditable() && mode == DisplayMode.EDIT) { chevron.setVisibility(View.VISIBLE); container.setOnClickListener(v -> { Intent intent = new Intent(activity, UDFCollectionEditActivity.class); // Edit UDF shares code with Create UDF (which handles multiple UDFs), so we pass list of definitions intent.putParcelableArrayListExtra(UDFCollectionEditActivity.UDF_DEFINITIONS, newArrayList(udfDef)); intent.putExtra(UDFCollectionEditActivity.INITIAL_VALUE, value.toString()); intent.putExtra(UDFCollectionEditActivity.TAG, tag); activity.startActivityForResult(intent, TreeEditDisplay.FIELD_ACTIVITY_REQUEST_CODE); }); } return container; } @Override protected Object getEditedValue() { return value; } private String formatSubValue(String key) { Object subValue = value.opt(key); JSONObject typeDef = subFieldDefinitionsByName.get(key); String type = typeDef.optString("type"); if (JSONObject.NULL.equals(subValue)) { return App.getAppInstance().getString(R.string.unspecified_field_value); } else if ("date".equals(type)) { return formatTimestampForDisplay((String) subValue); } else if ("float".equals(type)) { return TextField.formatWithDigits(subValue, DEFAULT_DIGITS); } return String.valueOf(value.opt(key)); } @Override public int compareTo(UDFCollectionValueField another) { String sortKeyType = subFieldDefinitionsByName.get(sortKey).optString("type"); if ("date".equals(sortKeyType)) { // Dates are serialized in ISO format, which allows us to sort them lexicographically return nullToEmpty(another.value.optString(sortKey)).compareTo(nullToEmpty(value.optString(sortKey))); } else if ("choice".equals(sortKey) || "string".equals(sortKey)) { // Natural String sorting return ComparisonChain.start() .compare(this, another, Ordering.natural() .nullsFirst() .reverse() .onResultOf(v -> v.value.optString(sortKey)) ) .result(); } else { return Doubles.compare(another.value.optDouble(sortKey, Double.MIN_VALUE), value.optDouble(sortKey, Double.MIN_VALUE)); } } public int getTag() { return tag; } }