diff --git a/app/src/androidTest/java/org/solovyev/android/calculator/plot/BasePlotTest.java b/app/src/androidTest/java/org/solovyev/android/calculator/plot/BasePlotTest.java new file mode 100644 index 00000000..08da0fec --- /dev/null +++ b/app/src/androidTest/java/org/solovyev/android/calculator/plot/BasePlotTest.java @@ -0,0 +1,58 @@ +package org.solovyev.android.calculator.plot; + +import android.support.annotation.NonNull; +import android.support.test.espresso.action.ViewActions; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.LargeTest; +import android.text.TextUtils; + +import org.hamcrest.Matchers; +import org.junit.Rule; +import org.junit.runner.RunWith; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.functions.CppFunction; +import org.solovyev.android.calculator.functions.FunctionParamsView; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.action.ViewActions.typeText; +import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView; +import static android.support.test.espresso.matcher.ViewMatchers.hasFocus; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withTagValue; +import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static org.hamcrest.Matchers.allOf; + +@RunWith(AndroidJUnit4.class) +@LargeTest +public class BasePlotTest { + @Rule + public ActivityTestRule rule = new ActivityTestRule<>(PlotActivity.class); + + protected void addFunction(@NonNull CppFunction function) { + openFunctionEditor(); + + if (!TextUtils.isEmpty(function.getName())) { + onView(withId(R.id.function_name)).perform(typeText(function.getName())); + } + + for (String parameter : function.getParameters()) { + onView(withId(R.id.function_params_add)).perform(click()); + onView(allOf(hasFocus(), withTagValue(Matchers.equalTo(FunctionParamsView.PARAM_VIEW_TAG)))).perform(click(), typeTextIntoFocusedView(parameter)); + } + + onView(withId(R.id.function_body)).perform(typeText(function.getBody())); + onView(withText(R.string.ok)).perform(click()); + } + + protected final void openFunctionEditor() { + onView(withId(R.id.plot_view_frame)).perform(ViewActions.click()); + onView(withId(R.id.plot_add_function)).perform(click()); + } + + protected final void openFunctionsList() { + onView(withId(R.id.plot_view_frame)).perform(ViewActions.click()); + onView(withId(R.id.plot_functions)).perform(click()); + } +} diff --git a/app/src/androidTest/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragmentTest.java b/app/src/androidTest/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragmentTest.java new file mode 100644 index 00000000..235dcdde --- /dev/null +++ b/app/src/androidTest/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragmentTest.java @@ -0,0 +1,22 @@ +package org.solovyev.android.calculator.plot; + +import org.junit.Test; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.functions.CppFunction; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +public class PlotEditFunctionFragmentTest extends BasePlotTest { + + @Test + public void testShouldAddFunction() throws Exception { + final CppFunction function = CppFunction.builder("", "x + y").withParameters("x", "y").build(); + addFunction(function); + + openFunctionsList(); + onView(withId(R.id.function_name)).check(matches(withText("x+y"))); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index de3810c4..956baf42 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -119,7 +119,11 @@ + android:label="@string/cpp_plotter"> + + + + JSON_CREATOR = new Json.Creator() { @@ -230,6 +235,13 @@ public class CppFunction implements Jsonable, Parcelable { return this; } + @Nonnull + public Builder withParameters(@Nonnull String... parameters) { + Check.isTrue(!built); + function.parameters.addAll(asList(parameters)); + return this; + } + @Nonnull public Builder withParameter(@Nonnull String parameter) { Check.isTrue(!built); diff --git a/app/src/main/java/org/solovyev/android/calculator/functions/FunctionParamsView.java b/app/src/main/java/org/solovyev/android/calculator/functions/FunctionParamsView.java index 06f72323..7177b416 100644 --- a/app/src/main/java/org/solovyev/android/calculator/functions/FunctionParamsView.java +++ b/app/src/main/java/org/solovyev/android/calculator/functions/FunctionParamsView.java @@ -36,17 +36,23 @@ import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.widget.*; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + import org.solovyev.android.Check; import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.R; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -63,6 +69,9 @@ public class FunctionParamsView extends LinearLayout { @Nonnull private final Preferences.Gui.Theme theme = App.getTheme(); private int maxRowId = START_ROW_ID; + private int maxParams = Integer.MAX_VALUE; + @Nonnull + private LinearLayout headerView; { final Resources resources = getResources(); @@ -91,8 +100,9 @@ public class FunctionParamsView extends LinearLayout { setOrientation(VERTICAL); final Context context = getContext(); - final LinearLayout headerView = makeRowView(context); + headerView = makeRowView(context); final ImageButton addButton = makeButton(theme.light ? R.drawable.ic_add_black_24dp : R.drawable.ic_add_white_24dp); + addButton.setId(R.id.function_params_add); addButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -187,9 +197,15 @@ public class FunctionParamsView extends LinearLayout { // for row is added at 0 position, the consequent rows addView(rowView, Math.max(0, getChildCount() - 1), new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + onParamsChanged(); return rowView; } + private void onParamsChanged() { + final boolean enabled = getParamsCount() < maxParams; + headerView.setVisibility(enabled ? VISIBLE : GONE); + } + @NonNull private LayoutParams makeButtonParams() { return new LayoutParams(imageButtonSize, imageButtonSize); @@ -224,19 +240,20 @@ public class FunctionParamsView extends LinearLayout { @Nonnull private ViewGroup getRow(int index) { - Check.isTrue(index >= 0 && index < getChildCount() - FOOTERS); + Check.isTrue(index >= 0 && index < getParamsCount()); return (ViewGroup) getChildAt(index); } public void removeRow(@Nonnull ViewGroup row) { removeView(row); + onParamsChanged(); } @Nonnull public List getParams() { - final List params = new ArrayList<>(getChildCount()); + final List params = new ArrayList<>(getParamsCount()); - for (int i = 0; i < getChildCount() - FOOTERS; i++) { + for (int i = 0; i < getParamsCount(); i++) { final ViewGroup row = getRow(i); final EditText paramView = getParamView(row); params.add(paramView.getText().toString()); @@ -245,6 +262,15 @@ public class FunctionParamsView extends LinearLayout { return params; } + private int getParamsCount() { + return getChildCount() - FOOTERS; + } + + public void setMaxParams(int maxParams) { + this.maxParams = maxParams; + onParamsChanged(); + } + @Nonnull private EditText getParamView(@Nonnull ViewGroup row) { final TextInputLayout paramLabel = getParamLabel(row); diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/PlotActivity.java b/app/src/main/java/org/solovyev/android/calculator/plot/PlotActivity.java index 8a226369..186893ce 100644 --- a/app/src/main/java/org/solovyev/android/calculator/plot/PlotActivity.java +++ b/app/src/main/java/org/solovyev/android/calculator/plot/PlotActivity.java @@ -16,12 +16,12 @@ import org.solovyev.android.plotter.Dimensions; import org.solovyev.android.plotter.PlotViewFrame; import org.solovyev.android.plotter.Plotter; -import butterknife.Bind; -import butterknife.ButterKnife; - import javax.annotation.Nonnull; import javax.inject.Inject; +import butterknife.Bind; +import butterknife.ButterKnife; + public class PlotActivity extends BaseActivity { public static class MyFragment extends BaseFragment implements PlotViewFrame.Listener { @@ -79,7 +79,7 @@ public class PlotActivity extends BaseActivity { PlotFunctionsFragment.show(getActivity().getSupportFragmentManager()); return true; } else if (id == R.id.plot_add_function) { - //App.getBus().post(new AddFunctionDialog.ShowEvent()); + PlotEditFunctionFragment.show(null, getActivity().getSupportFragmentManager()); return true; } return false; diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragment.java b/app/src/main/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragment.java index 66984f86..b5169efa 100644 --- a/app/src/main/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/plot/PlotEditFunctionFragment.java @@ -111,6 +111,7 @@ public class PlotEditFunctionFragment extends BaseFunctionFragment final int[] colors = MeshSpec.LightColors.asIntArray(); colorPicker.setColors(colors); + paramsView.setMaxParams(2); if (savedInstanceState == null) { if (plotFunction != null) { setupViews(plotFunction.meshSpec); diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java b/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java index 30157d33..209b55e2 100644 --- a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java @@ -1,8 +1,5 @@ package org.solovyev.android.calculator.plot; -import static android.support.v7.widget.LinearLayoutManager.VERTICAL; -import static android.view.Menu.NONE; - import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; @@ -32,14 +29,17 @@ import org.solovyev.android.plotter.Plotter; import org.solovyev.android.views.llm.DividerItemDecoration; import org.solovyev.android.views.llm.LinearLayoutManager; -import butterknife.Bind; -import butterknife.ButterKnife; - import java.util.List; import javax.annotation.Nonnull; import javax.inject.Inject; +import butterknife.Bind; +import butterknife.ButterKnife; + +import static android.support.v7.widget.LinearLayoutManager.VERTICAL; +import static android.view.Menu.NONE; + public class PlotFunctionsFragment extends BaseDialogFragment { @Inject @@ -120,7 +120,7 @@ public class PlotFunctionsFragment extends BaseDialogFragment { @Bind(R.id.function_icon) PlotIconView icon; - @Bind(R.id.fn_name_edittext) + @Bind(R.id.function_name) TextView name; private PlotFunction function; diff --git a/app/src/main/res/layout/dialog_functions_function.xml b/app/src/main/res/layout/dialog_functions_function.xml index 5285b60c..963ef3dd 100644 --- a/app/src/main/res/layout/dialog_functions_function.xml +++ b/app/src/main/res/layout/dialog_functions_function.xml @@ -16,7 +16,7 @@ android:layout_height="match_parent" /> + + \ No newline at end of file