KeyboardUi in EditFunctionDialog

This commit is contained in:
serso 2016-01-19 12:59:57 +01:00
parent 58da5a169e
commit 712f94484f
33 changed files with 768 additions and 8 deletions

View File

@ -0,0 +1,408 @@
package org.solovyev.android.calculator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.solovyev.android.views.dragbutton.DirectionDragButton;
import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.SimpleDragListener;
import java.util.List;
import static org.solovyev.android.views.dragbutton.DirectionDragButton.Direction.down;
import static org.solovyev.android.views.dragbutton.DirectionDragButton.Direction.up;
public class KeyboardUi {
@NonNull
private final ButtonHandler buttonHandler = new ButtonHandler();
@NonNull
private final User user;
@NonNull
private final List<String> parameterNames;
@NonNull
private final SimpleDragListener dragListener;
private final int textColor;
private final int textColorSecondary;
private final int sidePadding;
@SuppressWarnings("deprecation")
public KeyboardUi(@NonNull User user, @NonNull List<String> parameterNames) {
this.user = user;
this.parameterNames = parameterNames;
this.dragListener = new SimpleDragListener(buttonHandler, user.getContext());
final Resources resources = user.getResources();
textColor = resources.getColor(R.color.cpp_button_text);
textColorSecondary = resources.getColor(R.color.cpp_button_text);
sidePadding = resources.getDimensionPixelSize(R.dimen.cpp_button_padding);
}
public void makeView() {
LinearLayout row = makeRow();
addButton(row, 0, "7");
addButton(row, 0, "8");
addButton(row, 0, "9").setText("π", up).setText("e", down);
addOperationButton(row, R.id.cpp_kb_button_multiply, Locator.getInstance().getEngine().getMultiplicationSign()).setText("^n", up).setText("^2", down);
addButton(row, R.id.cpp_kb_button_clear, "C");
row = makeRow();
addButton(row, 0, "4");
addButton(row, 0, "5");
addButton(row, 0, "6");
addOperationButton(row, R.id.cpp_kb_button_divide, "/").setText("%", up).setText("sqrt", down);
final View backspace = addImageButton(row, R.id.cpp_kb_button_backspace, R.drawable.ic_backspace_white_24dp);
LongClickEraser.createAndAttach(backspace, user.getEditor());
row = makeRow();
addButton(row, 0, "1");
addButton(row, 0, "2");
addButton(row, 0, "3");
addOperationButton(row, R.id.cpp_kb_button_plus, "+");
addImageButton(row, R.id.cpp_kb_button_space, R.drawable.ic_space_bar_white_24dp);
row = makeRow();
addButton(row, R.id.cpp_kb_button_brackets, "( )").setText("(", up).setText(")", down);
addButton(row, 0, "0").setText("00", up).setText("000", down);
addButton(row, 0, ".").setText(",", up);
addOperationButton(row, R.id.cpp_kb_button_minus, "");
addImageButton(row, R.id.cpp_kb_button_keyboard, R.drawable.ic_keyboard_white_24dp);
row = makeRow();
final int parametersCount = parameterNames.size();
addButton(row, 0, parametersCount > 0 ? parameterNames.get(0) : "x");
addButton(row, 0, parametersCount > 1 ? parameterNames.get(1) : "y");
addButton(row, R.id.cpp_kb_button_functions, "f(x)");
addButton(row, R.id.cpp_kb_button_constants, "π");
addImageButton(row, R.id.cpp_kb_button_close, R.drawable.ic_done_white_24dp);
}
@NonNull
private View addImageButton(@NonNull LinearLayout row, @IdRes int id, @DrawableRes int icon) {
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
lp.weight = 1f;
final View view = makeImageButton(id, icon);
row.addView(view, lp);
return view;
}
@NonNull
private DirectionDragButton addOperationButton(@NonNull LinearLayout row, @IdRes int id, @NonNull String text) {
final DirectionDragButton button = addButton(row, id, text);
button.setBackgroundResource(R.drawable.material_button_light_primary);
button.setTextColor(Color.WHITE);
button.setDirectionTextColor(Color.WHITE);
return button;
}
@NonNull
private DirectionDragButton addButton(@NonNull LinearLayout row, @IdRes int id, @NonNull String text) {
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
lp.weight = 1f;
final DirectionDragButton view = makeButton(id, text);
row.addView(view, lp);
return view;
}
@NonNull
private LinearLayout makeRow() {
final LinearLayout row = new LinearLayout(user.getContext());
row.setOrientation(LinearLayout.HORIZONTAL);
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0);
lp.weight = 1f;
user.getKeyboard().addView(row, lp);
return row;
}
@NonNull
private DirectionDragButton makeButton(@IdRes int id, @NonNull String text) {
final DirectionDragButton button = new DirectionDragButton(user.getContext());
fillButton(button, id);
button.setText(text);
button.setTextColor(textColor);
button.setDirectionTextColor(textColorSecondary);
button.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24);
button.setOnDragListener(dragListener);
return button;
}
private void fillButton(@NonNull View button, @IdRes int id) {
button.setOnClickListener(buttonHandler);
button.setId(id);
button.setBackgroundResource(R.drawable.material_button_light);
button.setPadding(sidePadding, 1, sidePadding, 1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
button.setStateListAnimator(null);
}
}
@NonNull
private View makeImageButton(@IdRes int id, @DrawableRes int icon) {
final ImageButton button = new ImageButton(user.getContext());
fillButton(button, id);
button.setImageResource(icon);
button.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
return button;
}
public interface User {
@NonNull
Context getContext();
@NonNull
Resources getResources();
@NonNull
EditText getEditor();
@NonNull
ViewGroup getKeyboard();
void insertOperator(char operator);
void insertOperator(@NonNull String operator);
void showFunctions(@NonNull View v);
void showConstants(@NonNull View v);
void insertText(@NonNull CharSequence text, int offset);
void done();
void showIme();
}
private class ButtonHandler implements View.OnClickListener, SimpleDragListener.DragProcessor {
@Override
public void onClick(@NonNull View v) {
switch (v.getId()) {
case R.id.cpp_kb_button_divide:
user.insertOperator('/');
break;
case R.id.cpp_kb_button_plus:
user.insertOperator('+');
break;
case R.id.cpp_kb_button_minus:
user.insertOperator('-');
break;
case R.id.cpp_kb_button_multiply:
user.insertOperator('*');
break;
case R.id.cpp_kb_button_functions:
user.showFunctions(v);
break;
case R.id.cpp_kb_button_constants:
user.showConstants(v);
break;
case R.id.cpp_kb_button_space:
user.insertText(" ", 0);
break;
case R.id.cpp_kb_button_keyboard:
user.showIme();
break;
case R.id.cpp_kb_button_clear:
user.getEditor().setText("");
user.getEditor().setSelection(0);
break;
case R.id.cpp_kb_button_brackets:
user.insertText("()", -1);
break;
case R.id.cpp_kb_button_close:
user.done();
break;
default:
onDefaultClick(v);
break;
}
user.getEditor().requestFocus();
v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
}
private void onDefaultClick(@NonNull View v) {
user.insertText(((Button) v).getText(), 0);
}
@Override
public boolean processDragEvent(@NonNull DragDirection direction, @NonNull DragButton button, @NonNull PointF startPoint, @NonNull MotionEvent e) {
switch (button.getId()) {
default:
return onDefaultDrag(button, direction);
}
}
private boolean onDefaultDrag(@NonNull DragButton button, @NonNull DragDirection direction) {
final String text = ((DirectionDragButton) button).getText(direction);
if (TextUtils.isEmpty(text)) {
return false;
}
switch (text) {
case "sqrt":
user.insertText("sqrt()", -1);
break;
case ",":
user.insertText(", ", 0);
break;
case "^n":
user.insertOperator('^');
break;
case "^2":
user.insertOperator("^ 2");
break;
case "?":
case ">":
case "<":
case ">=":
case "<=":
case ":":
user.insertOperator(text);
break;
default:
user.insertText(text, 0);
break;
}
button.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
return true;
}
}
public static final class LongClickEraser implements View.OnTouchListener, View.OnClickListener {
@NonNull
private final View view;
@NonNull
private final EditText editText;
@NonNull
private final GestureDetector gestureDetector;
@NonNull
private final Eraser eraser = new Eraser();
private LongClickEraser(@NonNull final View view, @NonNull EditText editText) {
this.view = view;
this.editText = editText;
this.gestureDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
if (eraser.isTracking()) {
eraser.start();
}
}
});
}
public static void createAndAttach(@NonNull View view, @NonNull EditText editText) {
final LongClickEraser l = new LongClickEraser(view, editText);
view.setOnClickListener(l);
view.setOnTouchListener(l);
}
private static void erase(@NonNull EditText editText) {
final int start = clampSelection(editText.getSelectionStart());
final int end = clampSelection(editText.getSelectionEnd());
if (start != end) {
editText.getText().delete(Math.min(start, end), Math.max(start, end));
} else if (start > 0) {
editText.getText().delete(start - 1, start);
}
}
public static int clampSelection(int selection) {
return selection < 0 ? 0 : selection;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
eraser.stopTracking();
break;
default:
eraser.startTracking();
gestureDetector.onTouchEvent(event);
break;
}
return false;
}
@Override
public void onClick(View v) {
erase(editText);
v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
}
private class Eraser implements Runnable {
private static final int DELAY = 300;
private long delay;
private boolean erasing;
private boolean tracking = true;
@Override
public void run() {
erase(editText);
if (editText.length() == 0 || clampSelection(editText.getSelectionStart()) == 0) {
stop();
return;
}
delay = Math.max(50, 2 * delay / 3);
view.postDelayed(this, delay);
}
void start() {
if (erasing) {
stop();
}
erasing = true;
delay = DELAY;
view.removeCallbacks(this);
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
run();
}
void stop() {
view.removeCallbacks(this);
if (!erasing) {
return;
}
erasing = false;
}
public void stopTracking() {
stop();
tracking = false;
}
public boolean isTracking() {
return tracking;
}
public void startTracking() {
tracking = true;
}
}
}
}

View File

@ -0,0 +1,105 @@
package org.solovyev.android.calculator;
import android.app.Dialog;
import android.content.Context;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import java.util.List;
public class KeyboardWindow {
@Nullable
private PopupWindow window;
@Nullable
private Dialog dialog;
private static void hideIme(@NonNull View view) {
final IBinder token = view.getWindowToken();
if (token != null) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(token, 0);
}
}
public void hide() {
if (!isShown()) {
return;
}
moveDialog(Gravity.CENTER);
window.dismiss();
window = null;
dialog = null;
}
public void show(@NonNull KeyboardUi.User user, @Nullable Dialog dialog, @NonNull List<String> parameterNames) {
if (isShown()) {
return;
}
this.dialog = dialog;
moveDialog(Gravity.TOP);
final EditText editor = user.getEditor();
hideIme(editor);
final Context context = editor.getContext();
final LinearLayout view = new LinearLayout(context);
view.setOrientation(LinearLayout.VERTICAL);
final int buttonSize = context.getResources().getDimensionPixelSize(R.dimen.cpp_kb_button_size);
final int keyboardSize = 5 * buttonSize;
window = new PopupWindow(view, keyboardSize, keyboardSize);
window.setClippingEnabled(false);
window.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
window = null;
}
});
// see http://stackoverflow.com/a/4713487/720489
editor.post(new Runnable() {
@Override
public void run() {
if (window == null) {
return;
}
if (editor.getWindowToken() != null) {
hideIme(editor);
final int inputWidth = editor.getWidth();
final int xOff = (inputWidth - keyboardSize) / 2;
window.setWidth(keyboardSize);
window.showAsDropDown(editor, xOff, 0);
} else {
editor.postDelayed(this, 50);
}
}
});
new KeyboardUi(user, parameterNames).makeView();
}
public boolean isShown() {
return window != null;
}
@SuppressWarnings("unchecked")
public <V extends View> V getContentView() {
return (V) window.getContentView();
}
public void moveDialog(int gravity) {
if (dialog == null) {
return;
}
final Window window = dialog.getWindow();
final WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = gravity;
window.setAttributes(lp);
}
}

View File

@ -22,9 +22,11 @@
package org.solovyev.android.calculator.function; package org.solovyev.android.calculator.function;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@ -33,8 +35,15 @@ import android.support.design.widget.TextInputLayout;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
@ -45,6 +54,8 @@ import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType; import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorUtils; import org.solovyev.android.calculator.CalculatorUtils;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.KeyboardUi;
import org.solovyev.android.calculator.KeyboardWindow;
import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity; import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
@ -52,8 +63,10 @@ import org.solovyev.android.calculator.math.edit.FunctionsFragment;
import org.solovyev.android.calculator.math.edit.MathEntityRemover; import org.solovyev.android.calculator.math.edit.MathEntityRemover;
import org.solovyev.android.calculator.math.edit.VarEditorSaver; import org.solovyev.android.calculator.math.edit.VarEditorSaver;
import org.solovyev.android.calculator.model.AFunction; import org.solovyev.android.calculator.model.AFunction;
import org.solovyev.common.math.MathRegistry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -66,11 +79,23 @@ import jscl.math.Generic;
import jscl.math.function.Constant; 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.IConstant;
import jscl.math.function.IFunction; import jscl.math.function.IFunction;
public class EditFunctionFragment extends BaseDialogFragment implements CalculatorEventListener { public class EditFunctionFragment extends BaseDialogFragment implements CalculatorEventListener, View.OnClickListener, View.OnFocusChangeListener, View.OnKeyListener {
private static final String ARG_INPUT = "input"; private static final String ARG_INPUT = "input";
private static final int MENU_FUNCTION = Menu.FIRST;
private static final int MENU_CONSTANT = Menu.FIRST + 1;
@NonNull
private final MathRegistry<Function> functionsRegistry = Locator.getInstance().getEngine().getFunctionsRegistry();
@NonNull
private final MathRegistry<IConstant> constantsRegistry = Locator.getInstance().getEngine().getVarsRegistry();
@NonNull
private final KeyboardWindow keyboardWindow = new KeyboardWindow();
@NonNull
private final KeyboardUser keyboardUser = new KeyboardUser();
@Bind(R.id.function_params) @Bind(R.id.function_params)
FunctionParamsView paramsView; FunctionParamsView paramsView;
@Bind(R.id.function_name_label) @Bind(R.id.function_name_label)
@ -120,7 +145,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
builder.setPositiveButton(R.string.ok, null); builder.setPositiveButton(R.string.ok, null);
final AFunction function = input.getFunction(); final AFunction function = input.getFunction();
builder.setTitle(function == null ? R.string.function_create_function : R.string.function_edit_function); builder.setTitle(function == null ? R.string.function_create_function : R.string.function_edit_function);
if(function != null) { if (function != null) {
builder.setNeutralButton(R.string.c_remove, null); builder.setNeutralButton(R.string.c_remove, null);
} }
} }
@ -154,6 +179,34 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
return dialog; return dialog;
} }
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (v.getId() == R.id.function_body) {
if (hasFocus) {
keyboardWindow.show(keyboardUser, getDialog(), paramsView.getParams());
} else {
keyboardWindow.hide();
}
}
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.function_body) {
keyboardWindow.show(keyboardUser, getDialog(), paramsView.getParams());
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (v.getId() == R.id.function_body) {
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK && keyboardWindow.isShown()) {
keyboardWindow.hide();
return true;
}
}
return false;
}
private void tryClose() { private void tryClose() {
if (validate()) { if (validate()) {
applyData(); applyData();
@ -169,6 +222,9 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
if (!validateName()) { if (!validateName()) {
return false; return false;
} }
if (!validateBody()) {
return false;
}
return true; return true;
} }
@ -182,6 +238,11 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
return true; return true;
} }
private boolean validateBody() {
return true;
}
@SuppressLint("InflateParams")
@NonNull @NonNull
@Override @Override
protected View onCreateDialogView(@NonNull Context context, @NonNull LayoutInflater inflater, @Nullable Bundle savedInstanceState) { protected View onCreateDialogView(@NonNull Context context, @NonNull LayoutInflater inflater, @Nullable Bundle savedInstanceState) {
@ -198,6 +259,9 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
descriptionView.setText(input.getDescription()); descriptionView.setText(input.getDescription());
bodyView.setText(input.getContent()); bodyView.setText(input.getContent());
} }
bodyView.setOnClickListener(this);
bodyView.setOnFocusChangeListener(this);
bodyView.setOnKeyListener(this);
return view; return view;
} }
@ -275,7 +339,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
result.content = in.readString(); result.content = in.readString();
result.description = in.readString(); result.description = in.readString();
final List<String> parameterNames = new ArrayList<String>(); final List<String> parameterNames = new ArrayList<>();
in.readTypedList(parameterNames, STRING_CREATOR); in.readTypedList(parameterNames, STRING_CREATOR);
result.parameterNames = parameterNames; result.parameterNames = parameterNames;
@ -310,7 +374,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
result.name = name; result.name = name;
result.content = value; result.content = value;
result.description = description; result.description = description;
result.parameterNames = new ArrayList<String>(parameterNames); result.parameterNames = new ArrayList<>(parameterNames);
return result; return result;
} }
@ -323,7 +387,7 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
final Generic generic = viewState.getResult(); final Generic generic = viewState.getResult();
if (generic != null) { if (generic != null) {
final Set<Constant> constants = CalculatorUtils.getNotSystemConstants(generic); final Set<Constant> constants = CalculatorUtils.getNotSystemConstants(generic);
final List<String> parameterNames = new ArrayList<String>(constants.size()); final List<String> parameterNames = new ArrayList<>(constants.size());
for (Constant constant : constants) { for (Constant constant : constants) {
parameterNames.add(constant.getName()); parameterNames.add(constant.getName());
} }
@ -372,4 +436,161 @@ public class EditFunctionFragment extends BaseDialogFragment implements Calculat
out.writeSerializable(function); out.writeSerializable(function);
} }
} }
private class KeyboardUser implements KeyboardUi.User, MenuItem.OnMenuItemClickListener {
@NonNull
@Override
public Context getContext() {
return getActivity();
}
@NonNull
@Override
public Resources getResources() {
return EditFunctionFragment.this.getResources();
}
@NonNull
@Override
public EditText getEditor() {
return bodyView;
}
@NonNull
@Override
public ViewGroup getKeyboard() {
return keyboardWindow.getContentView();
}
@Override
public void insertOperator(char operator) {
insertOperator(String.valueOf(operator));
}
public int clampSelection(int selection) {
return selection < 0 ? 0 : selection;
}
@Override
public void insertOperator(@NonNull String operator) {
final int start = clampSelection(bodyView.getSelectionStart());
final int end = clampSelection(bodyView.getSelectionEnd());
final Editable e = bodyView.getText();
e.replace(start, end, getOperator(start, end, e, operator));
}
@NonNull
private String getOperator(int start, int end, @NonNull Editable e, @NonNull CharSequence operator) {
boolean spaceBefore = true;
boolean spaceAfter = true;
if (start > 0 && Character.isSpaceChar(e.charAt(start - 1))) {
spaceBefore = false;
}
if (end < e.length() && Character.isSpaceChar(e.charAt(end))) {
spaceAfter = false;
}
if (spaceBefore && spaceAfter) {
return " " + operator + " ";
}
if (spaceBefore) {
return " " + operator;
}
if (spaceAfter) {
return operator + " ";
}
return String.valueOf(operator);
}
@Override
public void showConstants(@NonNull View v) {
bodyView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
final int id = v.getId();
if (id == R.id.function_body) {
menu.clear();
for (String constant : getNamesSorted(constantsRegistry)) {
menu.add(MENU_CONSTANT, Menu.NONE, Menu.NONE, constant).setOnMenuItemClickListener(KeyboardUser.this);
}
unregisterForContextMenu(bodyView);
}
}
});
bodyView.showContextMenu();
}
@Nonnull
private List<String> getNamesSorted(@NonNull MathRegistry<?> registry) {
final List<String> names = registry.getNames();
Collections.sort(names);
return names;
}
@Override
public void showFunctions(@NonNull View v) {
bodyView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
final int id = v.getId();
if (id == R.id.function_body) {
menu.clear();
for (String function : getNamesSorted(functionsRegistry)) {
menu.add(MENU_FUNCTION, Menu.NONE, Menu.NONE, function).setOnMenuItemClickListener(KeyboardUser.this);
}
unregisterForContextMenu(bodyView);
}
}
});
bodyView.showContextMenu();
}
@Override
public void insertText(@NonNull CharSequence text, int selectionOffset) {
final int start = clampSelection(bodyView.getSelectionStart());
final int end = clampSelection(bodyView.getSelectionEnd());
final Editable e = bodyView.getText();
e.replace(start, end, text);
if (selectionOffset != 0) {
final int selection = clampSelection(bodyView.getSelectionEnd());
final int newSelection = selection + selectionOffset;
if (newSelection >= 0 && newSelection < e.length()) {
bodyView.setSelection(newSelection);
}
}
}
@Override
public void done() {
keyboardWindow.hide();
validateBody();
}
@Override
public void showIme() {
final InputMethodManager keyboard = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
keyboard.showSoftInput(getEditor(), InputMethodManager.SHOW_FORCED);
keyboardWindow.hide();
}
@Override
public boolean onMenuItemClick(MenuItem item) {
final int groupId = item.getGroupId();
final CharSequence title = item.getTitle();
if (groupId == MENU_FUNCTION) {
final int argsListIndex = title.toString().indexOf("(");
if (argsListIndex < 0) {
keyboardUser.insertText(title + "()", -1);
} else {
keyboardUser.insertText(title.subSequence(0, argsListIndex) + "()", -1);
}
} else if (groupId == MENU_CONSTANT) {
keyboardUser.insertText(title.toString(), 0);
} else {
return false;
}
return true;
}
}
} }

View File

@ -27,6 +27,8 @@ import android.content.Context;
import android.os.Build; import android.os.Build;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.text.Editable;
import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -38,6 +40,7 @@ import android.widget.TextView;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.R;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -146,6 +149,7 @@ public class FunctionParamsView extends LinearLayout {
} }
paramView.setInputType(EditorInfo.TYPE_CLASS_TEXT); paramView.setInputType(EditorInfo.TYPE_CLASS_TEXT);
paramView.setId(id); paramView.setId(id);
paramView.setHint(R.string.c_function_parameter);
rowView.addView(paramView, new LayoutParams(0, WRAP_CONTENT, 3)); rowView.addView(paramView, new LayoutParams(0, WRAP_CONTENT, 3));
addView(rowView, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); addView(rowView, new ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
@ -195,7 +199,10 @@ public class FunctionParamsView extends LinearLayout {
for (int i = 1; i < getChildCount(); i++) { for (int i = 1; i < getChildCount(); i++) {
final ViewGroup row = getRowByIndex(i); final ViewGroup row = getRowByIndex(i);
final EditText paramView = (EditText) row.getChildAt(PARAM_VIEW_INDEX); final EditText paramView = (EditText) row.getChildAt(PARAM_VIEW_INDEX);
params.add(paramView.getText().toString()); final Editable param = paramView.getText();
if (!TextUtils.isEmpty(param)) {
params.add(param.toString());
}
} }
return params; return params;

View File

@ -1,5 +1,6 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
@ -11,14 +12,16 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import org.solovyev.android.calculator.AppComponent; import org.solovyev.android.calculator.AppComponent;
import org.solovyev.android.calculator.BaseDialogFragment; import org.solovyev.android.calculator.BaseDialogFragment;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import javax.inject.Inject; import javax.inject.Inject;
import butterknife.Bind;
import butterknife.ButterKnife;
public class EditHistoryFragment extends BaseDialogFragment { public class EditHistoryFragment extends BaseDialogFragment {
public static final String ARG_STATE = "state"; public static final String ARG_STATE = "state";
@ -81,6 +84,7 @@ public class EditHistoryFragment extends BaseDialogFragment {
}); });
} }
@SuppressLint("InflateParams")
@NonNull @NonNull
@Override @Override
protected View onCreateDialogView(@NonNull Context context, @NonNull LayoutInflater inflater, @Nullable Bundle savedInstanceState) { protected View onCreateDialogView(@NonNull Context context, @NonNull LayoutInflater inflater, @Nullable Bundle savedInstanceState) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

View File

@ -29,4 +29,5 @@
<dimen name="cpp_display_text_size">20sp</dimen> <dimen name="cpp_display_text_size">20sp</dimen>
<dimen name="cpp_display_text_size_mobile">20sp</dimen> <dimen name="cpp_display_text_size_mobile">20sp</dimen>
<dimen name="cpp_kb_button_size">40dp</dimen>
</resources> </resources>

View File

@ -39,4 +39,5 @@
<dimen name="cpp_onscreen_main_padding">1dp</dimen> <dimen name="cpp_onscreen_main_padding">1dp</dimen>
<dimen name="cpp_dialog_spacing">20dp</dimen> <dimen name="cpp_dialog_spacing">20dp</dimen>
<dimen name="cpp_kb_button_size">50dp</dimen>
</resources> </resources>

View File

@ -60,5 +60,17 @@
<item name="acl_wizard_prev_button" type="id" /> <item name="acl_wizard_prev_button" type="id" />
<item name="acl_wizard_next_button" type="id" /> <item name="acl_wizard_next_button" type="id" />
<item name="acl_wizard_content" type="id" /> <item name="acl_wizard_content" type="id" />
<item name="cpp_kb_button_multiply" type="id" />
<item name="cpp_kb_button_clear" type="id" />
<item name="cpp_kb_button_divide" type="id" />
<item name="cpp_kb_button_backspace" type="id" />
<item name="cpp_kb_button_plus" type="id" />
<item name="cpp_kb_button_space" type="id" />
<item name="cpp_kb_button_brackets" type="id" />
<item name="cpp_kb_button_minus" type="id" />
<item name="cpp_kb_button_keyboard" type="id" />
<item name="cpp_kb_button_functions" type="id" />
<item name="cpp_kb_button_constants" type="id" />
<item name="cpp_kb_button_close" type="id" />
</resources> </resources>

View File

@ -149,6 +149,7 @@
<string name="c_function_value">Value</string> <string name="c_function_value">Value</string>
<string name="c_function_description">Description</string> <string name="c_function_description">Description</string>
<string name="c_function_parameters">Parameters</string> <string name="c_function_parameters">Parameters</string>
<string name="c_function_parameter">Parameter</string>
<string name="function_create_function">Create function</string> <string name="function_create_function">Create function</string>
<string name="function_edit_function">Edit function</string> <string name="function_edit_function">Edit function</string>
<string name="function_name_is_not_valid">Name of function is not valid: name must start with a letter, can contain letters, digits and underscore.</string> <string name="function_name_is_not_valid">Name of function is not valid: name must start with a letter, can contain letters, digits and underscore.</string>