protected void setState(CalculatorState state) { if (mCurrentState != state) { mCurrentState = state; invalidateEqualsButton(); if (state == CalculatorState.RESULT || state == CalculatorState.ERROR) { mDeleteButton.setVisibility(View.GONE); mClearButton.setVisibility(View.VISIBLE); } else { mDeleteButton.setVisibility(View.VISIBLE); mClearButton.setVisibility(View.GONE); } if (state == CalculatorState.ERROR) { final int errorColor = getResources().getColor(R.color.calculator_error_color); mFormulaEditText.setTextColor(errorColor); mResultEditText.setTextColor(errorColor); if (android.os.Build.VERSION.SDK_INT >= 21) { getWindow().setStatusBarColor(errorColor); } } else { mFormulaEditText.setTextColor(getResources().getColor(R.color.display_formula_text_color)); mResultEditText.setTextColor(getResources().getColor(R.color.display_result_text_color)); if (android.os.Build.VERSION.SDK_INT >= 21) { getWindow().setStatusBarColor(getResources().getColor(R.color.calculator_accent_color)); } } } }
/** * Inserts text into the formula EditText. If an equation was recently solved, it will replace the * formula's text instead of appending. */ protected void insert(String text) { // Add left parenthesis after functions. if (mCurrentState.equals(CalculatorState.INPUT) || mCurrentState.equals(CalculatorState.GRAPHING) || mFormulaEditText.isCursorModified()) { mFormulaEditText.insert(text); } else { mFormulaEditText.setText(text); incrementGroupId(); } }
private void onEquals() { String text = mFormulaEditText.getCleanText(); if (mCurrentState == CalculatorState.INPUT) { switch (mEqualButton.getState()) { case EQUALS: setState(CalculatorState.EVALUATE); mEvaluator.evaluate(text, this); break; case NEXT: mFormulaEditText.next(); break; } } else if (mCurrentState == CalculatorState.GRAPHING) { setState(CalculatorState.EVALUATE); onEvaluate(text, "", INVALID_RES_ID); } }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_calculator); savedInstanceState = savedInstanceState == null ? Bundle.EMPTY : savedInstanceState; initialize(savedInstanceState); mEvaluator.evaluate(mFormulaEditText.getCleanText(), this); }
@Override public void onEvaluate(String expr, String result, int errorResourceId) { if (mCurrentState == CalculatorState.INPUT || mCurrentState == CalculatorState.GRAPHING) { if (result == null || Solver.equal(result, expr)) { mResultEditText.setText(null); } else { mResultEditText.setText(result); } } else if (errorResourceId != INVALID_RES_ID) { onError(errorResourceId); } else if (saveHistory(expr, result, true)) { mDisplayView.scrollToMostRecent(); onResult(result); } else if (mCurrentState == CalculatorState.EVALUATE) { // The current expression cannot be evaluated -> return to the input state. setState(CalculatorState.INPUT); } invalidateEqualsButton(); }
public void onButtonClick(View view) { mCurrentButton = view; switch (view.getId()) { case R.id.eq: onEquals(); break; case R.id.del: onDelete(); break; case R.id.clr: onClear(); break; case R.id.parentheses: mFormulaEditText.setText('(' + mFormulaEditText.getCleanText() + ')'); break; case R.id.fun_cos: case R.id.fun_sin: case R.id.fun_tan: case R.id.fun_ln: case R.id.fun_log: case R.id.fun_det: case R.id.fun_transpose: case R.id.fun_inverse: case R.id.fun_trace: case R.id.fun_norm: case R.id.fun_polar: // Add left parenthesis after functions. insert(((Button) view).getText() + "("); break; case R.id.op_add: case R.id.op_sub: case R.id.op_mul: case R.id.op_div: case R.id.op_fact: case R.id.op_pow: mFormulaEditText.insert(((Button) view).getText().toString()); break; default: insert(((Button) view).getText().toString()); break; } }
@Override protected void onSaveInstanceState(@NonNull Bundle outState) { // If there's an animation in progress, cancel it first to ensure our state is up-to-date. if (mCurrentAnimator != null) { mCurrentAnimator.cancel(); } super.onSaveInstanceState(outState); outState.putInt(KEY_CURRENT_STATE, mCurrentState.ordinal()); outState.putString( KEY_CURRENT_EXPRESSION, mTokenizer.getNormalizedExpression(mFormulaEditText.getCleanText())); }
protected void onClear() { if (TextUtils.isEmpty(mFormulaEditText.getCleanText())) { return; } reveal( mCurrentButton, R.color.calculator_accent_color, new AnimationFinishedListener() { @Override public void onAnimationFinished() { mFormulaEditText.clear(); incrementGroupId(); } }); }
@Override public boolean onLongClick(View view) { mCurrentButton = view; switch (view.getId()) { case R.id.del: saveHistory(mFormulaEditText.getCleanText(), mResultEditText.getCleanText(), true); onClear(); return true; case R.id.lparen: case R.id.rparen: mFormulaEditText.setText('(' + mFormulaEditText.getCleanText() + ')'); return true; case R.id.fun_sin: insert(getString(R.string.fun_arcsin) + "("); return true; case R.id.fun_cos: insert(getString(R.string.fun_arccos) + "("); return true; case R.id.fun_tan: insert(getString(R.string.fun_arctan) + "("); return true; } return false; }
protected void initialize(Bundle savedInstanceState) { // Rebuild constants. If the user changed their locale, it won't kill the app // but it might change a decimal point from . to , Constants.rebuildConstants(); mDisplayView = (DisplayOverlay) findViewById(R.id.display); mDisplayView.setFade(findViewById(R.id.history_fade)); mDisplayForeground = (ViewGroup) findViewById(R.id.the_clear_animation); mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula); mResultEditText = (CalculatorEditText) findViewById(R.id.result); mPadViewPager = (CalculatorPadView) findViewById(R.id.pad_pager); mDeleteButton = findViewById(R.id.del); mClearButton = findViewById(R.id.clr); mEqualButton = (EqualsImageButton) findViewById(R.id.pad_numeric).findViewById(R.id.eq); if (mEqualButton == null || mEqualButton.getVisibility() != View.VISIBLE) { mEqualButton = (EqualsImageButton) findViewById(R.id.pad_operator).findViewById(R.id.eq); } mTokenizer = new CalculatorExpressionTokenizer(this); mEvaluator = new CalculatorExpressionEvaluator(mTokenizer); setState( CalculatorState.values()[ savedInstanceState.getInt(KEY_CURRENT_STATE, CalculatorState.INPUT.ordinal())]); mFormulaEditText.setSolver(mEvaluator.getSolver()); mResultEditText.setSolver(mEvaluator.getSolver()); mFormulaEditText.setText( mTokenizer.getLocalizedExpression( savedInstanceState.getString(KEY_CURRENT_EXPRESSION, ""))); mFormulaEditText.addTextChangedListener(mFormulaTextWatcher); mFormulaEditText.setOnKeyListener(mFormulaOnKeyListener); mFormulaEditText.setOnTextSizeChangeListener(this); mDeleteButton.setOnLongClickListener(this); mResultEditText.setEnabled(false); findViewById(R.id.lparen).setOnLongClickListener(this); findViewById(R.id.rparen).setOnLongClickListener(this); findViewById(R.id.fun_sin).setOnLongClickListener(this); findViewById(R.id.fun_cos).setOnLongClickListener(this); findViewById(R.id.fun_tan).setOnLongClickListener(this); // Disable IME for this application getWindow() .setFlags( WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); Button dot = (Button) findViewById(R.id.dec_point); dot.setText(String.valueOf(Constants.DECIMAL_POINT)); }
protected void onError(final int errorResourceId) { if (mCurrentState != CalculatorState.EVALUATE) { // Only animate error on evaluate. mResultEditText.setText(errorResourceId); return; } reveal( mCurrentButton, R.color.calculator_error_color, new AnimationFinishedListener() { @Override public void onAnimationFinished() { setState(CalculatorState.ERROR); mResultEditText.setText(errorResourceId); } }); }
protected void onResult(final String result) { // Calculate the values needed to perform the scale and translation animations, // accounting for how the scale will affect the final position of the text. final float resultScale = mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize(); final float resultTranslationX = (1.0f - resultScale) * (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingRight()); // Calculate the height of the formula (without padding) final float formulaRealHeight = mFormulaEditText.getHeight() - mFormulaEditText.getPaddingTop() - mFormulaEditText.getPaddingBottom(); // Calculate the height of the resized result (without padding) final float resultRealHeight = resultScale * (mResultEditText.getHeight() - mResultEditText.getPaddingTop() - mResultEditText.getPaddingBottom()); // Now adjust the result upwards! final float resultTranslationY = // Move the result up (so both formula + result heights match) -mFormulaEditText.getHeight() // Now switch the result's padding top with the formula's padding top - resultScale * mResultEditText.getPaddingTop() + mFormulaEditText.getPaddingTop() // But the result centers its text! And it's taller now! So adjust for that centered // text + (formulaRealHeight - resultRealHeight) / 2; // Move the formula all the way to the top of the screen final float formulaTranslationY = -mFormulaEditText.getBottom(); // Use a value animator to fade to the final text color over the course of the animation. final int resultTextColor = mResultEditText.getCurrentTextColor(); final int formulaTextColor = mFormulaEditText.getCurrentTextColor(); final ValueAnimator textColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor); textColorAnimator.addUpdateListener( new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mResultEditText.setTextColor((Integer) valueAnimator.getAnimatedValue()); } }); mResultEditText.setText(result); mResultEditText.setPivotX(mResultEditText.getWidth() / 2); mResultEditText.setPivotY(0f); final AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether( textColorAnimator, ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale), ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale), ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX), ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY), ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY)); animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime)); animatorSet.setInterpolator(new AccelerateDecelerateInterpolator()); animatorSet.addListener( new AnimationFinishedListener() { @Override public void onAnimationFinished() { // Reset all of the values modified during the animation. mResultEditText.setPivotY(mResultEditText.getHeight() / 2); mResultEditText.setTextColor(resultTextColor); mResultEditText.setScaleX(1.0f); mResultEditText.setScaleY(1.0f); mResultEditText.setTranslationX(0.0f); mResultEditText.setTranslationY(0.0f); mFormulaEditText.setTranslationY(0.0f); // Finally update the formula to use the current result. mFormulaEditText.setText(result); setState(CalculatorState.RESULT); } }); play(animatorSet); }
protected void onDelete() { // Delete works like backspace; remove the last character from the expression. mFormulaEditText.backspace(); }
@Override protected void onPause() { super.onPause(); saveHistory(mFormulaEditText.getCleanText(), mResultEditText.getCleanText(), true); mPersist.save(); }