Variable validation
This commit is contained in:
parent
4a9e8bf78a
commit
0170c3bb6a
@ -1,16 +1,16 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import dagger.Component;
|
||||
import org.solovyev.android.calculator.functions.EditFunctionFragment;
|
||||
import org.solovyev.android.calculator.history.BaseHistoryFragment;
|
||||
import org.solovyev.android.calculator.history.EditHistoryFragment;
|
||||
import org.solovyev.android.calculator.math.edit.FunctionsFragment;
|
||||
import org.solovyev.android.calculator.variables.VariablesFragment;
|
||||
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
|
||||
import org.solovyev.android.calculator.variables.EditVariableFragment;
|
||||
import org.solovyev.android.calculator.variables.VariablesFragment;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = AppModule.class)
|
||||
public interface AppComponent {
|
||||
@ -21,6 +21,7 @@ public interface AppComponent {
|
||||
void inject(BaseHistoryFragment fragment);
|
||||
void inject(BaseDialogFragment fragment);
|
||||
void inject(EditFunctionFragment fragment);
|
||||
void inject(EditVariableFragment fragment);
|
||||
void inject(EditHistoryFragment fragment);
|
||||
void inject(FunctionsFragment fragment);
|
||||
void inject(VariablesFragment fragment);
|
||||
|
@ -6,14 +6,13 @@ import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.TextInputLayout;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -62,12 +61,15 @@ public abstract class BaseDialogFragment extends DialogFragment {
|
||||
@NonNull
|
||||
protected abstract View onCreateDialogView(@NonNull Context context, @NonNull LayoutInflater inflater, @Nullable Bundle savedInstanceState);
|
||||
|
||||
protected static void setError(@NonNull TextInputLayout textInput, @NonNull String error) {
|
||||
protected void setError(@NonNull TextInputLayout textInput, @StringRes int error, Object... errorArgs) {
|
||||
setError(textInput, getString(error, errorArgs));
|
||||
}
|
||||
protected void setError(@NonNull TextInputLayout textInput, @NonNull String error) {
|
||||
textInput.setError(error);
|
||||
textInput.setErrorEnabled(true);
|
||||
}
|
||||
|
||||
protected static void clearError(@NonNull TextInputLayout textInput) {
|
||||
protected void clearError(@NonNull TextInputLayout textInput) {
|
||||
textInput.setError(null);
|
||||
textInput.setErrorEnabled(false);
|
||||
}
|
||||
|
@ -23,9 +23,12 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.squareup.otto.Bus;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.JsclMathEngine;
|
||||
import jscl.MathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.operator.Operator;
|
||||
import org.solovyev.android.Check;
|
||||
import org.solovyev.android.calculator.functions.FunctionsRegistry;
|
||||
import org.solovyev.android.prefs.BooleanPreference;
|
||||
@ -36,21 +39,14 @@ import org.solovyev.common.text.EnumMapper;
|
||||
import org.solovyev.common.text.NumberMapper;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import jscl.AngleUnit;
|
||||
import jscl.JsclMathEngine;
|
||||
import jscl.MathEngine;
|
||||
import jscl.NumeralBase;
|
||||
import jscl.math.operator.Operator;
|
||||
|
||||
@Singleton
|
||||
public class Engine implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@ -82,7 +78,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene
|
||||
}
|
||||
|
||||
@Inject
|
||||
public Engine(@Nonnull SharedPreferences preferences, @Nonnull JsclMathEngine mathEngine) {
|
||||
public Engine(@Nonnull JsclMathEngine mathEngine) {
|
||||
this.mathEngine = mathEngine;
|
||||
|
||||
this.mathEngine.setRoundResult(true);
|
||||
|
@ -65,9 +65,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements View.OnC
|
||||
private static final int MENU_CATEGORY = Menu.FIRST + 2;
|
||||
|
||||
@NonNull
|
||||
private final VariablesRegistry constantsRegistry = Locator.getInstance().getEngine().getVariablesRegistry();
|
||||
@NonNull
|
||||
private final FloatingKeyboardWindow keyboardWindow = new FloatingKeyboardWindow();
|
||||
private final FloatingKeyboardWindow keyboardWindow = new FloatingKeyboardWindow(null);
|
||||
@NonNull
|
||||
private final KeyboardUser keyboardUser = new KeyboardUser();
|
||||
@Bind(R.id.function_params)
|
||||
@ -86,6 +84,8 @@ public class EditFunctionFragment extends BaseDialogFragment implements View.OnC
|
||||
Calculator calculator;
|
||||
@Inject
|
||||
FunctionsRegistry functionsRegistry;
|
||||
@Inject
|
||||
VariablesRegistry variablesRegistry;
|
||||
@Nullable
|
||||
private CppFunction function;
|
||||
|
||||
@ -453,7 +453,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements View.OnC
|
||||
final int id = v.getId();
|
||||
if (id == R.id.function_body) {
|
||||
menu.clear();
|
||||
addEntities(menu, getNamesSorted(constantsRegistry), MENU_CONSTANT);
|
||||
addEntities(menu, getNamesSorted(variablesRegistry), MENU_CONSTANT);
|
||||
unregisterForContextMenu(bodyView);
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,18 @@ import org.solovyev.android.calculator.R;
|
||||
|
||||
public class FloatingKeyboardWindow {
|
||||
|
||||
@javax.annotation.Nullable
|
||||
private final PopupWindow.OnDismissListener dismissListener;
|
||||
|
||||
@Nullable
|
||||
private PopupWindow window;
|
||||
@Nullable
|
||||
private Dialog dialog;
|
||||
|
||||
public FloatingKeyboardWindow(@javax.annotation.Nullable PopupWindow.OnDismissListener dismissListener) {
|
||||
this.dismissListener = dismissListener;
|
||||
}
|
||||
|
||||
private static void hideIme(@NonNull View view) {
|
||||
final IBinder token = view.getWindowToken();
|
||||
if (token != null) {
|
||||
@ -67,6 +74,9 @@ public class FloatingKeyboardWindow {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
window = null;
|
||||
if (dismissListener != null) {
|
||||
dismissListener.onDismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
// see http://stackoverflow.com/a/4713487/720489
|
||||
|
@ -31,8 +31,6 @@ 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.TextWatcher;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@ -40,19 +38,24 @@ import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.widget.PopupWindow;
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import jscl.math.function.IConstant;
|
||||
import org.solovyev.android.Activities;
|
||||
import org.solovyev.android.Check;
|
||||
import org.solovyev.android.calculator.*;
|
||||
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.math.edit.VarEditorSaver;
|
||||
import org.solovyev.android.calculator.view.EditTextCompat;
|
||||
import org.solovyev.common.text.Strings;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -61,10 +64,14 @@ import static org.solovyev.android.calculator.functions.CppFunction.NO_ID;
|
||||
public class EditVariableFragment extends BaseDialogFragment implements CalculatorEventListener, View.OnFocusChangeListener, View.OnKeyListener, View.OnClickListener {
|
||||
|
||||
private static final String ARG_VARIABLE = "variable";
|
||||
private final static String greekAlphabet = "αβγδεζηθικλμνξοπρστυφχψω";
|
||||
private final static List<Character> acceptableChars = Arrays.asList(Strings.toObjects(("1234567890abcdefghijklmnopqrstuvwxyzйцукенгшщзхъфывапролджэячсмитьбюё_" + greekAlphabet).toCharArray()));
|
||||
private final static List<Character> ACCEPTABLE_CHARACTERS = Arrays.asList(Strings.toObjects(("1234567890abcdefghijklmnopqrstuvwxyzйцукенгшщзхъфывапролджэячсмитьбюё_" + GreekFloatingKeyboard.ALPHABET).toCharArray()));
|
||||
@NonNull
|
||||
private final FloatingKeyboardWindow keyboardWindow = new FloatingKeyboardWindow();
|
||||
private final FloatingKeyboardWindow keyboardWindow = new FloatingKeyboardWindow(new PopupWindow.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
nameView.setShowSoftInputOnFocusCompat(true);
|
||||
}
|
||||
});
|
||||
@NonNull
|
||||
private final KeyboardUser keyboardUser = new KeyboardUser();
|
||||
@Bind(R.id.variable_name_label)
|
||||
@ -79,6 +86,12 @@ public class EditVariableFragment extends BaseDialogFragment implements Calculat
|
||||
EditText valueView;
|
||||
@Bind(R.id.variable_description)
|
||||
EditText descriptionView;
|
||||
@Inject
|
||||
Calculator calculator;
|
||||
@Inject
|
||||
FunctionsRegistry functionsRegistry;
|
||||
@Inject
|
||||
VariablesRegistry variablesRegistry;
|
||||
@Nullable
|
||||
private CppVariable variable;
|
||||
|
||||
@ -124,6 +137,12 @@ public class EditVariableFragment extends BaseDialogFragment implements Calculat
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void inject(@NonNull AppComponent component) {
|
||||
super.inject(component);
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(@NonNull AlertDialog.Builder builder) {
|
||||
builder.setNegativeButton(R.string.c_cancel, null);
|
||||
@ -189,13 +208,61 @@ public class EditVariableFragment extends BaseDialogFragment implements Calculat
|
||||
}
|
||||
|
||||
private boolean validateValue() {
|
||||
final String value = valueView.getText().toString();
|
||||
if (!Strings.isEmpty(value)) {
|
||||
// value is not empty => must be a number
|
||||
if (!VariablesFragment.isValidValue(value)) {
|
||||
setError(valueLabel, R.string.c_value_is_not_a_number);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
clearError(valueLabel);
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean validateName() {
|
||||
final String name = nameView.getText().toString();
|
||||
if (!VarEditorSaver.isValidName(name)) {
|
||||
setError(nameLabel, getString(R.string.c_name_is_not_valid));
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < name.length(); i++) {
|
||||
final char c = name.charAt(i);
|
||||
if (!ACCEPTABLE_CHARACTERS.contains(Character.toLowerCase(c))) {
|
||||
setError(nameLabel, getString(R.string.c_char_is_not_accepted, c));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
final IConstant existingVariable = variablesRegistry.get(name);
|
||||
if (existingVariable != null) {
|
||||
if (!existingVariable.isIdDefined()) {
|
||||
Check.shouldNotHappen();
|
||||
setError(nameLabel, getString(R.string.c_var_already_exists));
|
||||
return false;
|
||||
}
|
||||
if (isNewVariable()) {
|
||||
// trying to create a new variable with existing name
|
||||
setError(nameLabel, getString(R.string.c_var_already_exists));
|
||||
return false;
|
||||
}
|
||||
Check.isNotNull(variable);
|
||||
if (!existingVariable.getId().equals(variable.id)) {
|
||||
// trying to change the name of existing variable to some other variable's name
|
||||
setError(nameLabel, getString(R.string.c_var_already_exists));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final MathType.Result type = MathType.getType(name, 0, false);
|
||||
if (type.type != MathType.text && type.type != MathType.constant) {
|
||||
setError(nameLabel, getString(R.string.c_var_name_clashes));
|
||||
return false;
|
||||
}
|
||||
|
||||
clearError(nameLabel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
@ -295,28 +362,6 @@ public class EditVariableFragment extends BaseDialogFragment implements Calculat
|
||||
keyboardWindow.show(new GreekFloatingKeyboard(keyboardUser), getDialog());
|
||||
}
|
||||
|
||||
private class NameWatcher implements TextWatcher {
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (!acceptableChars.contains(Character.toLowerCase(c))) {
|
||||
s.delete(i, i + 1);
|
||||
Toast.makeText(getActivity(), String.format(getString(R.string.c_char_is_not_accepted), c), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyboardUser implements FloatingKeyboard.User {
|
||||
@NonNull
|
||||
@Override
|
||||
|
@ -19,7 +19,7 @@ import java.util.Locale;
|
||||
|
||||
|
||||
public class GreekFloatingKeyboard extends BaseFloatingKeyboard implements View.OnClickListener {
|
||||
private final static String GREEK_ALPHABET = "αβγδεζηθικλμνξοπρστυφχψω";
|
||||
final static String ALPHABET = "αβγδεζηθικλμνξοπρστυφχψω";
|
||||
|
||||
public GreekFloatingKeyboard(@NonNull User user) {
|
||||
super(user);
|
||||
@ -41,8 +41,8 @@ public class GreekFloatingKeyboard extends BaseFloatingKeyboard implements View.
|
||||
} else {
|
||||
makeLastColumnLand(rowView, row);
|
||||
}
|
||||
} else if (letter < GREEK_ALPHABET.length()) {
|
||||
final Button button = addButton(rowView, View.NO_ID, String.valueOf(GREEK_ALPHABET.charAt(letter)));
|
||||
} else if (letter < ALPHABET.length()) {
|
||||
final Button button = addButton(rowView, View.NO_ID, String.valueOf(ALPHABET.charAt(letter)));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
fixCapitalization(button);
|
||||
}
|
||||
@ -146,7 +146,7 @@ public class GreekFloatingKeyboard extends BaseFloatingKeyboard implements View.
|
||||
@Override
|
||||
public void process(@Nonnull Button key) {
|
||||
final String letter = key.getText().toString();
|
||||
if (!GREEK_ALPHABET.contains(letter.toLowerCase(Locale.US))) {
|
||||
if (!ALPHABET.contains(letter.toLowerCase(Locale.US))) {
|
||||
return;
|
||||
}
|
||||
if (upperCase) {
|
||||
|
@ -66,7 +66,7 @@ public class VariablesFragment extends BaseEntitiesFragment<IConstant> implement
|
||||
final List<IConstant> constants = expression.getUndefinedVars();
|
||||
return constants.isEmpty();
|
||||
} catch (RuntimeException e) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,10 @@ import android.text.InputType;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.solovyev.android.Check;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class EditTextCompat extends EditText {
|
||||
|
||||
@ -38,23 +36,27 @@ public class EditTextCompat extends EditText {
|
||||
}
|
||||
|
||||
public void dontShowSoftInputOnFocusCompat() {
|
||||
setShowSoftInputOnFocusCompat(false);
|
||||
}
|
||||
|
||||
public void setShowSoftInputOnFocusCompat(boolean show) {
|
||||
Check.isMainThread();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
setShowSoftInputOnFocus(false);
|
||||
setShowSoftInputOnFocus(show);
|
||||
} else {
|
||||
dontShowSoftInputOnFocusPreLollipop();
|
||||
dontShowSoftInputOnFocusPreLollipop(show);
|
||||
}
|
||||
}
|
||||
|
||||
private void dontShowSoftInputOnFocusPreLollipop() {
|
||||
private void dontShowSoftInputOnFocusPreLollipop(boolean show) {
|
||||
final Method method = getSetShowSoftInputOnFocusMethod();
|
||||
if (method == null) {
|
||||
disableSoftInputFromAppearing();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
method.invoke(this, false);
|
||||
method.invoke(this, show);
|
||||
} catch (Exception e) {
|
||||
Log.w("EditTextCompat", e.getMessage(), e);
|
||||
}
|
||||
|
@ -73,7 +73,8 @@
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:hint="@string/c_function_description"
|
||||
a:inputType="text" />
|
||||
a:inputType="textMultiLine"
|
||||
a:maxLines="4" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -55,12 +55,12 @@
|
||||
a:id="@+id/variable_keyboard_button"
|
||||
a:layout_width="wrap_content"
|
||||
a:layout_height="wrap_content"
|
||||
a:layout_gravity="end|center_vertical"
|
||||
a:layout_gravity="end|top"
|
||||
a:background="?attr/selectableItemBackgroundBorderless"
|
||||
a:minWidth="0dp"
|
||||
a:padding="@dimen/cpp_image_button_padding"
|
||||
a:text="@string/cpp_show_greek_keyboard"
|
||||
a:textAllCaps="false"
|
||||
a:padding="@dimen/cpp_image_button_padding"
|
||||
a:minWidth="0dp"
|
||||
a:textAppearance="?android:attr/textAppearanceSmall"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
</FrameLayout>
|
||||
@ -87,7 +87,8 @@
|
||||
a:layout_width="match_parent"
|
||||
a:layout_height="wrap_content"
|
||||
a:hint="@string/c_var_description"
|
||||
a:inputType="text" />
|
||||
a:inputType="textMultiLine"
|
||||
a:maxLines="4" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user