Merge branch 'dev-exponent-in-vars'
This commit is contained in:
commit
19cb4d18d5
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -65,18 +65,36 @@
|
||||
tools:ignore="UnusedAttribute" />
|
||||
</FrameLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
a:id="@+id/variable_value_label"
|
||||
<FrameLayout
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content">
|
||||
|
||||
<org.solovyev.android.calculator.view.EditTextCompat
|
||||
a:id="@+id/variable_value"
|
||||
<android.support.design.widget.TextInputLayout
|
||||
a:id="@+id/variable_value_label"
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
a:id="@+id/variable_value"
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:hint="@string/c_var_value"
|
||||
a:inputType="numberDecimal|numberSigned" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
a:id="@+id/variable_exponent_button"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:hint="@string/c_var_value"
|
||||
a:inputType="numberDecimal|numberSigned" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
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" />
|
||||
</FrameLayout>
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
a:layout_width="match_parent"
|
||||
|
@ -14,6 +14,8 @@
|
||||
<string name="dimensions_y_min" translatable="false">Y min</string>
|
||||
<string name="dimensions_y_max" translatable="false">Y max</string>
|
||||
<string name="cpp_function_body" translatable="false">f(x, y)</string>
|
||||
<string name="cpp_show_greek_keyboard" translatable="false">αβγ</string>
|
||||
<string name="cpp_exponent" translatable="false">E</string>
|
||||
<string-array name="cpp_prefs_precisions" translatable="false">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
|
@ -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.</string>
|
||||
<string name="cpp_purchase_title">Purchase</string>
|
||||
<string name="cpp_show_greek_keyboard" translatable="false">αβγ</string>
|
||||
<string name="cpp_clear_history_title">Clear history?</string>
|
||||
<string name="cpp_clear_history_message">All history will be cleared.</string>
|
||||
<string name="cpp_clear_history">Clear</string>
|
||||
|
Loading…
Reference in New Issue
Block a user