diff --git a/app/src/main/java/org/solovyev/android/calculator/EditorView.java b/app/src/main/java/org/solovyev/android/calculator/EditorView.java
index 685eabef..2f928218 100644
--- a/app/src/main/java/org/solovyev/android/calculator/EditorView.java
+++ b/app/src/main/java/org/solovyev/android/calculator/EditorView.java
@@ -22,14 +22,11 @@
package org.solovyev.android.calculator;
-import android.annotation.TargetApi;
import android.content.Context;
-import android.os.Build;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.ContextMenu;
-
import org.solovyev.android.Check;
import org.solovyev.android.calculator.view.EditTextCompat;
import org.solovyev.android.views.Adjuster;
@@ -58,12 +55,6 @@ public class EditorView extends EditTextCompat {
init();
}
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public EditorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- init();
- }
-
private void init() {
if (!App.isFloatingCalculator(getContext())) {
Adjuster.adjustText(this, 0.22f,
diff --git a/app/src/main/java/org/solovyev/android/calculator/variables/EditVariableFragment.java b/app/src/main/java/org/solovyev/android/calculator/variables/EditVariableFragment.java
index 79c4e738..6170e276 100644
--- a/app/src/main/java/org/solovyev/android/calculator/variables/EditVariableFragment.java
+++ b/app/src/main/java/org/solovyev/android/calculator/variables/EditVariableFragment.java
@@ -34,6 +34,9 @@ import android.support.design.widget.TextInputLayout;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.SpannableStringBuilder;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,12 +51,12 @@ import dagger.Lazy;
import jscl.math.function.IConstant;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.*;
-import org.solovyev.android.calculator.RemovalConfirmationDialog;
import org.solovyev.android.calculator.functions.FunctionsRegistry;
import org.solovyev.android.calculator.keyboard.FloatingKeyboard;
import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.view.EditTextCompat;
+import org.solovyev.android.text.method.NumberInputFilter;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
@@ -87,6 +90,8 @@ public class EditVariableFragment extends BaseDialogFragment implements View.OnF
TextInputLayout valueLabel;
@Bind(R.id.variable_value)
EditText valueView;
+ @Bind(R.id.variable_exponent_button)
+ Button exponentButton;
@Bind(R.id.variable_description)
EditText descriptionView;
@Inject
@@ -304,6 +309,13 @@ public class EditVariableFragment extends BaseDialogFragment implements View.OnF
nameView.setOnFocusChangeListener(this);
nameView.setOnKeyListener(this);
valueView.setOnFocusChangeListener(this);
+ valueView.setEditableFactory(new Editable.Factory() {
+ @Override
+ public Editable newEditable(CharSequence source) {
+ return new NumberEditable(source);
+ }
+ });
+ exponentButton.setOnClickListener(this);
descriptionView.setOnFocusChangeListener(this);
keyboardButton.setOnClickListener(this);
@@ -352,6 +364,11 @@ public class EditVariableFragment extends BaseDialogFragment implements View.OnF
showKeyboard();
}
break;
+ case R.id.variable_exponent_button:
+ final int start = Math.max(valueView.getSelectionStart(), 0);
+ final int end = Math.max(valueView.getSelectionEnd(), 0);
+ valueView.getText().replace(Math.min(start, end), Math.max(start, end), "E", 0, 1);
+ break;
default:
super.onClick(v);
break;
@@ -379,6 +396,18 @@ public class EditVariableFragment extends BaseDialogFragment implements View.OnF
keyboardWindow.show(new GreekFloatingKeyboard(keyboardUser), getDialog());
}
+ private static class NumberEditable extends SpannableStringBuilder {
+ public NumberEditable(CharSequence source) {
+ super(source);
+ super.setFilters(new InputFilter[]{NumberInputFilter.getInstance()});
+ }
+
+ @Override
+ public void setFilters(InputFilter[] filters) {
+ // we don't want filters as we want to support numbers in scientific notation
+ }
+ }
+
private class KeyboardUser implements FloatingKeyboard.User {
@NonNull
@Override
diff --git a/app/src/main/java/org/solovyev/android/calculator/view/EditTextCompat.java b/app/src/main/java/org/solovyev/android/calculator/view/EditTextCompat.java
index 79f393b6..81a52e2a 100644
--- a/app/src/main/java/org/solovyev/android/calculator/view/EditTextCompat.java
+++ b/app/src/main/java/org/solovyev/android/calculator/view/EditTextCompat.java
@@ -1,8 +1,8 @@
package org.solovyev.android.calculator.view;
-import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
+import android.support.design.widget.TextInputEditText;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.Log;
@@ -12,7 +12,7 @@ import org.solovyev.android.Check;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
-public class EditTextCompat extends EditText {
+public class EditTextCompat extends TextInputEditText {
@Nullable
private static Method setShowSoftInputOnFocusMethod;
@@ -30,11 +30,6 @@ public class EditTextCompat extends EditText {
super(context, attrs, defStyleAttr);
}
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- public EditTextCompat(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
public void dontShowSoftInputOnFocusCompat() {
setShowSoftInputOnFocusCompat(false);
}
diff --git a/app/src/main/java/org/solovyev/android/text/method/NumberInputFilter.java b/app/src/main/java/org/solovyev/android/text/method/NumberInputFilter.java
new file mode 100644
index 00000000..5600c096
--- /dev/null
+++ b/app/src/main/java/org/solovyev/android/text/method/NumberInputFilter.java
@@ -0,0 +1,176 @@
+package org.solovyev.android.text.method;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.InputFilter;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+
+public class NumberInputFilter implements InputFilter {
+
+ private static final int[] CHARS = new int[]{-1, -1, -1};
+ private static final int CHAR_SIGN = 0;
+ private static final int CHAR_POINT = 1;
+ private static final int CHAR_EXP = 2;
+
+ private static final char[] ACCEPTED = {'E', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+', '.'};
+ private static final NumberInputFilter INSTANCE = new NumberInputFilter();
+
+ private static boolean isSignChar(final char c) {
+ return c == '-' || c == '+';
+ }
+
+ private static boolean isDecimalPointChar(final char c) {
+ return c == '.';
+ }
+
+ private static boolean isExponentChar(final char c) {
+ return c == 'E';
+ }
+
+ /**
+ * Returns a NumberInputFilter that accepts the digits 0 through 9.
+ */
+ public static NumberInputFilter getInstance() {
+ return INSTANCE;
+ }
+
+ private static boolean accepted(char c) {
+ for (int i = ACCEPTED.length - 1; i >= 0; i--) {
+ if (ACCEPTED[i] == c) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public CharSequence filter(CharSequence source, int start, int end,
+ Spanned dest, int dstart, int dend) {
+ final CharSequence out = filterIllegalCharacters(source, start, end);
+ if (out != null) {
+ source = out;
+ start = 0;
+ end = out.length();
+ }
+
+ CHARS[CHAR_SIGN] = -1;
+ CHARS[CHAR_POINT] = -1;
+ CHARS[CHAR_EXP] = -1;
+ findChars(dest, 0, dstart, 0, CHARS);
+ findChars(dest, dend, dest.length(), end - start, CHARS);
+
+ SpannableStringBuilder filtered = null;
+ for (int i = end - 1; i >= start; i--) {
+ final char c = source.charAt(i);
+
+ boolean filter = false;
+ if (isSignChar(c)) {
+ if (i == start && dstart == 0) {
+ if (CHARS[CHAR_SIGN] >= 0) {
+ filter = true;
+ } else {
+ CHARS[CHAR_SIGN] = i + dstart;
+ }
+ } else if (CHARS[CHAR_EXP] == i + dstart - 1) {
+ // allow sign after exponent symbol
+ filter = false;
+ } else {
+ filter = true;
+ }
+ } else if (isDecimalPointChar(c)) {
+ if (CHARS[CHAR_POINT] >= 0) {
+ filter = true;
+ } else if (CHARS[CHAR_EXP] >= 0 && CHARS[CHAR_EXP] < i + dstart) {
+ // no decimal point after exponent
+ filter = true;
+ } else {
+ CHARS[CHAR_POINT] = i + dstart;
+ }
+ } else if (isExponentChar(c)) {
+ if (CHARS[CHAR_EXP] >= 0) {
+ filter = true;
+ } else if (CHARS[CHAR_POINT] >= 0 && CHARS[CHAR_POINT] > i + dstart) {
+ // no exponent before decimal point
+ filter = true;
+ } else {
+ CHARS[CHAR_EXP] = i + dstart;
+ }
+ }
+
+ if (filter) {
+ if (end == start + 1) {
+ return ""; // Only one character, and it was stripped.
+ }
+
+ if (filtered == null) {
+ filtered = new SpannableStringBuilder(source, start, end);
+ }
+
+ filtered.delete(i - start, i + 1 - start);
+ }
+ }
+
+ if (filtered != null) {
+ return filtered;
+ } else if (out != null) {
+ return out;
+ } else {
+ return null;
+ }
+ }
+
+ private void findChars(@NonNull Spanned s, int start, int end, int offset, int[] out) {
+ for (int i = start; i < end; i++) {
+ final char c = s.charAt(i);
+
+ if (isSignChar(c)) {
+ if (out[CHAR_SIGN] == -1 && out[CHAR_EXP] == -1) {
+ // count in only signs before exponent
+ out[CHAR_SIGN] = i + offset;
+ }
+ } else if (isDecimalPointChar(c)) {
+ if (out[CHAR_POINT] == -1) {
+ out[CHAR_POINT] = i + offset;
+ }
+ } else if (isExponentChar(c)) {
+ if (out[CHAR_EXP] == -1) {
+ out[CHAR_EXP] = i + offset;
+ }
+ }
+ }
+ }
+
+ @Nullable
+ private CharSequence filterIllegalCharacters(CharSequence source, int start, int end) {
+ final int illegal = findIllegalChar(source, start, end);
+ if (illegal == end) {
+ // all OK
+ return null;
+ }
+ if (end - start == 1) {
+ // it was not OK, and there is only one char, so nothing remains.
+ return "";
+ }
+
+ final SpannableStringBuilder filtered = new SpannableStringBuilder(source, start, end);
+ final int newEnd = end - start - 1;
+ // only count down to "illegal" because the chars before that were all OK.
+ final int newIllegal = illegal - start;
+ for (int j = newEnd; j >= newIllegal; j--) {
+ if (!accepted(source.charAt(j))) {
+ filtered.delete(j, j + 1);
+ }
+ }
+ return filtered;
+ }
+
+ private int findIllegalChar(CharSequence s, int start, int end) {
+ for (int i = start; i < end; i++) {
+ if (!accepted(s.charAt(i))) {
+ return i;
+ }
+ }
+ return end;
+ }
+}
diff --git a/app/src/main/res/layout/fragment_variable_edit.xml b/app/src/main/res/layout/fragment_variable_edit.xml
index 7c39891e..26b9ce45 100644
--- a/app/src/main/res/layout/fragment_variable_edit.xml
+++ b/app/src/main/res/layout/fragment_variable_edit.xml
@@ -65,18 +65,36 @@
tools:ignore="UnusedAttribute" />
-
-
+
+
+
+
+
-
+ a:layout_gravity="end|top"
+ a:background="?attr/selectableItemBackgroundBorderless"
+ a:minWidth="0dp"
+ a:padding="@dimen/cpp_image_button_padding"
+ a:text="@string/cpp_exponent"
+ a:textAllCaps="false"
+ a:textAppearance="?android:attr/textAppearanceSmall"
+ tools:ignore="UnusedAttribute" />
+
Y min
Y max
f(x, y)
+ αβγ
+ E
- 0
- 1
diff --git a/app/src/main/res/values/text_strings.xml b/app/src/main/res/values/text_strings.xml
index 27f9623d..45c92675 100644
--- a/app/src/main/res/values/text_strings.xml
+++ b/app/src/main/res/values/text_strings.xml
@@ -115,7 +115,6 @@
several devices.\n\n
By clicking \'Continue\' button you will be redirected to the Google Play app to make the payment.
Purchase
- αβγ
Clear history?
All history will be cleared.
Clear