EditFunctionFragment

This commit is contained in:
serso 2016-01-18 14:10:03 +01:00
parent 498b2f5429
commit 58da5a169e
7 changed files with 276 additions and 271 deletions

View File

@ -38,6 +38,7 @@ import android.support.v4.app.FragmentTransaction;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.view.View;
import com.squareup.otto.Bus; import com.squareup.otto.Bus;
@ -56,7 +57,6 @@ import org.solovyev.android.checkout.Products;
import org.solovyev.android.checkout.RobotmediaDatabase; import org.solovyev.android.checkout.RobotmediaDatabase;
import org.solovyev.android.checkout.RobotmediaInventory; import org.solovyev.android.checkout.RobotmediaInventory;
import org.solovyev.android.wizard.Wizards; import org.solovyev.android.wizard.Wizards;
import org.solovyev.common.threads.DelayedExecutor;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -309,4 +309,28 @@ public final class App {
public static Bus getBus() { public static Bus getBus() {
return bus; return bus;
} }
private static final AtomicInteger sNextViewId = new AtomicInteger(1);
public static int generateViewId() {
Check.isMainThread();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
return View.generateViewId();
} else {
// Backwards compatible version, as given by fantouchx@gmail.com in
// http://stackoverflow.com/questions/6790623/#21000252
while (true) {
final int result = sNextViewId.get();
// aapt-generated IDs have the high byte non-zero. Clamp to the
// range below that.
int newValue = result + 1;
if (newValue > 0x00FFFFFF) {
newValue = 1;
}
if (sNextViewId.compareAndSet(result, newValue)) {
return result;
}
}
}
}
} }

View File

@ -7,9 +7,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.TextInputLayout; import android.support.design.widget.TextInputLayout;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager;
import javax.inject.Inject; import javax.inject.Inject;
@ -56,4 +58,13 @@ public abstract class BaseDialogFragment extends DialogFragment {
textInput.setError(null); textInput.setError(null);
textInput.setErrorEnabled(false); textInput.setErrorEnabled(false);
} }
protected final void showIme(@NonNull View view) {
final FragmentActivity activity = getActivity();
if (activity == null) {
return;
}
final InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
} }

View File

@ -37,6 +37,29 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.BaseDialogFragment;
import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorUtils;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
import org.solovyev.android.calculator.math.edit.FunctionsFragment;
import org.solovyev.android.calculator.math.edit.MathEntityRemover;
import org.solovyev.android.calculator.math.edit.VarEditorSaver;
import org.solovyev.android.calculator.model.AFunction;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import butterknife.Bind; import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import jscl.math.Generic; import jscl.math.Generic;
@ -44,18 +67,6 @@ import jscl.math.function.Constant;
import jscl.math.function.CustomFunction; import jscl.math.function.CustomFunction;
import jscl.math.function.Function; import jscl.math.function.Function;
import jscl.math.function.IFunction; import jscl.math.function.IFunction;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
import org.solovyev.android.calculator.math.edit.FunctionsFragment;
import org.solovyev.android.calculator.math.edit.MathEntityRemover;
import org.solovyev.android.calculator.math.edit.VarEditorSaver;
import org.solovyev.android.calculator.model.AFunction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class EditFunctionFragment extends BaseDialogFragment implements CalculatorEventListener { public class EditFunctionFragment extends BaseDialogFragment implements CalculatorEventListener {
@ -122,8 +133,8 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
dialog.setOnShowListener(new DialogInterface.OnShowListener() { dialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override @Override
public void onShow(DialogInterface d) { public void onShow(DialogInterface d) {
nameView.requestFocus();
nameView.selectAll(); nameView.selectAll();
showIme(nameView);
final Button ok = dialog.getButton(AlertDialog.BUTTON_POSITIVE); final Button ok = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
ok.setOnClickListener(new View.OnClickListener() { ok.setOnClickListener(new View.OnClickListener() {
@ -180,9 +191,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
if (savedInstanceState == null) { if (savedInstanceState == null) {
final List<String> parameterNames = input.getParameterNames(); final List<String> parameterNames = input.getParameterNames();
if (parameterNames != null) { if (parameterNames != null) {
paramsView.init(parameterNames); paramsView.addParams(parameterNames);
} else {
paramsView.init();
} }
nameView.setText(input.getName()); nameView.setText(input.getName());

View File

@ -24,9 +24,7 @@ package org.solovyev.android.calculator.function;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import jscl.CustomFunctionCalculationException;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
import org.solovyev.android.calculator.EntitiesRegistry; import org.solovyev.android.calculator.EntitiesRegistry;
import org.solovyev.android.calculator.FunctionsRegistry; import org.solovyev.android.calculator.FunctionsRegistry;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.Locator;
@ -36,11 +34,16 @@ import org.solovyev.android.calculator.model.AFunction;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.CustomFunctionCalculationException;
import jscl.math.function.Function;
import jscl.math.function.IFunction;
public class FunctionEditorSaver implements View.OnClickListener { public class FunctionEditorSaver implements View.OnClickListener {
@Nonnull @Nonnull
@ -84,7 +87,7 @@ public class FunctionEditorSaver implements View.OnClickListener {
String description = editDescription.getText().toString(); String description = editDescription.getText().toString();
final FunctionParamsView editParams = (FunctionParamsView) root.findViewById(R.id.function_params); final FunctionParamsView editParams = (FunctionParamsView) root.findViewById(R.id.function_params);
List<String> parameterNames = editParams.getParameterNames(); List<String> parameterNames = editParams.getParams();
return EditFunctionFragment.Input.newInstance(function, name, content, description, parameterNames); return EditFunctionFragment.Input.newInstance(function, name, content, description, parameterNames);
} }

View File

@ -25,188 +25,251 @@ package org.solovyev.android.calculator.function;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import jscl.text.MutableInt;
import org.solovyev.android.calculator.R; import org.solovyev.android.Check;
import org.solovyev.android.calculator.App;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import java.util.List; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
public class FunctionParamsView extends LinearLayout { public class FunctionParamsView extends LinearLayout {
private static final String PARAM_TAG_PREFIX = "function_param_"; private static final int PARAM_VIEW_INDEX = 3;
@Nonnull private static final int START_ROW_ID = App.generateViewId();
private final MutableInt paramsCount = new MutableInt(0); private int maxRowId = START_ROW_ID;
@Nonnull
private final List<Integer> paramIds = new ArrayList<Integer>(10);
public FunctionParamsView(Context context) { public FunctionParamsView(Context context) {
super(context); super(context);
init();
} }
public FunctionParamsView(Context context, AttributeSet attrs) { public FunctionParamsView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
init();
} }
@TargetApi(Build.VERSION_CODES.HONEYCOMB) @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public FunctionParamsView(Context context, AttributeSet attrs, int defStyle) { public FunctionParamsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyle); super(context, attrs, defStyleAttr);
init();
} }
public void init() { private void init() {
init(Collections.<String>emptyList()); setOrientation(VERTICAL);
} final Context context = getContext();
public void init(@Nonnull List<String> parameters) { final LinearLayout headerView = makeRowView(context);
this.setOrientation(VERTICAL); final Button addButton = new Button(context);
addButton.setText("+");
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); addButton.setOnClickListener(new View.OnClickListener() {
final View addParamView = inflater.inflate(R.layout.function_add_param, null);
final View addParamButton = addParamView.findViewById(R.id.function_add_param_button);
addParamButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
addParam(null); addParam(null);
} }
}); });
headerView.addView(addButton, new LayoutParams(0, WRAP_CONTENT, 1));
this.addView(addParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); headerView.addView(new View(context), new LayoutParams(0, WRAP_CONTENT, 5));
addView(headerView, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
for (String parameter : parameters) {
addParam(parameter);
}
}
public void addParam(@Nullable String name) {
synchronized (paramsCount) {
final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final Integer id = paramsCount.intValue();
final View editParamView = inflater.inflate(R.layout.fragment_function_edit_param, null);
editParamView.setTag(getParamTag(id));
final EditText paramNameEditText = (EditText) editParamView.findViewById(R.id.function_param_edit_text);
paramNameEditText.setText(name);
final View removeParamButton = editParamView.findViewById(R.id.function_remove_param_button);
removeParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
removeParam(id);
}
});
final View upParamButton = editParamView.findViewById(R.id.function_up_param_button);
upParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upParam(id);
}
});
final View downParamButton = editParamView.findViewById(R.id.function_down_param_button);
downParamButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
downParam(id);
}
});
this.addView(editParamView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
paramIds.add(id);
paramsCount.increment();
}
}
private void downParam(@Nonnull Integer id) {
synchronized (paramsCount) {
int index = paramIds.indexOf(id);
if (index < paramIds.size() - 1) {
swap(index, index + 1);
}
}
}
private void upParam(@Nonnull Integer id) {
synchronized (paramsCount) {
int index = paramIds.indexOf(id);
if (index > 0) {
swap(index, index - 1);
}
}
}
private void swap(int index1, int index2) {
final View editParamView1 = getParamView(paramIds.get(index1));
final View editParamView2 = getParamView(paramIds.get(index2));
if (editParamView1 != null && editParamView2 != null) {
final EditText paramNameEditText1 = (EditText) editParamView1.findViewById(R.id.function_param_edit_text);
final EditText paramNameEditText2 = (EditText) editParamView2.findViewById(R.id.function_param_edit_text);
swap(paramNameEditText1, paramNameEditText2);
}
}
private void swap(@Nonnull TextView first,
@Nonnull TextView second) {
final CharSequence tmp = first.getText();
first.setText(second.getText());
second.setText(tmp);
}
@Nullable
private View getParamView(@Nonnull Integer id) {
final String tag = getParamTag(id);
return this.findViewWithTag(tag);
} }
@Nonnull @Nonnull
private String getParamTag(@Nonnull Integer index) { private LinearLayout makeRowView(@Nonnull Context context) {
return PARAM_TAG_PREFIX + index; final LinearLayout rowView = new LinearLayout(context);
rowView.setOrientation(HORIZONTAL);
return rowView;
} }
public void removeParam(@Nonnull Integer id) {
synchronized (paramsCount) { public void addParams(@Nonnull List<String> params) {
if (paramIds.contains(id)) { for (String param : params) {
final View editParamView = getParamView(id); addParam(param);
if (editParamView != null) {
this.removeView(editParamView);
paramIds.remove(id);
} }
} }
public void addParam(@Nullable String param) {
addParam(param, maxRowId++);
} }
private void addParam(@Nullable String param, final int id) {
final Context context = getContext();
final LinearLayout rowView = makeRowView(context);
final Button removeButton = new Button(context);
removeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
removeRow(rowView);
}
});
removeButton.setText("");
rowView.addView(removeButton, new LayoutParams(0, WRAP_CONTENT, 1));
final Button upButton = new Button(context);
upButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
upRow(rowView);
}
});
upButton.setText("");
rowView.addView(upButton, new LayoutParams(0, WRAP_CONTENT, 1));
final Button downButton = new Button(context);
downButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
downRow(rowView);
}
});
downButton.setText("");
rowView.addView(downButton, new LayoutParams(0, WRAP_CONTENT, 1));
final EditText paramView = new EditText(context);
if (param != null) {
paramView.setText(param);
}
paramView.setInputType(EditorInfo.TYPE_CLASS_TEXT);
paramView.setId(id);
rowView.addView(paramView, new LayoutParams(0, WRAP_CONTENT, 3));
addView(rowView, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
}
private void downRow(@Nonnull ViewGroup row) {
final int index = indexOfChild(row);
if (index < getChildCount() - 1) {
swap(row, getRowByIndex(index + 1));
}
}
private void upRow(@Nonnull ViewGroup row) {
final int index = indexOfChild(row);
if (index > 1) {
swap(row, getRowByIndex(index - 1));
}
}
private void swap(@Nonnull ViewGroup l, @Nonnull ViewGroup r) {
final EditText lParam = (EditText) l.getChildAt(PARAM_VIEW_INDEX);
final EditText rParam = (EditText) r.getChildAt(PARAM_VIEW_INDEX);
swap(lParam, rParam);
}
private void swap(@Nonnull TextView l,
@Nonnull TextView r) {
final CharSequence tmp = l.getText();
l.setText(r.getText());
r.setText(tmp);
} }
@Nonnull @Nonnull
public List<String> getParameterNames() { private ViewGroup getRowByIndex(int index) {
synchronized (paramsCount) { Check.isTrue(index >= 0 && index < getChildCount());
final List<String> result = new ArrayList<String>(paramsCount.intValue()); return (ViewGroup) getChildAt(index);
for (Integer id : paramIds) {
final View paramView = getParamView(id);
if (paramView != null) {
final EditText paramNameEditText = (EditText) paramView.findViewById(R.id.function_param_edit_text);
result.add(paramNameEditText.getText().toString());
}
} }
return result; public void removeRow(@Nonnull ViewGroup row) {
} removeView(row);
} }
@Nonnull
public List<String> getParams() {
final List<String> params = new ArrayList<>(getChildCount());
for (int i = 1; i < getChildCount(); i++) {
final ViewGroup row = getRowByIndex(i);
final EditText paramView = (EditText) row.getChildAt(PARAM_VIEW_INDEX);
params.add(paramView.getText().toString());
}
return params;
}
@Override
protected Parcelable onSaveInstanceState() {
final Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState, getRowIds());
}
@Nonnull
private int[] getRowIds() {
final int childCount = getChildCount();
final int[] rowIds = new int[childCount - 1];
for (int i = 1; i < childCount; i++) {
final ViewGroup row = getRowByIndex(i);
final EditText paramView = (EditText) row.getChildAt(PARAM_VIEW_INDEX);
rowIds[i - 1] = paramView.getId();
}
return rowIds;
}
@Override
protected void onRestoreInstanceState(Parcelable in) {
if (!(in instanceof SavedState)) {
super.onRestoreInstanceState(in);
return;
}
final SavedState state = (SavedState) in;
for (int i = 0; i < state.rowIds.length; i++) {
final int rowId = state.rowIds[i];
addParam(null, rowId);
maxRowId = Math.max(maxRowId, rowId + 1);
}
super.onRestoreInstanceState(state.getSuperState());
}
public static final class SavedState extends BaseSavedState {
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(@Nonnull Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
private int[] rowIds;
public SavedState(@Nonnull Parcelable superState, int[] rowIds) {
super(superState);
this.rowIds = rowIds;
}
public SavedState(@Nonnull Parcel in) {
super(in);
rowIds = in.createIntArray();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeIntArray(rowIds);
}
}
} }

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
a:layout_width="match_parent"
a:layout_height="wrap_content"
a:orientation="horizontal">
<Button
a:id="@+id/function_remove_param_button"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="1"
a:text=""
tools:ignore="HardcodedText" />
<Button
a:id="@+id/function_up_param_button"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="1"
a:text="↑"
tools:ignore="HardcodedText" />
<Button
a:id="@+id/function_down_param_button"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="1"
a:text="↓"
tools:ignore="HardcodedText" />
<org.solovyev.android.calculator.function.FunctionParamEditText
a:id="@+id/function_param_edit_text"
style="@style/cpp_default_text_size"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="3"
a:inputType="text" />
</LinearLayout>

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_width="match_parent"
a:layout_height="wrap_content"
a:orientation="horizontal">
<Button
a:id="@+id/function_add_param_button"
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="1"
a:text="+" />
<TextView
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="5" />
</LinearLayout>