From 5a9bcdede73e6ce16b03bfa310bf1dcae7ab9ab4 Mon Sep 17 00:00:00 2001 From: serso Date: Thu, 28 Apr 2016 12:18:35 +0200 Subject: [PATCH 01/16] Number format preference --- app/src/main/AndroidManifest.xml | 6 +- .../org/solovyev/android/calculator/App.java | 18 +- .../solovyev/android/calculator/Engine.java | 45 +++- .../converter/ConverterFragment.java | 52 ++-- .../preferences/NumberFormatPreference.java | 100 ++++++++ .../preferences/PreferencesFragment.java | 6 +- .../calculator/text/NaturalComparator.java | 12 + .../android/views/DiscreteSeekBar.java | 224 ++++++++++++++++++ .../layout/fragment_plot_function_edit.xml | 8 +- .../res/layout/preference_number_format.xml | 34 +++ app/src/main/res/values/attrs_dsb.xml | 8 + app/src/main/res/values/styles.xml | 5 + .../main/res/values/text_non_translatable.xml | 1 - app/src/main/res/values/text_strings.xml | 3 + .../main/res/xml/preferences_calculations.xml | 8 +- 15 files changed, 477 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java create mode 100644 app/src/main/java/org/solovyev/android/calculator/text/NaturalComparator.java create mode 100644 app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java create mode 100644 app/src/main/res/layout/preference_number_format.xml create mode 100644 app/src/main/res/values/attrs_dsb.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8ac9c420..1624bd8a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -56,7 +56,11 @@ + android:label="@string/cpp_settings"> + + + + ArrayAdapter makeSimpleSpinnerAdapter(@NonNull Context context) { + return new ArrayAdapter<>(context, R.layout.support_simple_spinner_dropdown_item); + } + public interface ViewProcessor { void process(@Nonnull V view); } diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index 244881f9..36ceb743 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -23,15 +23,11 @@ package org.solovyev.android.calculator; import android.content.SharedPreferences; +import android.support.annotation.StringRes; import android.text.TextUtils; + import com.squareup.otto.Bus; -import jscl.AngleUnit; -import jscl.JsclMathEngine; -import jscl.MathEngine; -import jscl.NumeralBase; -import jscl.math.operator.Operator; -import jscl.text.Identifier; -import jscl.text.Parser; + import org.solovyev.android.Check; import org.solovyev.android.calculator.functions.FunctionsRegistry; import org.solovyev.android.calculator.operators.OperatorsRegistry; @@ -43,15 +39,25 @@ import org.solovyev.android.prefs.StringPreference; import org.solovyev.common.text.EnumMapper; import org.solovyev.common.text.NumberMapper; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.annotation.Nullable; +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; +import jscl.text.Identifier; +import jscl.text.Parser; +import midpcalc.Real; + @Singleton public class Engine implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -231,8 +237,24 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } } + public enum Notation { + simple(Real.NumberFormat.FSE_NONE, R.string.cpp_number_format_simple), + eng(Real.NumberFormat.FSE_ENG, R.string.cpp_number_format_eng), + sci(Real.NumberFormat.FSE_SCI, R.string.cpp_number_format_sci); + + public final int id; + @StringRes + public final int name; + + Notation(int id, @StringRes int name) { + this.id = id; + this.name = name; + } + } + public static class ChangedEvent { static final ChangedEvent INSTANCE = new ChangedEvent(); + private ChangedEvent() { } } @@ -264,6 +286,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static final StringPreference precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class)); public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false); public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); + public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.simple, Notation.class); } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java b/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java index c69ec60b..448a6b8d 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java @@ -21,21 +21,38 @@ import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.widget.*; -import butterknife.Bind; -import butterknife.ButterKnife; -import org.solovyev.android.calculator.*; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import org.solovyev.android.calculator.App; +import org.solovyev.android.calculator.AppComponent; +import org.solovyev.android.calculator.AppModule; +import org.solovyev.android.calculator.BaseDialogFragment; +import org.solovyev.android.calculator.Clipboard; +import org.solovyev.android.calculator.Editor; +import org.solovyev.android.calculator.Keyboard; +import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.keyboard.FloatingKeyboard; import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow; import org.solovyev.android.calculator.keyboard.FloatingNumberKeyboard; import org.solovyev.android.calculator.math.MathUtils; +import org.solovyev.android.calculator.text.NaturalComparator; import org.solovyev.android.calculator.view.EditTextCompat; import javax.annotation.Nonnull; import javax.inject.Inject; -import java.util.Comparator; -import static org.solovyev.android.calculator.UiPreferences.Converter.*; +import butterknife.Bind; +import butterknife.ButterKnife; + +import static org.solovyev.android.calculator.UiPreferences.Converter.lastDimension; +import static org.solovyev.android.calculator.UiPreferences.Converter.lastUnitsFrom; +import static org.solovyev.android.calculator.UiPreferences.Converter.lastUnitsTo; public class ConverterFragment extends BaseDialogFragment implements AdapterView.OnItemSelectedListener, View.OnFocusChangeListener, TextView.OnEditorActionListener, View.OnClickListener, TextWatcher { @@ -44,7 +61,6 @@ public class ConverterFragment extends BaseDialogFragment private static final String STATE_SELECTION_FROM = "selection.from"; private static final String STATE_SELECTION_TO = "selection.to"; private static final String EXTRA_VALUE = "value"; - private static final NamedItemComparator COMPARATOR = new NamedItemComparator(); public static final int NONE = -1; @NonNull @@ -96,11 +112,6 @@ public class ConverterFragment extends BaseDialogFragment App.showDialog(fragment, "converter", activity.getSupportFragmentManager()); } - @Nonnull - private static ArrayAdapter makeAdapter(@NonNull Context context) { - return new ArrayAdapter<>(context, R.layout.support_simple_spinner_dropdown_item); - } - @NonNull @Override public AlertDialog onCreateDialog(@Nullable Bundle savedInstanceState) { @@ -130,13 +141,13 @@ public class ConverterFragment extends BaseDialogFragment final View view = inflater.inflate(R.layout.cpp_unit_converter, null); ButterKnife.bind(this, view); - dimensionsAdapter = makeAdapter(context); + dimensionsAdapter = App.makeSimpleSpinnerAdapter(context); for (ConvertibleDimension dimension : UnitDimension.values()) { dimensionsAdapter.add(dimension.named(context)); } dimensionsAdapter.add(NumeralBaseDimension.get().named(context)); - adapterFrom = makeAdapter(context); - adapterTo = makeAdapter(context); + adapterFrom = App.makeSimpleSpinnerAdapter(context); + adapterTo = App.makeSimpleSpinnerAdapter(context); dimensionsSpinner.setAdapter(dimensionsAdapter); spinnerFrom.setAdapter(adapterFrom); @@ -235,7 +246,7 @@ public class ConverterFragment extends BaseDialogFragment for (Convertible unit : dimension.getUnits()) { adapterFrom.add(unit.named(getActivity())); } - adapterFrom.sort(COMPARATOR); + adapterFrom.sort(NaturalComparator.INSTANCE); adapterFrom.setNotifyOnChange(true); adapterFrom.notifyDataSetChanged(); if (pendingFromSelection != NONE) { @@ -261,7 +272,7 @@ public class ConverterFragment extends BaseDialogFragment adapterTo.add(unit.named(getActivity())); } } - adapterTo.sort(COMPARATOR); + adapterTo.sort(NaturalComparator.INSTANCE); adapterTo.setNotifyOnChange(true); adapterTo.notifyDataSetChanged(); if (selectedUnit != null && !except.equals(selectedUnit)) { @@ -431,13 +442,6 @@ public class ConverterFragment extends BaseDialogFragment super.dismiss(); } - private static class NamedItemComparator implements Comparator> { - @Override - public int compare(Named lhs, Named rhs) { - return lhs.toString().compareTo(rhs.toString()); - } - } - private class KeyboardUser implements FloatingKeyboard.User { @NonNull @Override diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java new file mode 100644 index 00000000..2edb24db --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -0,0 +1,100 @@ +package org.solovyev.android.calculator.preferences; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; +import android.preference.DialogPreference; +import android.support.annotation.NonNull; +import android.util.AttributeSet; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.SeekBar; +import android.widget.Spinner; + +import org.solovyev.android.calculator.App; +import org.solovyev.android.calculator.Engine; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.text.NaturalComparator; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class NumberFormatPreference extends DialogPreference { + @Bind(R.id.nf_notation_spinner) + Spinner notationSpinner; + @Bind(R.id.nf_precision_seekbar) + SeekBar precisionSeekBar; + + { + setPersistent(false); + setDialogLayoutResource(R.layout.preference_number_format); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public NumberFormatPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public NumberFormatPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public NumberFormatPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public NumberFormatPreference(Context context) { + super(context); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + ButterKnife.bind(this, view); + + final SharedPreferences preferences = getSharedPreferences(); + precisionSeekBar.setMax(15); + precisionSeekBar.setProgress(Math.max(0, Math.min(15, Engine.Preferences.Output.precision.getPreference(preferences)))); + final ArrayAdapter adapter = makeNumberFormatAdapter(); + notationSpinner.setAdapter(adapter); + notationSpinner.setSelection(indexOf(adapter, Engine.Preferences.Output.notation.getPreference(preferences))); + } + + private int indexOf(ArrayAdapter adapter, Engine.Notation notation) { + for (int i = 0; i < adapter.getCount(); i++) { + if (adapter.getItem(i).notation == notation) { + return i; + } + } + return -1; + } + + @NonNull + private ArrayAdapter makeNumberFormatAdapter() { + final ArrayAdapter adapter = App.makeSimpleSpinnerAdapter(getContext()); + for (Engine.Notation format : Engine.Notation.values()) { + adapter.add(new NotationItem(format)); + } + adapter.sort(NaturalComparator.INSTANCE); + return adapter; + } + + private final class NotationItem { + @NonNull + final Engine.Notation notation; + @NonNull + final String name; + + private NotationItem(@NonNull Engine.Notation notation) { + this.notation = notation; + this.name = getContext().getString(notation.name); + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java index e18bd7cf..b360c9e1 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java @@ -11,6 +11,7 @@ import android.support.v4.app.FragmentActivity; import android.util.SparseArray; import android.view.View; import android.widget.ListView; + import org.solovyev.android.calculator.AdView; import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; @@ -24,11 +25,12 @@ import org.solovyev.android.checkout.ProductTypes; import org.solovyev.android.checkout.RequestListener; import org.solovyev.android.wizard.Wizards; +import java.util.Arrays; +import java.util.List; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; -import java.util.Arrays; -import java.util.List; import static org.solovyev.android.calculator.App.cast; import static org.solovyev.android.calculator.wizard.CalculatorWizards.DEFAULT_WIZARD_FLOW; diff --git a/app/src/main/java/org/solovyev/android/calculator/text/NaturalComparator.java b/app/src/main/java/org/solovyev/android/calculator/text/NaturalComparator.java new file mode 100644 index 00000000..bf219dfe --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/text/NaturalComparator.java @@ -0,0 +1,12 @@ +package org.solovyev.android.calculator.text; + +import java.util.Comparator; + +public class NaturalComparator implements Comparator { + public static final NaturalComparator INSTANCE = new NaturalComparator(); + + @Override + public int compare(Object lhs, Object rhs) { + return lhs.toString().compareTo(rhs.toString()); + } +} diff --git a/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java b/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java new file mode 100644 index 00000000..eed1180c --- /dev/null +++ b/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java @@ -0,0 +1,224 @@ +package org.solovyev.android.views; + +import android.animation.ObjectAnimator; +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.Build; +import android.util.AttributeSet; +import android.view.animation.DecelerateInterpolator; +import android.widget.SeekBar; + +import org.solovyev.android.Check; +import org.solovyev.android.calculator.R; + +/** + * SeekBar for discrete values with a label displayed underneath the active tick + */ +public class DiscreteSeekBar extends SeekBar { + // Duration of how quick the SeekBar thumb should snap to its destination value + private static final int THUMB_SNAP_DURATION_TIME = 100; + private final Paint mPaint = new Paint(); + private ObjectAnimator mObjectAnimator; + private OnChangeListener mOnChangeListener; + private int mCurrentTick = 0; + private CharSequence[] mTickLabels; + private ColorStateList mLabelColor; + + public DiscreteSeekBar(Context context) { + super(context); + init(context, null, 0); + } + + public DiscreteSeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public DiscreteSeekBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + private void init(Context context, AttributeSet attrs, int defStyle) { + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.DiscreteSeekBar, defStyle, 0); + mTickLabels = a.getTextArray(R.styleable.DiscreteSeekBar_values); + final int labelsSize = a.getDimensionPixelSize(R.styleable.DiscreteSeekBar_labelsSize, 0); + final ColorStateList labelsColor = a.getColorStateList(R.styleable.DiscreteSeekBar_labelsColor); + a.recycle(); + + Check.isNotNull(mTickLabels); + Check.isTrue(mTickLabels.length > 0); + Check.isTrue(labelsSize > 0); + + mPaint.setStyle(Paint.Style.FILL); + mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); + mPaint.setTextSize(labelsSize); + + if (labelsColor != null) { + setLabelColor(labelsColor); + } else { + mPaint.setColor(Color.BLACK); + } + + // Extend the bottom padding to include tick label height (including descent in order to not + // clip glyphs that extends below the baseline). + Paint.FontMetricsInt fi = mPaint.getFontMetricsInt(); + setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), + getPaddingBottom() + labelsSize + fi.descent); + + super.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + cancelAnimator(); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void cancelAnimator() { + if (mObjectAnimator != null) { + mObjectAnimator.cancel(); + } + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + mCurrentTick = getClosestTick(seekBar.getProgress()); + final int endProgress = getProgressForTick(mCurrentTick); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + startAnimator(seekBar, endProgress); + } else { + seekBar.setProgress(endProgress); + } + if (mOnChangeListener != null) { + mOnChangeListener.onValueChanged(mCurrentTick); + } + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + private void startAnimator(SeekBar seekBar, int endProgress) { + mObjectAnimator = ObjectAnimator.ofInt( + seekBar, "progress", seekBar.getProgress(), endProgress); + mObjectAnimator.setInterpolator(new DecelerateInterpolator()); + mObjectAnimator.setDuration(THUMB_SNAP_DURATION_TIME); + mObjectAnimator.start(); + } + }); + } + + private int getClosestTick(int progress) { + float normalizedValue = (float) progress / getMax(); + return Math.round(normalizedValue * getMaxTick()); + } + + private int getProgressForTick(int tick) { + return (getMax() / getMaxTick()) * tick; + } + + @Override + public void setOnSeekBarChangeListener(OnSeekBarChangeListener seekBarChangeListener) { + // It doesn't make sense to expose the interface for listening to intermediate changes. + Check.isTrue(false); + } + + /** + * Get the largest tick value the SeekBar can represent + * + * @return maximum tick value + */ + public int getMaxTick() { + return mTickLabels.length - 1; + } + + /** + * Set listener for observing value changes + * + * @param onChangeListener listener that should receive updates + */ + public void setOnChangeListener(OnChangeListener onChangeListener) { + mOnChangeListener = onChangeListener; + } + + /** + * Set tick value + * + * @param tickValue tick value in range [0, maxTick] + */ + public void setTickValue(int tickValue) { + Check.isTrue(tickValue >= 0); + Check.isTrue(tickValue <= getMaxTick()); + mCurrentTick = tickValue; + setProgress(getProgressForTick(mCurrentTick)); + } + + public void setLabelColor(int color) { + mLabelColor = ColorStateList.valueOf(color); + updateLabelColor(); + } + + public void setLabelColor(ColorStateList colors) { + mLabelColor = colors; + updateLabelColor(); + } + + private void updateLabelColor() { + int color = mLabelColor.getColorForState(getDrawableState(), Color.BLACK); + if (color != mPaint.getColor()) { + mPaint.setColor(color); + invalidate(); + } + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + updateLabelColor(); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final float sliderWidth = getWidth() - getPaddingRight() - getPaddingLeft(); + final float sliderStepSize = sliderWidth / getMaxTick(); + int closestTick = getClosestTick(getProgress()); + String text = mTickLabels[closestTick].toString(); + final float startOffset = getPaddingLeft(); + final float tickLabelWidth = mPaint.measureText(text); + final float tickPos = sliderStepSize * closestTick; + final float labelOffset; + // First step description text should be anchored with its left edge just + // below the slider start tick. The last step description should be anchored + // to the right just under the end tick. Tick labels in between are centered below + // each tick. + if (closestTick == 0) { + labelOffset = startOffset; + } else if (closestTick == getMaxTick()) { + labelOffset = startOffset + sliderWidth - tickLabelWidth; + } else { + labelOffset = startOffset + tickPos - tickLabelWidth / 2; + } + // Text position is drawn from bottom left, with bottom at the font baseline. We need to + // offset by the descent to cover e.g 'g' that extends below the baseline. + final Paint.FontMetricsInt m = mPaint.getFontMetricsInt(); + final int lowestPosForFullGlyphCoverage = getHeight() - m.descent; + canvas.drawText(text, labelOffset, lowestPosForFullGlyphCoverage, mPaint); + } + + /** + * Listener for observing tick changes + */ + public interface OnChangeListener { + void onValueChanged(int selectedTick); + } +} diff --git a/app/src/main/res/layout/fragment_plot_function_edit.xml b/app/src/main/res/layout/fragment_plot_function_edit.xml index cebfc31a..eecacbf3 100644 --- a/app/src/main/res/layout/fragment_plot_function_edit.xml +++ b/app/src/main/res/layout/fragment_plot_function_edit.xml @@ -59,11 +59,9 @@ @@ -74,11 +72,9 @@ diff --git a/app/src/main/res/layout/preference_number_format.xml b/app/src/main/res/layout/preference_number_format.xml new file mode 100644 index 00000000..fb1478ea --- /dev/null +++ b/app/src/main/res/layout/preference_number_format.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs_dsb.xml b/app/src/main/res/values/attrs_dsb.xml new file mode 100644 index 00000000..1c26d503 --- /dev/null +++ b/app/src/main/res/values/attrs_dsb.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index b908d698..fcca4323 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -319,6 +319,11 @@ gone + + 16sp 14sp \ No newline at end of file diff --git a/app/src/main/res/values/text_non_translatable.xml b/app/src/main/res/values/text_non_translatable.xml index c7026931..85d6359d 100644 --- a/app/src/main/res/values/text_non_translatable.xml +++ b/app/src/main/res/values/text_non_translatable.xml @@ -34,6 +34,5 @@ 13 14 15 - 16 \ No newline at end of file diff --git a/app/src/main/res/values/text_strings.xml b/app/src/main/res/values/text_strings.xml index 1c1c5868..becee1e2 100644 --- a/app/src/main/res/values/text_strings.xml +++ b/app/src/main/res/values/text_strings.xml @@ -124,4 +124,7 @@ Angles Radix Numeral system + Simple + Engineering + Scientific diff --git a/app/src/main/res/xml/preferences_calculations.xml b/app/src/main/res/xml/preferences_calculations.xml index 4aeb0433..bffa19a4 100644 --- a/app/src/main/res/xml/preferences_calculations.xml +++ b/app/src/main/res/xml/preferences_calculations.xml @@ -24,11 +24,9 @@ - + Date: Thu, 28 Apr 2016 18:40:11 +0200 Subject: [PATCH 02/16] fixup! Number format preference --- .../solovyev/android/calculator/Engine.java | 7 +- .../calculator/{converter => }/Named.java | 8 +- .../converter/ConverterFragment.java | 1 + .../calculator/converter/Convertible.java | 2 + .../converter/ConvertibleDimension.java | 2 + .../converter/NumeralBaseConvertible.java | 3 + .../converter/NumeralBaseDimension.java | 2 + .../calculator/converter/UnitConvertible.java | 3 + .../calculator/converter/UnitDimension.java | 2 + .../preferences/NumberFormatPreference.java | 75 ++++++++++++------- .../android/views/DiscreteSeekBar.java | 14 ++-- .../res/layout/preference_number_format.xml | 11 +++ app/src/main/res/values/text_strings.xml | 2 +- 13 files changed, 92 insertions(+), 40 deletions(-) rename app/src/main/java/org/solovyev/android/calculator/{converter => }/Named.java (79%) diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index 36ceb743..dae12ad4 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -238,7 +238,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } public enum Notation { - simple(Real.NumberFormat.FSE_NONE, R.string.cpp_number_format_simple), + dec(Real.NumberFormat.FSE_NONE, R.string.cpp_number_format_dec), eng(Real.NumberFormat.FSE_ENG, R.string.cpp_number_format_eng), sci(Real.NumberFormat.FSE_SCI, R.string.cpp_number_format_sci); @@ -260,6 +260,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } public static class Preferences { + // todo serso: move to Output public static final StringPreference groupingSeparator = StringPreference.of("engine.groupingSeparator", String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT)); public static final StringPreference multiplicationSign = StringPreference.of("engine.multiplicationSign", "×"); public static final StringPreference numeralBase = StringPreference.ofTypedValue("engine.numeralBase", "dec", EnumMapper.of(NumeralBase.class)); @@ -275,6 +276,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene preferenceKeys.add(Output.precision.getKey()); preferenceKeys.add(Output.scientificNotation.getKey()); preferenceKeys.add(Output.round.getKey()); + preferenceKeys.add(Output.notation.getKey()); } @Nonnull @@ -284,9 +286,10 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static class Output { public static final StringPreference precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class)); + // todo serso: remove public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false); public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); - public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.simple, Notation.class); + public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/Named.java b/app/src/main/java/org/solovyev/android/calculator/Named.java similarity index 79% rename from app/src/main/java/org/solovyev/android/calculator/converter/Named.java rename to app/src/main/java/org/solovyev/android/calculator/Named.java index c22059ad..bea042f6 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/Named.java +++ b/app/src/main/java/org/solovyev/android/calculator/Named.java @@ -1,4 +1,4 @@ -package org.solovyev.android.calculator.converter; +package org.solovyev.android.calculator; import android.content.Context; import android.support.annotation.NonNull; @@ -6,7 +6,7 @@ import android.support.annotation.StringRes; import javax.annotation.Nonnull; -class Named { +public class Named { @NonNull public final T item; @NonNull @@ -18,12 +18,12 @@ class Named { } @NonNull - static Named create(@NonNull T item, @Nonnull String name) { + public static Named create(@NonNull T item, @Nonnull String name) { return new Named(item, name); } @NonNull - static Named create(@NonNull T item, @StringRes int name, @NonNull Context context) { + public static Named create(@NonNull T item, @StringRes int name, @NonNull Context context) { return create(item, name == 0 ? item.toString() : context.getString(name)); } diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java b/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java index 448a6b8d..275f5173 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/ConverterFragment.java @@ -36,6 +36,7 @@ import org.solovyev.android.calculator.BaseDialogFragment; import org.solovyev.android.calculator.Clipboard; import org.solovyev.android.calculator.Editor; import org.solovyev.android.calculator.Keyboard; +import org.solovyev.android.calculator.Named; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.keyboard.FloatingKeyboard; import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow; diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/Convertible.java b/app/src/main/java/org/solovyev/android/calculator/converter/Convertible.java index d02017dc..701fe7b0 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/Convertible.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/Convertible.java @@ -3,6 +3,8 @@ package org.solovyev.android.calculator.converter; import android.content.Context; import android.support.annotation.NonNull; +import org.solovyev.android.calculator.Named; + interface Convertible { @NonNull String convert(@NonNull Convertible to, @NonNull String value) throws NumberFormatException; diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/ConvertibleDimension.java b/app/src/main/java/org/solovyev/android/calculator/converter/ConvertibleDimension.java index f33b6f1b..f945b4dc 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/ConvertibleDimension.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/ConvertibleDimension.java @@ -3,6 +3,8 @@ package org.solovyev.android.calculator.converter; import android.content.Context; import android.support.annotation.NonNull; +import org.solovyev.android.calculator.Named; + import java.util.List; public interface ConvertibleDimension { diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseConvertible.java b/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseConvertible.java index f211340b..5c5dc63c 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseConvertible.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseConvertible.java @@ -2,6 +2,9 @@ package org.solovyev.android.calculator.converter; import android.content.Context; import android.support.annotation.NonNull; + +import org.solovyev.android.calculator.Named; + import jscl.JsclMathEngine; import jscl.NumeralBase; import midpcalc.Real; diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseDimension.java b/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseDimension.java index 1834e257..8368101e 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseDimension.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/NumeralBaseDimension.java @@ -3,6 +3,8 @@ package org.solovyev.android.calculator.converter; import android.content.Context; import android.support.annotation.NonNull; import jscl.NumeralBase; + +import org.solovyev.android.calculator.Named; import org.solovyev.android.calculator.R; import java.util.ArrayList; diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/UnitConvertible.java b/app/src/main/java/org/solovyev/android/calculator/converter/UnitConvertible.java index e8b3dded..91aadf3f 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/UnitConvertible.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/UnitConvertible.java @@ -2,6 +2,9 @@ package org.solovyev.android.calculator.converter; import android.content.Context; import android.support.annotation.NonNull; + +import org.solovyev.android.calculator.Named; + import jscl.JsclMathEngine; import jscl.NumeralBase; diff --git a/app/src/main/java/org/solovyev/android/calculator/converter/UnitDimension.java b/app/src/main/java/org/solovyev/android/calculator/converter/UnitDimension.java index 6dc91974..9fbd4b35 100644 --- a/app/src/main/java/org/solovyev/android/calculator/converter/UnitDimension.java +++ b/app/src/main/java/org/solovyev/android/calculator/converter/UnitDimension.java @@ -4,6 +4,8 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; + +import org.solovyev.android.calculator.Named; import org.solovyev.android.calculator.R; import javax.measure.unit.Dimension; diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index 2edb24db..d5ecf45f 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -9,22 +9,29 @@ import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.View; import android.widget.ArrayAdapter; -import android.widget.SeekBar; import android.widget.Spinner; import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.Engine; +import org.solovyev.android.calculator.Named; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.text.NaturalComparator; +import org.solovyev.android.views.DiscreteSeekBar; import butterknife.Bind; import butterknife.ButterKnife; +import static org.solovyev.android.calculator.Engine.Preferences.Output; + public class NumberFormatPreference extends DialogPreference { @Bind(R.id.nf_notation_spinner) Spinner notationSpinner; + ArrayAdapter> notationAdapter; @Bind(R.id.nf_precision_seekbar) - SeekBar precisionSeekBar; + DiscreteSeekBar precisionSeekBar; + @Bind(R.id.nf_separator_spinner) + Spinner separatorSpinner; + ArrayAdapter> separatorAdapter; { setPersistent(false); @@ -55,16 +62,34 @@ public class NumberFormatPreference extends DialogPreference { ButterKnife.bind(this, view); final SharedPreferences preferences = getSharedPreferences(); - precisionSeekBar.setMax(15); - precisionSeekBar.setProgress(Math.max(0, Math.min(15, Engine.Preferences.Output.precision.getPreference(preferences)))); - final ArrayAdapter adapter = makeNumberFormatAdapter(); - notationSpinner.setAdapter(adapter); - notationSpinner.setSelection(indexOf(adapter, Engine.Preferences.Output.notation.getPreference(preferences))); + final int maxPrecision = precisionSeekBar.getMaxTick(); + precisionSeekBar.setMax(maxPrecision); + precisionSeekBar.setCurrentTick(Math.max(0, Math.min(maxPrecision, Output.precision.getPreference(preferences)))); + notationAdapter = makeNotationAdapter(); + notationSpinner.setAdapter(notationAdapter); + notationSpinner.setSelection(indexOf(notationAdapter, Output.notation.getPreference(preferences))); + + separatorAdapter = makeSeparatorAdapter(); + separatorSpinner.setAdapter(separatorAdapter); + separatorSpinner.setSelection(indexOf(separatorAdapter, Engine.Preferences.groupingSeparator.getPreference(preferences))); } - private int indexOf(ArrayAdapter adapter, Engine.Notation notation) { + @Override + protected void onDialogClosed(boolean save) { + super.onDialogClosed(save); + if (!save) { + return; + } + final SharedPreferences.Editor editor = getSharedPreferences().edit(); + Output.precision.putPreference(editor, precisionSeekBar.getCurrentTick()); + Output.notation.putPreference(editor, notationAdapter.getItem(notationSpinner.getSelectedItemPosition()).item); + Engine.Preferences.groupingSeparator.putPreference(editor, separatorAdapter.getItem(separatorSpinner.getSelectedItemPosition()).item); + editor.apply(); + } + + private int indexOf(ArrayAdapter> adapter, T item) { for (int i = 0; i < adapter.getCount(); i++) { - if (adapter.getItem(i).notation == notation) { + if (adapter.getItem(i).item.equals(item)) { return i; } } @@ -72,29 +97,23 @@ public class NumberFormatPreference extends DialogPreference { } @NonNull - private ArrayAdapter makeNumberFormatAdapter() { - final ArrayAdapter adapter = App.makeSimpleSpinnerAdapter(getContext()); - for (Engine.Notation format : Engine.Notation.values()) { - adapter.add(new NotationItem(format)); + private ArrayAdapter> makeNotationAdapter() { + final Context context = getContext(); + final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); + for (Engine.Notation notation : Engine.Notation.values()) { + adapter.add(Named.create(notation, notation.name, context)); } adapter.sort(NaturalComparator.INSTANCE); return adapter; } - private final class NotationItem { - @NonNull - final Engine.Notation notation; - @NonNull - final String name; - - private NotationItem(@NonNull Engine.Notation notation) { - this.notation = notation; - this.name = getContext().getString(notation.name); - } - - @Override - public String toString() { - return name; - } + @NonNull + private ArrayAdapter> makeSeparatorAdapter() { + final Context context = getContext(); + final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); + adapter.add(Named.create("", R.string.p_grouping_separator_no, context)); + adapter.add(Named.create("'", R.string.p_grouping_separator_apostrophe, context)); + adapter.add(Named.create(" ", R.string.p_grouping_separator_space, context)); + return adapter; } } diff --git a/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java b/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java index eed1180c..088f309e 100644 --- a/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java +++ b/app/src/main/java/org/solovyev/android/views/DiscreteSeekBar.java @@ -152,15 +152,19 @@ public class DiscreteSeekBar extends SeekBar { /** * Set tick value * - * @param tickValue tick value in range [0, maxTick] + * @param tick tick value in range [0, maxTick] */ - public void setTickValue(int tickValue) { - Check.isTrue(tickValue >= 0); - Check.isTrue(tickValue <= getMaxTick()); - mCurrentTick = tickValue; + public void setCurrentTick(int tick) { + Check.isTrue(tick >= 0); + Check.isTrue(tick <= getMaxTick()); + mCurrentTick = tick; setProgress(getProgressForTick(mCurrentTick)); } + public int getCurrentTick() { + return mCurrentTick; + } + public void setLabelColor(int color) { mLabelColor = ColorStateList.valueOf(color); updateLabelColor(); diff --git a/app/src/main/res/layout/preference_number_format.xml b/app/src/main/res/layout/preference_number_format.xml index fb1478ea..14921c8e 100644 --- a/app/src/main/res/layout/preference_number_format.xml +++ b/app/src/main/res/layout/preference_number_format.xml @@ -31,4 +31,15 @@ app:labelsSize="12sp" app:values="@array/cpp_prefs_precisions"/> + + + + \ No newline at end of file diff --git a/app/src/main/res/values/text_strings.xml b/app/src/main/res/values/text_strings.xml index becee1e2..446c5885 100644 --- a/app/src/main/res/values/text_strings.xml +++ b/app/src/main/res/values/text_strings.xml @@ -124,7 +124,7 @@ Angles Radix Numeral system - Simple + Decimal Engineering Scientific From f618f2cd446656794c92447526e701c7dfad23b0 Mon Sep 17 00:00:00 2001 From: serso Date: Fri, 29 Apr 2016 18:52:25 +0200 Subject: [PATCH 03/16] Fix font issues --- .../android/calculator/BaseActivity.java | 34 +++++++++---------- .../calculator/BaseDialogFragment.java | 4 +++ .../android/calculator/BaseFragment.java | 17 +++++----- .../floating/FloatingCalculatorView.java | 2 +- .../calculator/keyboard/BaseKeyboardUi.java | 4 --- .../wizard/ChooseModeWizardStep.java | 2 -- .../wizard/ChooseThemeWizardStep.java | 8 +++-- .../wizard/DragButtonWizardStep.java | 1 - .../calculator/wizard/WizardFragment.java | 10 ++++++ 9 files changed, 44 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseActivity.java b/app/src/main/java/org/solovyev/android/calculator/BaseActivity.java index b17fc27d..bf170efc 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseActivity.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseActivity.java @@ -87,7 +87,13 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr public static void setFont(@Nonnull View view, @Nonnull Typeface newTypeface) { if (view instanceof TextView) { - setFont((TextView) view, newTypeface); + final TextView textView = (TextView) view; + final Typeface oldTypeface = textView.getTypeface(); + if (oldTypeface == newTypeface) { + return; + } + final int style = oldTypeface != null ? oldTypeface.getStyle() : Typeface.NORMAL; + textView.setTypeface(newTypeface, style); } else if (view instanceof DirectionDragImageButton) { ((DirectionDragImageButton) view).setTypeface(newTypeface); } @@ -98,15 +104,6 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr return mode; } - public static void setFont(@Nonnull TextView view, @Nonnull Typeface newTypeface) { - final Typeface oldTypeface = view.getTypeface(); - if (oldTypeface == newTypeface) { - return; - } - final int style = oldTypeface != null ? oldTypeface.getStyle() : Typeface.NORMAL; - view.setTypeface(newTypeface, style); - } - public boolean restartIfModeChanged() { final Preferences.Gui.Mode newMode = Preferences.Gui.mode.getPreference(preferences); if (newMode != mode) { @@ -162,7 +159,7 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr } ButterKnife.bind(this, this); - fixFonts(mainView); + fixFonts(mainView, typeface); initToolbar(); populateTabs(tabs); tabs.onCreate(); @@ -285,14 +282,15 @@ public abstract class BaseActivity extends AppCompatActivity implements SharedPr fab.setOnClickListener(listener); } - protected void fixFonts(@Nonnull View root) { - // some devices ship own fonts which causes issues with rendering. Let's use our own font for all text views - App.processViewsOfType(root, TextView.class, new App.ViewProcessor() { - @Override - public void process(@Nonnull TextView view) { - setFont(view, typeface); + public static void fixFonts(@Nonnull View view, @Nonnull Typeface typeface) { + if (view instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) view; + for (int index = 0; index < group.getChildCount(); index++) { + fixFonts(group.getChildAt(index), typeface); } - }); + } else { + setFont(view, typeface); + } } @Override diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseDialogFragment.java b/app/src/main/java/org/solovyev/android/calculator/BaseDialogFragment.java index 93758196..afe8f280 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseDialogFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseDialogFragment.java @@ -3,6 +3,7 @@ package org.solovyev.android.calculator; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -29,6 +30,8 @@ public abstract class BaseDialogFragment extends DialogFragment implements View. protected SharedPreferences preferences; @Inject Ga ga; + @Inject + Typeface typeface; @Nullable private Button positiveButton; @Nullable @@ -57,6 +60,7 @@ public abstract class BaseDialogFragment extends DialogFragment implements View. if (view != null) { final int spacing = context.getResources().getDimensionPixelSize(R.dimen.cpp_dialog_spacing); b.setView(view, spacing, spacing, spacing, spacing); + BaseActivity.fixFonts(view, typeface); } onPrepareDialog(b); final AlertDialog dialog = b.create(); diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java b/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java index 561cf449..81d93632 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java @@ -1,31 +1,29 @@ package org.solovyev.android.calculator; -import static android.view.Menu.NONE; -import static org.solovyev.android.calculator.App.cast; - +import android.graphics.Typeface; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.support.v4.app.Fragment; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - +import android.view.*; import org.solovyev.android.calculator.ads.AdUi; import org.solovyev.android.plotter.Check; import javax.annotation.Nonnull; import javax.inject.Inject; +import static android.view.Menu.NONE; +import static org.solovyev.android.calculator.App.cast; + public abstract class BaseFragment extends Fragment { private final int layout; @Inject AdUi adUi; + @Inject + Typeface typeface; protected BaseFragment(@LayoutRes int layout) { this.layout = layout; @@ -61,6 +59,7 @@ public abstract class BaseFragment extends Fragment { Bundle savedInstanceState) { final View view = inflater.inflate(layout, container, false); adUi.onCreateView(view); + BaseActivity.fixFonts(view, typeface); return view; } diff --git a/app/src/main/java/org/solovyev/android/calculator/floating/FloatingCalculatorView.java b/app/src/main/java/org/solovyev/android/calculator/floating/FloatingCalculatorView.java index 85109d2e..90db8575 100644 --- a/app/src/main/java/org/solovyev/android/calculator/floating/FloatingCalculatorView.java +++ b/app/src/main/java/org/solovyev/android/calculator/floating/FloatingCalculatorView.java @@ -266,6 +266,7 @@ public class FloatingCalculatorView { final Preferences.SimpleTheme resolvedTheme = theme.resolveThemeFor(appTheme); this.context = new ContextThemeWrapper(context, resolvedTheme.light ? R.style.Cpp_Theme_Light : R.style.Cpp_Theme); this.root = View.inflate(this.context, theme.getOnscreenLayout(appTheme), null); + BaseActivity.fixFonts(this.root, typeface); final State persistedState = State.fromPrefs(myPreferences); if (persistedState != null) { this.state = persistedState; @@ -357,7 +358,6 @@ public class FloatingCalculatorView { } else { BaseKeyboardUi.adjustButton(button); } - BaseActivity.setFont(button, typeface); } final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); diff --git a/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java b/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java index 9e71605d..f0bdf05b 100644 --- a/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java +++ b/app/src/main/java/org/solovyev/android/calculator/keyboard/BaseKeyboardUi.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; -import android.graphics.Typeface; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.text.TextUtils; @@ -47,8 +46,6 @@ public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPrefer @Inject SharedPreferences preferences; @Inject - Typeface typeface; - @Inject Keyboard keyboard; @Inject Editor editor; @@ -133,7 +130,6 @@ public abstract class BaseKeyboardUi implements SharedPreferences.OnSharedPrefer // we call android.view.View.performHapticFeedback(int, int) from #onClick button.setHapticFeedbackEnabled(false); button.setOnClickListener(this); - BaseActivity.setFont(button, typeface); } protected final void prepareButton(@Nullable DirectionDragImageButton button) { diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseModeWizardStep.java b/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseModeWizardStep.java index eaa60c57..5db52c41 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseModeWizardStep.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseModeWizardStep.java @@ -28,7 +28,6 @@ import android.view.View; import android.widget.AdapterView; import android.widget.Spinner; import android.widget.TextView; -import org.solovyev.android.calculator.BaseActivity; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.keyboard.BaseKeyboardUi; @@ -73,7 +72,6 @@ public class ChooseModeWizardStep extends WizardFragment implements AdapterView. spinner.setOnItemSelectedListener(this); button = (DirectionDragButton) root.findViewById(R.id.wizard_mode_button); - BaseActivity.setFont(button, typeface); Adjuster.adjustText(button, BaseKeyboardUi.getTextScale(getActivity())); description = (TextView) root.findViewById(R.id.wizard_mode_description); updateDescription(mode); diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseThemeWizardStep.java b/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseThemeWizardStep.java index 78244e8b..cc3551d9 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseThemeWizardStep.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/ChooseThemeWizardStep.java @@ -30,6 +30,7 @@ import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.Spinner; import org.solovyev.android.calculator.App; +import org.solovyev.android.calculator.BaseActivity; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.keyboard.BaseKeyboardUi; @@ -69,7 +70,7 @@ public class ChooseThemeWizardStep extends WizardFragment implements AdapterView spinner.setOnItemSelectedListener(this); preview = (FrameLayout) root.findViewById(R.id.wizard_theme_preview); - updateImage(theme); + updatePreview(theme); } private int findPosition(@Nonnull Preferences.Gui.Theme theme) { @@ -82,7 +83,7 @@ public class ChooseThemeWizardStep extends WizardFragment implements AdapterView return 0; } - private void updateImage(@Nonnull Preferences.Gui.Theme theme) { + private void updatePreview(@Nonnull Preferences.Gui.Theme theme) { preview.removeAllViews(); final ContextThemeWrapper context = new ContextThemeWrapper(getActivity(), theme.theme); LayoutInflater.from(context).inflate(R.layout.cpp_wizard_step_choose_theme_preview, preview); @@ -90,6 +91,7 @@ public class ChooseThemeWizardStep extends WizardFragment implements AdapterView @Override public void process(@Nonnull View view) { BaseKeyboardUi.adjustButton(view); + BaseActivity.setFont(view, typeface); } }); } @@ -98,7 +100,7 @@ public class ChooseThemeWizardStep extends WizardFragment implements AdapterView public void onItemSelected(AdapterView parent, View view, int position, long id) { final ThemeUi theme = adapter.getItem(position); Preferences.Gui.theme.putPreference(preferences, theme.theme); - updateImage(theme.theme); + updatePreview(theme.theme); } @Override diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java b/app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java index cd50369f..9aae8364 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java @@ -83,7 +83,6 @@ public class DragButtonWizardStep extends WizardFragment { return false; } }); - BaseActivity.setFont(dragButton, typeface); Adjuster.adjustText(dragButton, BaseKeyboardUi.getTextScale(getActivity())); actionTextView = (TextView) root.findViewById(R.id.wizard_dragbutton_action_textview); if (savedInstanceState != null) { diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java b/app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java index 72fcf175..9a810b2a 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/WizardFragment.java @@ -1,6 +1,7 @@ package org.solovyev.android.calculator.wizard; import android.content.SharedPreferences; +import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.LayoutRes; import android.support.v4.app.Fragment; @@ -10,6 +11,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import org.solovyev.android.calculator.AppComponent; +import org.solovyev.android.calculator.BaseActivity; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.release.ChooseThemeReleaseNoteFragment; import org.solovyev.android.calculator.release.ChooseThemeReleaseNoteStep; @@ -35,6 +37,8 @@ public abstract class WizardFragment extends Fragment implements View.OnClickLis protected TextView prevButton; @Inject SharedPreferences preferences; + @Inject + Typeface typeface; private WizardStep step; @Override @@ -112,6 +116,12 @@ public abstract class WizardFragment extends Fragment implements View.OnClickLis return view; } + @Override + public void onViewCreated(View view, @android.support.annotation.Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + BaseActivity.fixFonts(view, typeface); + } + protected final void setupNextButton(int textResId) { assert nextButton != null; nextButton.setText(textResId); From 70abeeeea5d4673491a15fa377c45017e37c57b7 Mon Sep 17 00:00:00 2001 From: serso Date: Sat, 30 Apr 2016 09:32:47 +0200 Subject: [PATCH 04/16] Save history even when calculation doesn't happen on-the-fly --- .../android/calculator/Calculator.java | 10 ++------- .../android/calculator/history/History.java | 5 +++-- .../calculator/history/RecentHistory.java | 22 ++++++++++++++++--- .../calculator/BaseCalculatorTest.java | 4 ++-- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/Calculator.java b/app/src/main/java/org/solovyev/android/calculator/Calculator.java index f6a3e50c..4ca7f32a 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Calculator.java +++ b/app/src/main/java/org/solovyev/android/calculator/Calculator.java @@ -102,17 +102,12 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis public void evaluate() { final EditorState state = editor.getState(); - evaluate(JsclOperation.numeric, state.getTextString()); + evaluate(JsclOperation.numeric, state.getTextString(), state.sequence); } public void simplify() { final EditorState state = editor.getState(); - evaluate(JsclOperation.simplify, state.getTextString()); - } - - public long evaluate(@Nonnull final JsclOperation operation, - @Nonnull final String expression) { - return evaluate(operation, expression, nextSequence()); + evaluate(JsclOperation.simplify, state.getTextString(), state.sequence); } public long evaluate(@Nonnull final JsclOperation operation, @Nonnull final String expression, @@ -343,5 +338,4 @@ public class Calculator implements SharedPreferences.OnSharedPreferenceChangeLis public static long nextSequence() { return SEQUENCER.incrementAndGet(); } - } diff --git a/app/src/main/java/org/solovyev/android/calculator/history/History.java b/app/src/main/java/org/solovyev/android/calculator/history/History.java index ca6408c8..e4b90a9f 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/History.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/History.java @@ -254,8 +254,9 @@ public class History { // don't add empty states to empty history return; } - recent.add(state); - onRecentChanged(new AddedEvent(state, true)); + if (recent.add(state)) { + onRecentChanged(new AddedEvent(state, true)); + } } public void updateSaved(@Nonnull HistoryState state) { diff --git a/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java b/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java index 45022de8..5cd58044 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/RecentHistory.java @@ -2,7 +2,6 @@ package org.solovyev.android.calculator.history; import android.support.annotation.NonNull; import android.support.annotation.Nullable; - import org.solovyev.android.Check; import java.util.Collections; @@ -17,10 +16,13 @@ public class RecentHistory { private final List list = new LinkedList<>(); private int current = -1; - public void add(@NonNull HistoryState state) { + public boolean add(@NonNull HistoryState state) { Check.isMainThread(); if (isCurrent(state)) { - return; + return false; + } + if (updateState(state)) { + return true; } while (current != list.size() - 1) { list.remove(list.size() - 1); @@ -28,6 +30,20 @@ public class RecentHistory { list.add(state); current++; trim(); + return true; + } + + private boolean updateState(@NonNull HistoryState state) { + if (current == -1) { + return false; + } + final HistoryState old = list.get(current); + if (old.display.sequence == state.display.sequence && old.editor.sequence == state.editor.sequence) { + // if recalculation is taking place we need to update current history item + list.set(current, state); + return true; + } + return false; } private void trim() { diff --git a/app/src/test/java/org/solovyev/android/calculator/BaseCalculatorTest.java b/app/src/test/java/org/solovyev/android/calculator/BaseCalculatorTest.java index d5617970..93cdbdbb 100644 --- a/app/src/test/java/org/solovyev/android/calculator/BaseCalculatorTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/BaseCalculatorTest.java @@ -32,7 +32,7 @@ public abstract class BaseCalculatorTest { } protected final void assertError(@NonNull String expression) { - calculator.evaluate(numeric, expression); + calculator.evaluate(numeric, expression, 0); verify(calculator.bus, atLeastOnce()).post(argThat(failed())); } @@ -55,7 +55,7 @@ public abstract class BaseCalculatorTest { } protected final void assertEval(@NonNull final String expected, @NonNull final String expression, final JsclOperation operation) { - calculator.evaluate(operation, expression); + calculator.evaluate(operation, expression, 0); verify(calculator.bus, atLeastOnce()).post(finishedEvent(expected, expression, operation)); } From 545caebc329eedd339d01543632a3c102f7a463b Mon Sep 17 00:00:00 2001 From: serso Date: Sat, 30 Apr 2016 09:38:53 +0200 Subject: [PATCH 05/16] Fix fonts even for list views --- .../org/solovyev/android/calculator/BaseFragment.java | 2 +- .../calculator/entities/BaseEntitiesFragment.java | 6 ++---- .../android/calculator/history/BaseHistoryFragment.java | 4 ++++ .../android/calculator/plot/PlotFunctionsFragment.java | 9 +++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java b/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java index 81d93632..ac09fc8c 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseFragment.java @@ -23,7 +23,7 @@ public abstract class BaseFragment extends Fragment { @Inject AdUi adUi; @Inject - Typeface typeface; + public Typeface typeface; protected BaseFragment(@LayoutRes int layout) { this.layout = layout; diff --git a/app/src/main/java/org/solovyev/android/calculator/entities/BaseEntitiesFragment.java b/app/src/main/java/org/solovyev/android/calculator/entities/BaseEntitiesFragment.java index 8f893ea7..ae3794d2 100644 --- a/app/src/main/java/org/solovyev/android/calculator/entities/BaseEntitiesFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/entities/BaseEntitiesFragment.java @@ -36,10 +36,7 @@ import android.widget.TextView; import butterknife.Bind; import butterknife.ButterKnife; import org.solovyev.android.Check; -import org.solovyev.android.calculator.BaseFragment; -import org.solovyev.android.calculator.CalculatorActivity; -import org.solovyev.android.calculator.Keyboard; -import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.*; import org.solovyev.android.views.DividerItemDecoration; import org.solovyev.common.math.MathEntity; import org.solovyev.common.text.Strings; @@ -205,6 +202,7 @@ public abstract class BaseEntitiesFragment extends BaseFra public EntityViewHolder(@Nonnull View view) { super(view); + BaseActivity.fixFonts(itemView, typeface); ButterKnife.bind(this, view); view.setOnClickListener(this); view.setOnCreateContextMenuListener(this); diff --git a/app/src/main/java/org/solovyev/android/calculator/history/BaseHistoryFragment.java b/app/src/main/java/org/solovyev/android/calculator/history/BaseHistoryFragment.java index 228faf61..6d95a33b 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/BaseHistoryFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/BaseHistoryFragment.java @@ -24,6 +24,7 @@ package org.solovyev.android.calculator.history; import android.app.Activity; import android.content.Context; +import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.FragmentActivity; @@ -59,6 +60,8 @@ public abstract class BaseHistoryFragment extends BaseFragment { Editor editor; @Inject Bus bus; + @Inject + Typeface typeface; @Bind(R.id.history_recyclerview) RecyclerView recyclerView; private HistoryAdapter adapter; @@ -151,6 +154,7 @@ public abstract class BaseHistoryFragment extends BaseFragment { public HistoryViewHolder(View view) { super(view); + BaseActivity.fixFonts(view, typeface); ButterKnife.bind(this, view); view.setOnCreateContextMenuListener(this); view.setOnClickListener(this); diff --git a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java b/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java index cb2f2b9f..5b6efc0a 100644 --- a/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/plot/PlotFunctionsFragment.java @@ -3,6 +3,7 @@ package org.solovyev.android.calculator.plot; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Typeface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -14,10 +15,7 @@ import android.view.*; import android.widget.TextView; import butterknife.Bind; import butterknife.ButterKnife; -import org.solovyev.android.calculator.App; -import org.solovyev.android.calculator.AppComponent; -import org.solovyev.android.calculator.BaseDialogFragment; -import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.*; import org.solovyev.android.plotter.BasePlotterListener; import org.solovyev.android.plotter.PlotFunction; import org.solovyev.android.plotter.PlotIconView; @@ -35,6 +33,8 @@ public class PlotFunctionsFragment extends BaseDialogFragment { @Inject Plotter plotter; + @Inject + Typeface typeface; @NonNull private final PlotterListener plotterListener = new PlotterListener(); private Adapter adapter; @@ -105,6 +105,7 @@ public class PlotFunctionsFragment extends BaseDialogFragment { private ViewHolder(@NonNull View itemView) { super(itemView); + BaseActivity.fixFonts(itemView, typeface); ButterKnife.bind(this, itemView); itemView.setOnClickListener(this); itemView.setOnCreateContextMenuListener(this); From 0f7e5ee3eee1acfa3dc0612b4bb4a798db298b97 Mon Sep 17 00:00:00 2001 From: serso Date: Sat, 30 Apr 2016 10:07:07 +0200 Subject: [PATCH 06/16] Fix non-scrollable toolbar in AboutActivity --- .../calculator/about/AboutFragment.java | 2 +- .../about/ReleaseNotesFragment.java | 2 +- app/src/main/res/layout/about_fragment.xml | 76 ------------------- app/src/main/res/layout/fragment_about.xml | 69 +++++++++++++++++ ...ragment.xml => fragment_release_notes.xml} | 10 +-- 5 files changed, 76 insertions(+), 83 deletions(-) delete mode 100644 app/src/main/res/layout/about_fragment.xml create mode 100644 app/src/main/res/layout/fragment_about.xml rename app/src/main/res/layout/{release_notes_fragment.xml => fragment_release_notes.xml} (77%) diff --git a/app/src/main/java/org/solovyev/android/calculator/about/AboutFragment.java b/app/src/main/java/org/solovyev/android/calculator/about/AboutFragment.java index 33e4e62b..66a8243b 100644 --- a/app/src/main/java/org/solovyev/android/calculator/about/AboutFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/about/AboutFragment.java @@ -50,7 +50,7 @@ public class AboutFragment extends BaseFragment { TextView translatorsView; public AboutFragment() { - super(R.layout.about_fragment); + super(R.layout.fragment_about); } @Override diff --git a/app/src/main/java/org/solovyev/android/calculator/about/ReleaseNotesFragment.java b/app/src/main/java/org/solovyev/android/calculator/about/ReleaseNotesFragment.java index 9cfddf2a..b493a3c0 100644 --- a/app/src/main/java/org/solovyev/android/calculator/about/ReleaseNotesFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/about/ReleaseNotesFragment.java @@ -41,7 +41,7 @@ public class ReleaseNotesFragment extends BaseFragment { TextView text; public ReleaseNotesFragment() { - super(R.layout.release_notes_fragment); + super(R.layout.fragment_release_notes); } @Override diff --git a/app/src/main/res/layout/about_fragment.xml b/app/src/main/res/layout/about_fragment.xml deleted file mode 100644 index 4384cd65..00000000 --- a/app/src/main/res/layout/about_fragment.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml new file mode 100644 index 00000000..a9e711ba --- /dev/null +++ b/app/src/main/res/layout/fragment_about.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/release_notes_fragment.xml b/app/src/main/res/layout/fragment_release_notes.xml similarity index 77% rename from app/src/main/res/layout/release_notes_fragment.xml rename to app/src/main/res/layout/fragment_release_notes.xml index 73ee4e06..5173b6f0 100644 --- a/app/src/main/res/layout/release_notes_fragment.xml +++ b/app/src/main/res/layout/fragment_release_notes.xml @@ -22,16 +22,16 @@ ~ Site: http://se.solovyev.org --> - + app:layout_behavior="@string/appbar_scrolling_view_behavior"> + a:layout_height="wrap_content" /> - \ No newline at end of file + \ No newline at end of file From 1c6651bd4bdcb99ffbbdc8cc72965f2aa440a990 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 13:57:29 +0200 Subject: [PATCH 07/16] Move grouping separator preference to Output section --- .../solovyev/android/calculator/Engine.java | 14 ++++---- .../android/calculator/Preferences.java | 8 +++-- .../android/calculator/history/History.java | 26 ++++++++++----- .../preferences/NumberFormatPreference.java | 4 +-- .../calculator/history/HistoryTest.java | 32 ++++++++++++++----- 5 files changed, 57 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index dae12ad4..2820e4a0 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -174,13 +174,15 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } final SharedPreferences.Editor editor = preferences.edit(); if (oldVersion == 0) { - migratePreference(preferences, Preferences.groupingSeparator, "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator", editor); + migratePreference(preferences, Preferences.Output.separator, "org.solovyev.android.calculator.CalculatorActivity_calc_grouping_separator", editor); migratePreference(preferences, Preferences.multiplicationSign, "org.solovyev.android.calculator.CalculatorActivity_calc_multiplication_sign", editor); migratePreference(preferences, Preferences.numeralBase, "org.solovyev.android.calculator.CalculatorActivity_numeral_bases", editor); migratePreference(preferences, Preferences.angleUnit, "org.solovyev.android.calculator.CalculatorActivity_angle_units", editor); migratePreference(preferences, Preferences.Output.precision, "org.solovyev.android.calculator.CalculatorModel_result_precision", editor); migratePreference(preferences, Preferences.Output.scientificNotation, "calculation.output.science_notation", editor); migratePreference(preferences, Preferences.Output.round, "org.solovyev.android.calculator.CalculatorModel_round_result", editor); + } else if (oldVersion == 1) { + migratePreference(preferences, Preferences.Output.separator, "engine.groupingSeparator", editor); } Preferences.version.putDefault(editor); editor.apply(); @@ -211,7 +213,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene mathEngine.setScienceNotation(Preferences.Output.scientificNotation.getPreference(preferences)); mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences)); - final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences); + final String groupingSeparator = Preferences.Output.separator.getPreference(preferences); if (TextUtils.isEmpty(groupingSeparator)) { mathEngine.setUseGroupingSeparator(false); } else { @@ -260,16 +262,13 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } public static class Preferences { - // todo serso: move to Output - public static final StringPreference groupingSeparator = StringPreference.of("engine.groupingSeparator", String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT)); public static final StringPreference multiplicationSign = StringPreference.of("engine.multiplicationSign", "×"); public static final StringPreference numeralBase = StringPreference.ofTypedValue("engine.numeralBase", "dec", EnumMapper.of(NumeralBase.class)); public static final StringPreference angleUnit = StringPreference.ofTypedValue("engine.angleUnit", "deg", EnumMapper.of(AngleUnit.class)); - public static final Preference version = IntegerPreference.of("engine.version", 1); + public static final Preference version = IntegerPreference.of("engine.version", 2); private static final List preferenceKeys = new ArrayList<>(); static { - preferenceKeys.add(groupingSeparator.getKey()); preferenceKeys.add(multiplicationSign.getKey()); preferenceKeys.add(numeralBase.getKey()); preferenceKeys.add(angleUnit.getKey()); @@ -277,6 +276,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene preferenceKeys.add(Output.scientificNotation.getKey()); preferenceKeys.add(Output.round.getKey()); preferenceKeys.add(Output.notation.getKey()); + preferenceKeys.add(Output.separator.getKey()); } @Nonnull @@ -290,6 +290,8 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false); public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); + public static final StringPreference separator = StringPreference.of("engine.output.separator", String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT)); + } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/Preferences.java b/app/src/main/java/org/solovyev/android/calculator/Preferences.java index 0622d50e..ceb7629a 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Preferences.java +++ b/app/src/main/java/org/solovyev/android/calculator/Preferences.java @@ -53,6 +53,8 @@ import java.util.EnumMap; import java.util.Locale; import java.util.Map; +import jscl.JsclMathEngine; + import static org.solovyev.android.prefs.IntegerPreference.DEF_VALUE; public final class Preferences { @@ -108,7 +110,7 @@ public final class Preferences { } private static void setInitialDefaultValues(@Nonnull Application application, @Nonnull SharedPreferences preferences, @Nonnull SharedPreferences.Editor editor) { - if (!Engine.Preferences.groupingSeparator.isSet(preferences)) { + if (!Engine.Preferences.Output.separator.isSet(preferences)) { final Locale locale = Locale.getDefault(); if (locale != null) { final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); @@ -117,10 +119,10 @@ public final class Preferences { if (index >= 0) { groupingSeparator = MathType.grouping_separator.getTokens().get(index); } else { - groupingSeparator = " "; + groupingSeparator = String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } - Engine.Preferences.groupingSeparator.putPreference(editor, groupingSeparator); + Engine.Preferences.Output.separator.putPreference(editor, groupingSeparator); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/history/History.java b/app/src/main/java/org/solovyev/android/calculator/history/History.java index e4b90a9f..16d5fbac 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/History.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/History.java @@ -27,22 +27,26 @@ import android.content.SharedPreferences; import android.os.Handler; import android.support.annotation.NonNull; import android.text.TextUtils; + import com.google.common.base.Strings; import com.squareup.otto.Bus; import com.squareup.otto.Subscribe; + import org.json.JSONArray; import org.json.JSONException; import org.solovyev.android.Check; -import org.solovyev.android.calculator.*; +import org.solovyev.android.calculator.AppModule; +import org.solovyev.android.calculator.Calculator; +import org.solovyev.android.calculator.Display; +import org.solovyev.android.calculator.DisplayState; +import org.solovyev.android.calculator.Editor; +import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.Engine.Preferences; +import org.solovyev.android.calculator.ErrorReporter; +import org.solovyev.android.calculator.Runnables; import org.solovyev.android.calculator.json.Json; import org.solovyev.android.io.FileSystem; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -51,6 +55,12 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executor; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + import static android.text.TextUtils.isEmpty; @Singleton @@ -302,7 +312,7 @@ public class History { final List result = new LinkedList<>(); - final String groupingSeparator = Preferences.groupingSeparator.getPreference(preferences); + final String separator = Preferences.Output.separator.getPreference(preferences); final List states = recent.asList(); final int statesCount = states.size(); @@ -312,7 +322,7 @@ public class History { final HistoryState newerState = states.get(i); final String olderText = olderState.editor.getTextString(); final String newerText = newerState.editor.getTextString(); - if (streak >= MAX_INTERMEDIATE_STREAK || !isIntermediate(olderText, newerText, groupingSeparator)) { + if (streak >= MAX_INTERMEDIATE_STREAK || !isIntermediate(olderText, newerText, separator)) { result.add(0, olderState); streak = 0; } else { diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index d5ecf45f..e4cbaee7 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -71,7 +71,7 @@ public class NumberFormatPreference extends DialogPreference { separatorAdapter = makeSeparatorAdapter(); separatorSpinner.setAdapter(separatorAdapter); - separatorSpinner.setSelection(indexOf(separatorAdapter, Engine.Preferences.groupingSeparator.getPreference(preferences))); + separatorSpinner.setSelection(indexOf(separatorAdapter, Output.separator.getPreference(preferences))); } @Override @@ -83,7 +83,7 @@ public class NumberFormatPreference extends DialogPreference { final SharedPreferences.Editor editor = getSharedPreferences().edit(); Output.precision.putPreference(editor, precisionSeekBar.getCurrentTick()); Output.notation.putPreference(editor, notationAdapter.getItem(notationSpinner.getSelectedItemPosition()).item); - Engine.Preferences.groupingSeparator.putPreference(editor, separatorAdapter.getItem(separatorSpinner.getSelectedItemPosition()).item); + Output.separator.putPreference(editor, separatorAdapter.getItem(separatorSpinner.getSelectedItemPosition()).item); editor.apply(); } diff --git a/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java b/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java index 0e9eef5d..3768d2f4 100644 --- a/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/history/HistoryTest.java @@ -25,7 +25,9 @@ package org.solovyev.android.calculator.history; import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; + import com.squareup.otto.Bus; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -35,19 +37,33 @@ import org.robolectric.RobolectricGradleTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.solovyev.android.CalculatorTestRunner; -import org.solovyev.android.calculator.*; +import org.solovyev.android.calculator.BuildConfig; +import org.solovyev.android.calculator.Display; +import org.solovyev.android.calculator.DisplayState; +import org.solovyev.android.calculator.Editor; +import org.solovyev.android.calculator.EditorState; +import org.solovyev.android.calculator.Engine; +import org.solovyev.android.calculator.ErrorReporter; import org.solovyev.android.calculator.json.Json; import org.solovyev.android.io.FileSystem; -import javax.annotation.Nonnull; import java.io.File; import java.util.List; -import static org.junit.Assert.*; +import javax.annotation.Nonnull; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; -import static org.solovyev.android.calculator.Engine.Preferences.groupingSeparator; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.solovyev.android.calculator.Tests.sameThreadExecutor; import static org.solovyev.android.calculator.jscl.JsclOperation.numeric; @@ -106,8 +122,8 @@ public class HistoryTest { @Test public void testRecentHistoryShouldTakeIntoAccountGroupingSeparator() throws Exception { - when(history.preferences.contains(eq(groupingSeparator.getKey()))).thenReturn(true); - when(history.preferences.getString(eq(groupingSeparator.getKey()), anyString())).thenReturn(" "); + when(history.preferences.contains(eq(Engine.Preferences.Output.separator.getKey()))).thenReturn(true); + when(history.preferences.getString(eq(Engine.Preferences.Output.separator.getKey()), anyString())).thenReturn(" "); addState("1"); addState("12"); addState("123"); @@ -119,7 +135,7 @@ public class HistoryTest { assertEquals("12 345", states.get(0).editor.getTextString()); history.clearRecent(); - when(history.preferences.getString(eq(groupingSeparator.getKey()), anyString())).thenReturn("'"); + when(history.preferences.getString(eq(Engine.Preferences.Output.separator.getKey()), anyString())).thenReturn("'"); addState("1"); addState("12"); addState("123"); From 7e26b3519948768b6c55caa56245e9153fca0b0f Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 14:20:27 +0200 Subject: [PATCH 08/16] Store grouping separator in integer preference and remove boolean from Engine --- .../solovyev/android/calculator/Engine.java | 22 ++++---- .../android/calculator/Preferences.java | 10 ++-- .../android/calculator/history/History.java | 15 +++--- .../preferences/NumberFormatPreference.java | 13 ++--- .../android/prefs/CharacterPreference.java | 27 ++++++++++ .../solovyev/android/calculator/Tests.java | 1 - jscl/src/main/java/jscl/JsclMathEngine.java | 53 +++++++++++-------- jscl/src/main/java/jscl/MathContext.java | 14 ++--- .../test/java/jscl/JsclMathEngineTest.java | 9 ++-- .../test/java/jscl/math/ExpressionTest.java | 32 ++++++----- 10 files changed, 119 insertions(+), 77 deletions(-) create mode 100644 app/src/main/java/org/solovyev/android/prefs/CharacterPreference.java diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index 2820e4a0..ae17c886 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -33,6 +33,7 @@ import org.solovyev.android.calculator.functions.FunctionsRegistry; import org.solovyev.android.calculator.operators.OperatorsRegistry; import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry; import org.solovyev.android.prefs.BooleanPreference; +import org.solovyev.android.prefs.CharacterPreference; import org.solovyev.android.prefs.IntegerPreference; import org.solovyev.android.prefs.Preference; import org.solovyev.android.prefs.StringPreference; @@ -93,7 +94,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene this.mathEngine = mathEngine; this.mathEngine.setRoundResult(true); - this.mathEngine.setUseGroupingSeparator(true); + this.mathEngine.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull BooleanPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { @@ -110,6 +111,15 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene editor.putString(preference.getKey(), preferences.getString(oldKey, null)); } + private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull CharacterPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { + if (!preferences.contains(oldKey)) { + return; + } + final String s = preferences.getString(oldKey, null); + editor.putInt(preference.getKey(), TextUtils.isEmpty(s) ? 0 : s.charAt(0)); + } + + public static boolean isValidName(@Nullable String name) { if (!TextUtils.isEmpty(name)) { try { @@ -212,14 +222,8 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene mathEngine.setPrecision(Preferences.Output.precision.getPreference(preferences)); mathEngine.setScienceNotation(Preferences.Output.scientificNotation.getPreference(preferences)); mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences)); + mathEngine.setGroupingSeparator(Preferences.Output.separator.getPreference(preferences)); - final String groupingSeparator = Preferences.Output.separator.getPreference(preferences); - if (TextUtils.isEmpty(groupingSeparator)) { - mathEngine.setUseGroupingSeparator(false); - } else { - mathEngine.setUseGroupingSeparator(true); - mathEngine.setGroupingSeparator(groupingSeparator.charAt(0)); - } bus.post(ChangedEvent.INSTANCE); } @@ -290,7 +294,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false); public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); - public static final StringPreference separator = StringPreference.of("engine.output.separator", String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT)); + public static final CharacterPreference separator = CharacterPreference.of("engine.output.separator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/Preferences.java b/app/src/main/java/org/solovyev/android/calculator/Preferences.java index ceb7629a..a51da55c 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Preferences.java +++ b/app/src/main/java/org/solovyev/android/calculator/Preferences.java @@ -114,15 +114,15 @@ public final class Preferences { final Locale locale = Locale.getDefault(); if (locale != null) { final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); - int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator())); - final String groupingSeparator; + final int index = MathType.grouping_separator.getTokens().indexOf(String.valueOf(decimalFormatSymbols.getGroupingSeparator())); + final char separator; if (index >= 0) { - groupingSeparator = MathType.grouping_separator.getTokens().get(index); + separator = MathType.grouping_separator.getTokens().get(index).charAt(0); } else { - groupingSeparator = String.valueOf(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); + separator = JsclMathEngine.GROUPING_SEPARATOR_DEFAULT; } - Engine.Preferences.Output.separator.putPreference(editor, groupingSeparator); + Engine.Preferences.Output.separator.putPreference(editor, separator); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/history/History.java b/app/src/main/java/org/solovyev/android/calculator/history/History.java index 16d5fbac..bb7ef9cf 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/History.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/History.java @@ -125,15 +125,15 @@ public class History { private static boolean isIntermediate(@Nonnull String olderText, @Nonnull String newerText, - @NonNull String groupingSeparator) { + char separator) { if (TextUtils.isEmpty(olderText)) { return true; } if (TextUtils.isEmpty(newerText)) { return false; } - olderText = trimGroupingSeparators(olderText, groupingSeparator); - newerText = trimGroupingSeparators(newerText, groupingSeparator); + olderText = trimGroupingSeparators(olderText, separator); + newerText = trimGroupingSeparators(newerText, separator); final int diff = newerText.length() - olderText.length(); if (diff >= 1) { @@ -148,11 +148,10 @@ public class History { } @NonNull - static String trimGroupingSeparators(@NonNull String text, @NonNull String groupingSeparator) { - if (TextUtils.isEmpty(groupingSeparator)) { + static String trimGroupingSeparators(@NonNull String text, char separator) { + if (separator == 0) { return text; } - Check.isTrue(groupingSeparator.length() == 1); final StringBuilder sb = new StringBuilder(text.length()); for (int i = 0; i < text.length(); i++) { if (i == 0 || i == text.length() - 1) { @@ -160,7 +159,7 @@ public class History { sb.append(text.charAt(i)); continue; } - if (Character.isDigit(text.charAt(i - 1)) && text.charAt(i) == groupingSeparator.charAt(0) && Character.isDigit(text.charAt(i + 1))) { + if (Character.isDigit(text.charAt(i - 1)) && text.charAt(i) == separator && Character.isDigit(text.charAt(i + 1))) { // grouping separator => skip continue; } @@ -312,7 +311,7 @@ public class History { final List result = new LinkedList<>(); - final String separator = Preferences.Output.separator.getPreference(preferences); + final char separator = Preferences.Output.separator.getPreference(preferences); final List states = recent.asList(); final int statesCount = states.size(); diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index e4cbaee7..484dc9ca 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -20,6 +20,7 @@ import org.solovyev.android.views.DiscreteSeekBar; import butterknife.Bind; import butterknife.ButterKnife; +import jscl.JsclMathEngine; import static org.solovyev.android.calculator.Engine.Preferences.Output; @@ -31,7 +32,7 @@ public class NumberFormatPreference extends DialogPreference { DiscreteSeekBar precisionSeekBar; @Bind(R.id.nf_separator_spinner) Spinner separatorSpinner; - ArrayAdapter> separatorAdapter; + ArrayAdapter> separatorAdapter; { setPersistent(false); @@ -108,12 +109,12 @@ public class NumberFormatPreference extends DialogPreference { } @NonNull - private ArrayAdapter> makeSeparatorAdapter() { + private ArrayAdapter> makeSeparatorAdapter() { final Context context = getContext(); - final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); - adapter.add(Named.create("", R.string.p_grouping_separator_no, context)); - adapter.add(Named.create("'", R.string.p_grouping_separator_apostrophe, context)); - adapter.add(Named.create(" ", R.string.p_grouping_separator_space, context)); + final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); + adapter.add(Named.create(JsclMathEngine.GROUPING_SEPARATOR_NO, R.string.p_grouping_separator_no, context)); + adapter.add(Named.create('\'', R.string.p_grouping_separator_apostrophe, context)); + adapter.add(Named.create(' ', R.string.p_grouping_separator_space, context)); return adapter; } } diff --git a/app/src/main/java/org/solovyev/android/prefs/CharacterPreference.java b/app/src/main/java/org/solovyev/android/prefs/CharacterPreference.java new file mode 100644 index 00000000..5f6780ab --- /dev/null +++ b/app/src/main/java/org/solovyev/android/prefs/CharacterPreference.java @@ -0,0 +1,27 @@ +package org.solovyev.android.prefs; + +import android.content.SharedPreferences; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CharacterPreference extends AbstractPreference { + private CharacterPreference(@Nonnull String key, @Nullable Character defaultValue) { + super(key, defaultValue); + } + + public static CharacterPreference of(@Nonnull String key, @Nullable Character defaultValue) { + return new CharacterPreference(key, defaultValue); + } + + @Nullable + @Override + protected Character getPersistedValue(@Nonnull SharedPreferences preferences) { + return (char) preferences.getInt(getKey(), 0); + } + + @Override + protected void putPersistedValue(@Nonnull SharedPreferences.Editor editor, @Nonnull Character value) { + editor.putInt(getKey(), value); + } +} diff --git a/app/src/test/java/org/solovyev/android/calculator/Tests.java b/app/src/test/java/org/solovyev/android/calculator/Tests.java index fb8f5108..574534e5 100644 --- a/app/src/test/java/org/solovyev/android/calculator/Tests.java +++ b/app/src/test/java/org/solovyev/android/calculator/Tests.java @@ -23,7 +23,6 @@ public class Tests { @NonNull public static Engine makeEngine() { final JsclMathEngine mathEngine = JsclMathEngine.getInstance(); - mathEngine.setUseGroupingSeparator(true); mathEngine.setGroupingSeparator(' '); final Engine engine = new Engine(mathEngine); engine.postfixFunctionsRegistry = new PostfixFunctionsRegistry(mathEngine); diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java index 6c26d3d9..00550d93 100644 --- a/jscl/src/main/java/jscl/JsclMathEngine.java +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -1,32 +1,42 @@ package jscl; -import jscl.math.Expression; -import jscl.math.Generic; -import jscl.math.NotIntegerException; -import jscl.math.function.*; -import jscl.math.operator.Operator; -import jscl.math.operator.Percent; -import jscl.math.operator.Rand; -import jscl.math.operator.matrix.OperatorsRegistry; -import jscl.text.ParseException; import org.solovyev.common.NumberFormatter; import org.solovyev.common.math.MathRegistry; import org.solovyev.common.msg.MessageRegistry; import org.solovyev.common.msg.Messages; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; -import static midpcalc.Real.NumberFormat.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import jscl.math.Expression; +import jscl.math.Generic; +import jscl.math.NotIntegerException; +import jscl.math.function.Constants; +import jscl.math.function.ConstantsRegistry; +import jscl.math.function.Function; +import jscl.math.function.FunctionsRegistry; +import jscl.math.function.IConstant; +import jscl.math.function.PostfixFunctionsRegistry; +import jscl.math.operator.Operator; +import jscl.math.operator.Percent; +import jscl.math.operator.Rand; +import jscl.math.operator.matrix.OperatorsRegistry; +import jscl.text.ParseException; + +import static midpcalc.Real.NumberFormat.FSE_ENG; +import static midpcalc.Real.NumberFormat.FSE_NONE; +import static midpcalc.Real.NumberFormat.FSE_SCI; public class JsclMathEngine implements MathEngine { public static final AngleUnit DEFAULT_ANGLE_UNITS = AngleUnit.deg; public static final NumeralBase DEFAULT_NUMERAL_BASE = NumeralBase.dec; public static final char GROUPING_SEPARATOR_DEFAULT = ' '; + public static final char GROUPING_SEPARATOR_NO = 0; public static final int MAX_FRACTION_DIGITS = 20; @Nonnull private static JsclMathEngine instance = new JsclMathEngine(); @@ -39,11 +49,10 @@ public class JsclMathEngine implements MathEngine { return new NumberFormatter(); } }; - private char groupingSeparator = GROUPING_SEPARATOR_DEFAULT; + private char groupingSeparator = GROUPING_SEPARATOR_NO; private boolean roundResult = false; private int numberFormat = FSE_NONE; private int precision = 5; - private boolean useGroupingSeparator = false; @Nonnull private AngleUnit angleUnits = DEFAULT_ANGLE_UNITS; @Nonnull @@ -172,7 +181,7 @@ public class JsclMathEngine implements MathEngine { private NumberFormatter prepareNumberFormatter(@Nonnull NumeralBase nb) { final NumberFormatter nf = numberFormatter.get(); - nf.setGroupingSeparator(useGroupingSeparator ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING); + nf.setGroupingSeparator(hasGroupingSeparator() ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING); nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING); switch (numberFormat) { case FSE_ENG: @@ -272,7 +281,7 @@ public class JsclMathEngine implements MathEngine { @Nonnull public String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedDoubleValue) { - if (useGroupingSeparator) { + if (hasGroupingSeparator()) { final String groupingSeparator = getGroupingSeparator(nb); final int dotIndex = ungroupedDoubleValue.indexOf("."); @@ -299,6 +308,10 @@ public class JsclMathEngine implements MathEngine { } } + private boolean hasGroupingSeparator() { + return groupingSeparator != JsclMathEngine.GROUPING_SEPARATOR_NO; + } + @Nonnull private String getGroupingSeparator(@Nonnull NumeralBase nb) { return nb == NumeralBase.dec ? String.valueOf(groupingSeparator) : " "; @@ -342,10 +355,6 @@ public class JsclMathEngine implements MathEngine { this.precision = precision; } - public void setUseGroupingSeparator(boolean useGroupingSeparator) { - this.useGroupingSeparator = useGroupingSeparator; - } - public void setScienceNotation(boolean scienceNotation) { setNumberFormat(scienceNotation ? FSE_SCI : FSE_NONE); } @@ -361,7 +370,7 @@ public class JsclMathEngine implements MathEngine { return this.groupingSeparator; } - public void setGroupingSeparator(char groupingSeparator) { - this.groupingSeparator = groupingSeparator; + public void setGroupingSeparator(char separator) { + this.groupingSeparator = separator; } } diff --git a/jscl/src/main/java/jscl/MathContext.java b/jscl/src/main/java/jscl/MathContext.java index 4f280149..1b298121 100644 --- a/jscl/src/main/java/jscl/MathContext.java +++ b/jscl/src/main/java/jscl/MathContext.java @@ -1,12 +1,14 @@ package jscl; +import org.solovyev.common.math.MathRegistry; + +import java.math.BigInteger; + +import javax.annotation.Nonnull; + import jscl.math.function.Function; import jscl.math.function.IConstant; import jscl.math.operator.Operator; -import org.solovyev.common.math.MathRegistry; - -import javax.annotation.Nonnull; -import java.math.BigInteger; public interface MathContext { @@ -40,9 +42,7 @@ public interface MathContext { void setPrecision(int precision); - void setUseGroupingSeparator(boolean useGroupingSeparator); - - void setGroupingSeparator(char groupingSeparator); + void setGroupingSeparator(char separator); @Nonnull String format(double value); diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java index ae3cb0c7..b6336305 100644 --- a/jscl/src/test/java/jscl/JsclMathEngineTest.java +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -1,9 +1,10 @@ package jscl; -import midpcalc.Real; import org.junit.Before; import org.junit.Test; +import midpcalc.Real; + import static org.junit.Assert.assertEquals; /** @@ -23,7 +24,7 @@ public class JsclMathEngineTest { @Test public void testFormat() throws Exception { try { - me.setUseGroupingSeparator(true); + me.setGroupingSeparator(' '); assertEquals("1", me.format(1d, NumeralBase.bin)); assertEquals("10", me.format(2d, NumeralBase.bin)); assertEquals("11", me.format(3d, NumeralBase.bin)); @@ -60,7 +61,7 @@ public class JsclMathEngineTest { assertEquals("6.CCDA6A054226DB6E-19", me.format(0.00000000000000000000009d, NumeralBase.hex)); assertEquals("A.E15D766ED03E2BEE-20", me.format(0.000000000000000000000009d, NumeralBase.hex)); } finally { - me.setUseGroupingSeparator(false); + me.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_NO); } assertEquals("1", me.format(1d, NumeralBase.bin)); @@ -93,7 +94,6 @@ public class JsclMathEngineTest { @Test public void testBinShouldAlwaysUseSpaceAsGroupingSeparator() throws Exception { me.setGroupingSeparator('\''); - me.setUseGroupingSeparator(true); assertEquals("100 0000 0000", me.format(1024d, NumeralBase.bin)); } @@ -101,7 +101,6 @@ public class JsclMathEngineTest { @Test public void testHexShouldAlwaysUseSpaceAsGroupingSeparator() throws Exception { me.setGroupingSeparator('\''); - me.setUseGroupingSeparator(true); assertEquals("4 00", me.format(1024d, NumeralBase.hex)); } diff --git a/jscl/src/test/java/jscl/math/ExpressionTest.java b/jscl/src/test/java/jscl/math/ExpressionTest.java index 8ea51f24..416d754a 100644 --- a/jscl/src/test/java/jscl/math/ExpressionTest.java +++ b/jscl/src/test/java/jscl/math/ExpressionTest.java @@ -1,5 +1,18 @@ package jscl.math; +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Set; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import jscl.AngleUnit; import jscl.JsclMathEngine; import jscl.MathEngine; @@ -8,19 +21,10 @@ import jscl.math.function.Constant; import jscl.math.function.ExtendedConstant; import jscl.math.function.IConstant; import jscl.text.ParseException; -import org.junit.Test; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Set; - -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class ExpressionTest { @@ -786,7 +790,7 @@ public class ExpressionTest { public void testFormat() throws Exception { final JsclMathEngine me = JsclMathEngine.getInstance(); try { - me.setUseGroupingSeparator(true); + me.setGroupingSeparator(' '); assertEquals("123 456.7891011", Expression.valueOf("123456.7891011").numeric().toString()); assertEquals("123 456.7891011", Expression.valueOf("123456.7891011").simplify().toString()); assertEquals("123 456.7891011123", Expression.valueOf("123456.7891011123123123123123").simplify().toString()); @@ -831,7 +835,7 @@ public class ExpressionTest { assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); } finally { - me.setUseGroupingSeparator(false); + me.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_NO); me.setScienceNotation(false); me.setRoundResult(false); } From 2ac061d8bacb7185b6982e407175b3f8bd9f2c05 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 15:37:19 +0200 Subject: [PATCH 09/16] Remove scientificNotation preference and use Output.notation instead --- .../org/solovyev/android/calculator/Engine.java | 15 +++++++++------ .../calculator/wizard/CalculatorMode.java | 8 +++++--- jscl/src/main/java/jscl/JsclMathEngine.java | 16 ++++++---------- jscl/src/main/java/jscl/MathContext.java | 2 +- jscl/src/test/java/jscl/JsclMathEngineTest.java | 4 ++-- jscl/src/test/java/jscl/math/ExpressionTest.java | 15 ++++++++------- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index ae17c886..cdf8263b 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -189,10 +189,17 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene migratePreference(preferences, Preferences.numeralBase, "org.solovyev.android.calculator.CalculatorActivity_numeral_bases", editor); migratePreference(preferences, Preferences.angleUnit, "org.solovyev.android.calculator.CalculatorActivity_angle_units", editor); migratePreference(preferences, Preferences.Output.precision, "org.solovyev.android.calculator.CalculatorModel_result_precision", editor); - migratePreference(preferences, Preferences.Output.scientificNotation, "calculation.output.science_notation", editor); + if (preferences.contains("engine.output.science_notation")) { + final boolean scientific = preferences.getBoolean("engine.output.science_notation", false); + Preferences.Output.notation.putPreference(editor, scientific ? Notation.sci : Notation.dec); + } migratePreference(preferences, Preferences.Output.round, "org.solovyev.android.calculator.CalculatorModel_round_result", editor); } else if (oldVersion == 1) { migratePreference(preferences, Preferences.Output.separator, "engine.groupingSeparator", editor); + if (preferences.contains("engine.output.scientificNotation")) { + final boolean scientific = preferences.getBoolean("engine.output.scientificNotation", false); + Preferences.Output.notation.putPreference(editor, scientific ? Notation.sci : Notation.dec); + } } Preferences.version.putDefault(editor); editor.apply(); @@ -220,7 +227,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene setMultiplicationSign(Preferences.multiplicationSign.getPreference(preferences)); mathEngine.setPrecision(Preferences.Output.precision.getPreference(preferences)); - mathEngine.setScienceNotation(Preferences.Output.scientificNotation.getPreference(preferences)); + mathEngine.setNotation(Preferences.Output.notation.getPreference(preferences).id); mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences)); mathEngine.setGroupingSeparator(Preferences.Output.separator.getPreference(preferences)); @@ -277,7 +284,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene preferenceKeys.add(numeralBase.getKey()); preferenceKeys.add(angleUnit.getKey()); preferenceKeys.add(Output.precision.getKey()); - preferenceKeys.add(Output.scientificNotation.getKey()); preferenceKeys.add(Output.round.getKey()); preferenceKeys.add(Output.notation.getKey()); preferenceKeys.add(Output.separator.getKey()); @@ -290,12 +296,9 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static class Output { public static final StringPreference precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class)); - // todo serso: remove - public static final BooleanPreference scientificNotation = BooleanPreference.of("engine.output.scientificNotation", false); public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); public static final CharacterPreference separator = CharacterPreference.of("engine.output.separator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); - } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java b/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java index 301d6bd3..6720ac8d 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java @@ -23,12 +23,14 @@ package org.solovyev.android.calculator.wizard; import android.content.SharedPreferences; -import jscl.AngleUnit; + import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; import javax.annotation.Nonnull; +import jscl.AngleUnit; + enum CalculatorMode { simple() { @@ -38,7 +40,7 @@ enum CalculatorMode { Preferences.Gui.mode.putPreference(editor, Preferences.Gui.Mode.simple); Engine.Preferences.angleUnit.putPreference(editor, AngleUnit.deg); - Engine.Preferences.Output.scientificNotation.putPreference(editor, false); + Engine.Preferences.Output.notation.putPreference(editor, Engine.Notation.dec); Engine.Preferences.Output.round.putPreference(editor, true); editor.apply(); @@ -52,7 +54,7 @@ enum CalculatorMode { Preferences.Gui.mode.putPreference(editor, Preferences.Gui.Mode.engineer); Engine.Preferences.angleUnit.putPreference(editor, AngleUnit.rad); - Engine.Preferences.Output.scientificNotation.putPreference(editor, true); + Engine.Preferences.Output.notation.putPreference(editor, Engine.Notation.eng); Engine.Preferences.Output.round.putPreference(editor, false); editor.apply(); diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java index 00550d93..43fec261 100644 --- a/jscl/src/main/java/jscl/JsclMathEngine.java +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -51,7 +51,7 @@ public class JsclMathEngine implements MathEngine { }; private char groupingSeparator = GROUPING_SEPARATOR_NO; private boolean roundResult = false; - private int numberFormat = FSE_NONE; + private int notation = FSE_NONE; private int precision = 5; @Nonnull private AngleUnit angleUnits = DEFAULT_ANGLE_UNITS; @@ -183,7 +183,7 @@ public class JsclMathEngine implements MathEngine { final NumberFormatter nf = numberFormatter.get(); nf.setGroupingSeparator(hasGroupingSeparator() ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING); nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING); - switch (numberFormat) { + switch (notation) { case FSE_ENG: nf.useEngineeringFormat(NumberFormatter.DEFAULT_MAGNITUDE); break; @@ -355,15 +355,11 @@ public class JsclMathEngine implements MathEngine { this.precision = precision; } - public void setScienceNotation(boolean scienceNotation) { - setNumberFormat(scienceNotation ? FSE_SCI : FSE_NONE); - } - - public void setNumberFormat(int numberFormat) { - if (numberFormat != FSE_SCI && numberFormat != FSE_ENG && numberFormat != FSE_NONE) { - throw new IllegalArgumentException("Unsupported format: " + numberFormat); + public void setNotation(int notation) { + if (notation != FSE_SCI && notation != FSE_ENG && notation != FSE_NONE) { + throw new IllegalArgumentException("Unsupported notation: " + notation); } - this.numberFormat = numberFormat; + this.notation = notation; } public char getGroupingSeparator() { diff --git a/jscl/src/main/java/jscl/MathContext.java b/jscl/src/main/java/jscl/MathContext.java index 1b298121..f71c3d3e 100644 --- a/jscl/src/main/java/jscl/MathContext.java +++ b/jscl/src/main/java/jscl/MathContext.java @@ -55,5 +55,5 @@ public interface MathContext { @Nonnull String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedIntValue); - void setScienceNotation(boolean scienceNotation); + void setNotation(int notation); } diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java index b6336305..49eec1f8 100644 --- a/jscl/src/test/java/jscl/JsclMathEngineTest.java +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -107,7 +107,7 @@ public class JsclMathEngineTest { @Test public void testEngineeringNotationWithRounding() throws Exception { - me.setNumberFormat(Real.NumberFormat.FSE_ENG); + me.setNotation(Real.NumberFormat.FSE_ENG); me.setRoundResult(true); me.setPrecision(5); @@ -163,7 +163,7 @@ public class JsclMathEngineTest { @Test public void testEngineeringNotationWithoutRounding() throws Exception { - me.setNumberFormat(Real.NumberFormat.FSE_ENG); + me.setNotation(Real.NumberFormat.FSE_ENG); me.setRoundResult(false); assertEquals("10E6", me.format(10000000d)); diff --git a/jscl/src/test/java/jscl/math/ExpressionTest.java b/jscl/src/test/java/jscl/math/ExpressionTest.java index 416d754a..7e76fb0b 100644 --- a/jscl/src/test/java/jscl/math/ExpressionTest.java +++ b/jscl/src/test/java/jscl/math/ExpressionTest.java @@ -21,6 +21,7 @@ import jscl.math.function.Constant; import jscl.math.function.ExtendedConstant; import jscl.math.function.IConstant; import jscl.text.ParseException; +import midpcalc.Real; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -797,17 +798,17 @@ public class ExpressionTest { assertEquals("0.000001222", Expression.valueOf("1222/(10^9)").numeric().toString()); assertEquals("12 345", JsclInteger.valueOf(12345L).toString()); - me.setScienceNotation(true); + me.setNotation(Real.NumberFormat.FSE_SCI); assertEquals("0", Expression.valueOf("0.0").simplify().toString()); assertEquals("1", Expression.valueOf("1.0").simplify().toString()); assertEquals("100", Expression.valueOf("100.0").simplify().toString()); - me.setScienceNotation(false); + me.setNotation(Real.NumberFormat.FSE_NONE); me.setRoundResult(true); me.setPrecision(5); assertEquals("0", Expression.valueOf("1222/(10^9)").numeric().toString()); - me.setScienceNotation(true); + me.setNotation(Real.NumberFormat.FSE_SCI); me.setRoundResult(true); me.setPrecision(5); assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); @@ -819,24 +820,24 @@ public class ExpressionTest { me.setRoundResult(false); assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); - me.setScienceNotation(false); + me.setNotation(Real.NumberFormat.FSE_NONE); assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); - me.setScienceNotation(true); + me.setNotation(Real.NumberFormat.FSE_SCI); assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); me.setRoundResult(true); me.setPrecision(10); assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); - me.setScienceNotation(false); + me.setNotation(Real.NumberFormat.FSE_NONE); me.setRoundResult(true); me.setPrecision(10); assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); } finally { me.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_NO); - me.setScienceNotation(false); + me.setNotation(Real.NumberFormat.FSE_NONE); me.setRoundResult(false); } } From 6e2f20dd01021db20b6d37156a0f8100564a1a40 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 17:16:56 +0200 Subject: [PATCH 10/16] Remove round preference --- .../solovyev/android/calculator/Engine.java | 19 ++++++++++++++----- .../preferences/NumberFormatPreference.java | 4 ++-- .../preferences/PreferencesFragment.java | 9 --------- .../calculator/wizard/CalculatorMode.java | 5 +++-- jscl/src/main/java/jscl/JsclMathEngine.java | 17 +++++------------ jscl/src/main/java/jscl/MathContext.java | 2 -- .../org/solovyev/common/NumberFormatter.java | 17 ++++++++++------- .../test/java/jscl/JsclMathEngineTest.java | 9 ++++----- .../test/java/jscl/math/ExpressionTest.java | 12 ++++-------- 9 files changed, 42 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index cdf8263b..e9939b9d 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -37,6 +37,7 @@ import org.solovyev.android.prefs.CharacterPreference; import org.solovyev.android.prefs.IntegerPreference; import org.solovyev.android.prefs.Preference; import org.solovyev.android.prefs.StringPreference; +import org.solovyev.common.NumberFormatter; import org.solovyev.common.text.EnumMapper; import org.solovyev.common.text.NumberMapper; @@ -93,7 +94,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public Engine(@Nonnull JsclMathEngine mathEngine) { this.mathEngine = mathEngine; - this.mathEngine.setRoundResult(true); + this.mathEngine.setPrecision(5); this.mathEngine.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } @@ -193,13 +194,24 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene final boolean scientific = preferences.getBoolean("engine.output.science_notation", false); Preferences.Output.notation.putPreference(editor, scientific ? Notation.sci : Notation.dec); } - migratePreference(preferences, Preferences.Output.round, "org.solovyev.android.calculator.CalculatorModel_round_result", editor); + if (preferences.contains("org.solovyev.android.calculator.CalculatorModel_round_result")) { + final boolean round = preferences.getBoolean("org.solovyev.android.calculator.CalculatorModel_round_result", true); + if (!round) { + Preferences.Output.precision.putPreference(editor, NumberFormatter.MAX_PRECISION); + } + } } else if (oldVersion == 1) { migratePreference(preferences, Preferences.Output.separator, "engine.groupingSeparator", editor); if (preferences.contains("engine.output.scientificNotation")) { final boolean scientific = preferences.getBoolean("engine.output.scientificNotation", false); Preferences.Output.notation.putPreference(editor, scientific ? Notation.sci : Notation.dec); } + if (preferences.contains("engine.output.round")) { + final boolean round = preferences.getBoolean("engine.output.round", true); + if (!round) { + Preferences.Output.precision.putPreference(editor, NumberFormatter.MAX_PRECISION); + } + } } Preferences.version.putDefault(editor); editor.apply(); @@ -228,7 +240,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene mathEngine.setPrecision(Preferences.Output.precision.getPreference(preferences)); mathEngine.setNotation(Preferences.Output.notation.getPreference(preferences).id); - mathEngine.setRoundResult(Preferences.Output.round.getPreference(preferences)); mathEngine.setGroupingSeparator(Preferences.Output.separator.getPreference(preferences)); bus.post(ChangedEvent.INSTANCE); @@ -284,7 +295,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene preferenceKeys.add(numeralBase.getKey()); preferenceKeys.add(angleUnit.getKey()); preferenceKeys.add(Output.precision.getKey()); - preferenceKeys.add(Output.round.getKey()); preferenceKeys.add(Output.notation.getKey()); preferenceKeys.add(Output.separator.getKey()); } @@ -296,7 +306,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static class Output { public static final StringPreference precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class)); - public static final BooleanPreference round = BooleanPreference.of("engine.output.round", true); public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); public static final CharacterPreference separator = CharacterPreference.of("engine.output.separator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index 484dc9ca..8a36d481 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -17,10 +17,10 @@ import org.solovyev.android.calculator.Named; import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.text.NaturalComparator; import org.solovyev.android.views.DiscreteSeekBar; +import org.solovyev.common.NumberFormatter; import butterknife.Bind; import butterknife.ButterKnife; -import jscl.JsclMathEngine; import static org.solovyev.android.calculator.Engine.Preferences.Output; @@ -112,7 +112,7 @@ public class NumberFormatPreference extends DialogPreference { private ArrayAdapter> makeSeparatorAdapter() { final Context context = getContext(); final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); - adapter.add(Named.create(JsclMathEngine.GROUPING_SEPARATOR_NO, R.string.p_grouping_separator_no, context)); + adapter.add(Named.create(NumberFormatter.NO_GROUPING, R.string.p_grouping_separator_no, context)); adapter.add(Named.create('\'', R.string.p_grouping_separator_apostrophe, context)); adapter.add(Named.create(' ', R.string.p_grouping_separator_space, context)); return adapter; diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java index b360c9e1..1f441473 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java @@ -13,7 +13,6 @@ import android.view.View; import android.widget.ListView; import org.solovyev.android.calculator.AdView; -import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.Preferences.Gui.Theme; import org.solovyev.android.calculator.R; @@ -135,8 +134,6 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc }); } }); - - onSharedPreferenceChanged(preferences, Engine.Preferences.Output.round.getKey()); } private void prepareLayoutPreference(int preference) { @@ -221,12 +218,6 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { - if (Engine.Preferences.Output.round.getKey().equals(key)) { - final Preference preference = findPreference(Engine.Preferences.Output.precision.getKey()); - if (preference != null) { - preference.setEnabled(preferences.getBoolean(key, Engine.Preferences.Output.round.getDefaultValue())); - } - } } @Override diff --git a/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java b/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java index 6720ac8d..d1be8929 100644 --- a/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java +++ b/app/src/main/java/org/solovyev/android/calculator/wizard/CalculatorMode.java @@ -26,6 +26,7 @@ import android.content.SharedPreferences; import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; +import org.solovyev.common.NumberFormatter; import javax.annotation.Nonnull; @@ -41,7 +42,7 @@ enum CalculatorMode { Preferences.Gui.mode.putPreference(editor, Preferences.Gui.Mode.simple); Engine.Preferences.angleUnit.putPreference(editor, AngleUnit.deg); Engine.Preferences.Output.notation.putPreference(editor, Engine.Notation.dec); - Engine.Preferences.Output.round.putPreference(editor, true); + Engine.Preferences.Output.precision.putPreference(editor, 5); editor.apply(); } @@ -55,7 +56,7 @@ enum CalculatorMode { Preferences.Gui.mode.putPreference(editor, Preferences.Gui.Mode.engineer); Engine.Preferences.angleUnit.putPreference(editor, AngleUnit.rad); Engine.Preferences.Output.notation.putPreference(editor, Engine.Notation.eng); - Engine.Preferences.Output.round.putPreference(editor, false); + Engine.Preferences.Output.precision.putPreference(editor, NumberFormatter.MAX_PRECISION); editor.apply(); } diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java index 43fec261..022a7e92 100644 --- a/jscl/src/main/java/jscl/JsclMathEngine.java +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -36,8 +36,6 @@ public class JsclMathEngine implements MathEngine { public static final AngleUnit DEFAULT_ANGLE_UNITS = AngleUnit.deg; public static final NumeralBase DEFAULT_NUMERAL_BASE = NumeralBase.dec; public static final char GROUPING_SEPARATOR_DEFAULT = ' '; - public static final char GROUPING_SEPARATOR_NO = 0; - public static final int MAX_FRACTION_DIGITS = 20; @Nonnull private static JsclMathEngine instance = new JsclMathEngine(); @Nonnull @@ -49,10 +47,9 @@ public class JsclMathEngine implements MathEngine { return new NumberFormatter(); } }; - private char groupingSeparator = GROUPING_SEPARATOR_NO; - private boolean roundResult = false; + private char groupingSeparator = NumberFormatter.NO_GROUPING; private int notation = FSE_NONE; - private int precision = 5; + private int precision = NumberFormatter.MAX_PRECISION; @Nonnull private AngleUnit angleUnits = DEFAULT_ANGLE_UNITS; @Nonnull @@ -182,7 +179,7 @@ public class JsclMathEngine implements MathEngine { private NumberFormatter prepareNumberFormatter(@Nonnull NumeralBase nb) { final NumberFormatter nf = numberFormatter.get(); nf.setGroupingSeparator(hasGroupingSeparator() ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING); - nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING); + nf.setPrecision(precision); switch (notation) { case FSE_ENG: nf.useEngineeringFormat(NumberFormatter.DEFAULT_MAGNITUDE); @@ -264,7 +261,7 @@ public class JsclMathEngine implements MathEngine { ungroupedValue = to.toString(new BigDecimal(value).toBigInteger()); } catch (NotIntegerException e) { - ungroupedValue = to.toString(value, roundResult ? precision : MAX_FRACTION_DIGITS); + ungroupedValue = to.toString(value, precision); } return addGroupingSeparators(to, ungroupedValue); @@ -309,7 +306,7 @@ public class JsclMathEngine implements MathEngine { } private boolean hasGroupingSeparator() { - return groupingSeparator != JsclMathEngine.GROUPING_SEPARATOR_NO; + return groupingSeparator != NumberFormatter.NO_GROUPING; } @Nonnull @@ -347,10 +344,6 @@ public class JsclMathEngine implements MathEngine { return result; } - public void setRoundResult(boolean roundResult) { - this.roundResult = roundResult; - } - public void setPrecision(int precision) { this.precision = precision; } diff --git a/jscl/src/main/java/jscl/MathContext.java b/jscl/src/main/java/jscl/MathContext.java index f71c3d3e..2a9dcdb3 100644 --- a/jscl/src/main/java/jscl/MathContext.java +++ b/jscl/src/main/java/jscl/MathContext.java @@ -38,8 +38,6 @@ public interface MathContext { void setNumeralBase(@Nonnull NumeralBase numeralBase); - void setRoundResult(boolean roundResult); - void setPrecision(int precision); void setGroupingSeparator(char separator); diff --git a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java index b875774d..8c824e98 100644 --- a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java +++ b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java @@ -1,17 +1,21 @@ package org.solovyev.common; -import midpcalc.Real; - -import javax.annotation.Nonnull; import java.math.BigDecimal; import java.math.BigInteger; +import javax.annotation.Nonnull; + +import midpcalc.Real; + import static java.lang.Math.pow; -import static midpcalc.Real.NumberFormat.*; +import static midpcalc.Real.NumberFormat.FSE_ENG; +import static midpcalc.Real.NumberFormat.FSE_FIX; +import static midpcalc.Real.NumberFormat.FSE_NONE; +import static midpcalc.Real.NumberFormat.FSE_SCI; public class NumberFormatter { - public static final int NO_GROUPING = 0; + public static final char NO_GROUPING = 0; public static final int NO_ROUNDING = -1; public static final int DEFAULT_MAGNITUDE = 5; public static final int MAX_PRECISION = 16; @@ -94,7 +98,6 @@ public class NumberFormatter { final BigInteger absValue = value.abs(); final boolean simpleFormat = useSimpleFormat(radix, absValue); - final int effectivePrecision = precision == NO_ROUNDING ? MAX_PRECISION : precision; if (simpleFormat) { numberFormat.fse = FSE_FIX; } else if (format == FSE_NONE) { @@ -105,7 +108,7 @@ public class NumberFormatter { numberFormat.fse = format; } numberFormat.thousand = groupingSeparator; - numberFormat.precision = effectivePrecision; + numberFormat.precision = Math.max(0, Math.min(precision, MAX_PRECISION)); numberFormat.base = radix; numberFormat.maxwidth = simpleFormat ? 100 : 30; diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java index 49eec1f8..d2e3583f 100644 --- a/jscl/src/test/java/jscl/JsclMathEngineTest.java +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -2,6 +2,7 @@ package jscl; import org.junit.Before; import org.junit.Test; +import org.solovyev.common.NumberFormatter; import midpcalc.Real; @@ -39,7 +40,6 @@ public class JsclMathEngineTest { assertEquals("1 0100", me.format(20d, NumeralBase.bin)); assertEquals("1 1111", me.format(31d, NumeralBase.bin)); - me.setRoundResult(true); me.setPrecision(10); assertEquals("111 1111 0011 0110", me.format(32566d, NumeralBase.bin)); @@ -57,11 +57,11 @@ public class JsclMathEngineTest { assertEquals("D 25 0F 77 0A.6F7319", me.format(56456345354.43534534523459999d, NumeralBase.hex)); assertEquals("3 E7.4CCCCCCCCD", me.format(999.3d, NumeralBase.hex)); - me.setRoundResult(false); + me.setPrecision(NumberFormatter.MAX_PRECISION); assertEquals("6.CCDA6A054226DB6E-19", me.format(0.00000000000000000000009d, NumeralBase.hex)); assertEquals("A.E15D766ED03E2BEE-20", me.format(0.000000000000000000000009d, NumeralBase.hex)); } finally { - me.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_NO); + me.setGroupingSeparator(NumberFormatter.NO_GROUPING); } assertEquals("1", me.format(1d, NumeralBase.bin)); @@ -108,7 +108,6 @@ public class JsclMathEngineTest { @Test public void testEngineeringNotationWithRounding() throws Exception { me.setNotation(Real.NumberFormat.FSE_ENG); - me.setRoundResult(true); me.setPrecision(5); assertEquals("10E6", me.format(10000000d)); @@ -164,7 +163,7 @@ public class JsclMathEngineTest { @Test public void testEngineeringNotationWithoutRounding() throws Exception { me.setNotation(Real.NumberFormat.FSE_ENG); - me.setRoundResult(false); + me.setPrecision(NumberFormatter.MAX_PRECISION); assertEquals("10E6", me.format(10000000d)); assertEquals("99E6", me.format(99000000d)); diff --git a/jscl/src/test/java/jscl/math/ExpressionTest.java b/jscl/src/test/java/jscl/math/ExpressionTest.java index 7e76fb0b..a45fbc7b 100644 --- a/jscl/src/test/java/jscl/math/ExpressionTest.java +++ b/jscl/src/test/java/jscl/math/ExpressionTest.java @@ -1,6 +1,7 @@ package jscl.math; import org.junit.Test; +import org.solovyev.common.NumberFormatter; import java.io.BufferedReader; import java.io.IOException; @@ -804,20 +805,17 @@ public class ExpressionTest { assertEquals("100", Expression.valueOf("100.0").simplify().toString()); me.setNotation(Real.NumberFormat.FSE_NONE); - me.setRoundResult(true); me.setPrecision(5); assertEquals("0", Expression.valueOf("1222/(10^9)").numeric().toString()); me.setNotation(Real.NumberFormat.FSE_SCI); - me.setRoundResult(true); me.setPrecision(5); assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); - me.setRoundResult(true); me.setPrecision(10); assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); - me.setRoundResult(false); + me.setPrecision(NumberFormatter.MAX_PRECISION); assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); me.setNotation(Real.NumberFormat.FSE_NONE); @@ -826,19 +824,17 @@ public class ExpressionTest { me.setNotation(Real.NumberFormat.FSE_SCI); assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); - me.setRoundResult(true); me.setPrecision(10); assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); me.setNotation(Real.NumberFormat.FSE_NONE); - me.setRoundResult(true); me.setPrecision(10); assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); } finally { - me.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_NO); + me.setGroupingSeparator(NumberFormatter.NO_GROUPING); me.setNotation(Real.NumberFormat.FSE_NONE); - me.setRoundResult(false); + me.setPrecision(NumberFormatter.MAX_PRECISION); } } } From 8add68bddb8d8d14d2d59400a0ef1b7e4b479a4d Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 17:20:50 +0200 Subject: [PATCH 11/16] Make maxPrecision=15 --- .../calculator/preferences/NumberFormatPreference.java | 5 ++--- jscl/src/main/java/org/solovyev/common/NumberFormatter.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index 8a36d481..f921f8a6 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -63,9 +63,8 @@ public class NumberFormatPreference extends DialogPreference { ButterKnife.bind(this, view); final SharedPreferences preferences = getSharedPreferences(); - final int maxPrecision = precisionSeekBar.getMaxTick(); - precisionSeekBar.setMax(maxPrecision); - precisionSeekBar.setCurrentTick(Math.max(0, Math.min(maxPrecision, Output.precision.getPreference(preferences)))); + precisionSeekBar.setMax(NumberFormatter.MAX_PRECISION); + precisionSeekBar.setCurrentTick(Math.max(0, Math.min(NumberFormatter.MAX_PRECISION, Output.precision.getPreference(preferences)))); notationAdapter = makeNotationAdapter(); notationSpinner.setAdapter(notationAdapter); notationSpinner.setSelection(indexOf(notationAdapter, Output.notation.getPreference(preferences))); diff --git a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java index 8c824e98..e5fa934a 100644 --- a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java +++ b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java @@ -18,7 +18,7 @@ public class NumberFormatter { public static final char NO_GROUPING = 0; public static final int NO_ROUNDING = -1; public static final int DEFAULT_MAGNITUDE = 5; - public static final int MAX_PRECISION = 16; + public static final int MAX_PRECISION = 15; private final Real.NumberFormat numberFormat = new Real.NumberFormat(); private final Real real = new Real(); From 99452483f8acbda786a7f7a72ee613d501d9010a Mon Sep 17 00:00:00 2001 From: serso Date: Sat, 30 Apr 2016 19:10:20 +0200 Subject: [PATCH 12/16] Reformat code and remove unused code --- .../android/calculator/BaseNumberBuilder.java | 2 +- .../android/calculator/NumberBuilder.java | 48 +------- .../android/calculator/math/MathType.java | 15 +-- jscl/src/main/java/jscl/JsclMathEngine.java | 109 ++++++------------ jscl/src/main/java/jscl/MathContext.java | 2 +- jscl/src/main/java/jscl/MathEngine.java | 3 - 6 files changed, 50 insertions(+), 129 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java b/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java index de8783a1..6546afd3 100644 --- a/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java @@ -77,7 +77,7 @@ public abstract class BaseNumberBuilder { if ("−".equals(match) || "-".equals(match) || "+".equals(match)) { final StringBuilder localNb = numberBuilder; if (localNb != null && localNb.length() > 0) { - if (localNb.charAt(localNb.length() - 1) == MathType.POWER_10) { + if (localNb.charAt(localNb.length() - 1) == MathType.EXPONENT) { return true; } } diff --git a/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java b/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java index e506e435..01e1ea9a 100644 --- a/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java +++ b/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java @@ -26,7 +26,6 @@ import android.text.SpannableStringBuilder; import jscl.MathContext; import jscl.MathEngine; import jscl.NumeralBase; -import jscl.math.numeric.Real; import jscl.text.DoubleParser; import jscl.text.JsclIntegerParser; import jscl.text.ParseException; @@ -45,60 +44,23 @@ public class NumberBuilder extends BaseNumberBuilder { } private static int replaceNumberInText(@Nonnull SpannableStringBuilder sb, - @Nullable String number, + @Nullable String oldNumber, int trimmedChars, @Nonnull NumeralBase nb, @Nonnull final MathEngine engine) { - if (number == null) { + if (oldNumber == null) { return 0; } // in any case remove old number from text - final int oldNumberLength = number.length() + trimmedChars; + final int oldNumberLength = oldNumber.length() + trimmedChars; sb.delete(sb.length() - oldNumberLength, sb.length()); - final String newNumber = formatNumber(number, nb, engine); + final String newNumber = engine.format(oldNumber, nb); sb.append(newNumber); // offset between old number and new number return newNumber.length() - oldNumberLength; } - @Nonnull - private static String formatNumber(@Nonnull String number, @Nonnull NumeralBase nb, @Nonnull MathEngine engine) { - String result; - - int indexOfDot = number.indexOf('.'); - - if (indexOfDot < 0) { - int indexOfE; - if (nb == NumeralBase.hex) { - indexOfE = -1; - } else { - indexOfE = number.indexOf(MathType.POWER_10); - } - if (indexOfE < 0) { - result = engine.addGroupingSeparators(nb, number); - } else { - final String partBeforeE; - if (indexOfE != 0) { - partBeforeE = engine.addGroupingSeparators(nb, number.substring(0, indexOfE)); - } else { - partBeforeE = ""; - } - result = partBeforeE + number.substring(indexOfE); - } - } else { - final String integerPart; - if (indexOfDot != 0) { - integerPart = engine.addGroupingSeparators(nb, number.substring(0, indexOfDot)); - } else { - integerPart = ""; - } - result = integerPart + number.substring(indexOfDot); - } - - return result; - } - @Nonnull private static Double toDouble(@Nonnull String s, @Nonnull NumeralBase nb, @Nonnull final MathContext mc) throws NumberFormatException { final NumeralBase defaultNb = mc.getNumeralBase(); @@ -112,7 +74,7 @@ public class NumberBuilder extends BaseNumberBuilder { p.exceptionsPool.release(e); try { p.reset(); - return ((Real) DoubleParser.parser.parse(p, null).content()).doubleValue(); + return DoubleParser.parser.parse(p, null).content().doubleValue(); } catch (ParseException e1) { p.exceptionsPool.release(e1); throw new NumberFormatException(); diff --git a/app/src/main/java/org/solovyev/android/calculator/math/MathType.java b/app/src/main/java/org/solovyev/android/calculator/math/MathType.java index d4c12250..89e464a9 100644 --- a/app/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/app/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -23,24 +23,21 @@ package org.solovyev.android.calculator.math; import android.support.annotation.NonNull; - +import jscl.JsclMathEngine; +import jscl.NumeralBase; +import jscl.math.function.Constants; import org.solovyev.android.Check; import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.ParseException; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import jscl.JsclMathEngine; -import jscl.NumeralBase; -import jscl.math.function.Constants; - public enum MathType { @@ -224,7 +221,7 @@ public enum MathType { }; public static final List groupSymbols = Arrays.asList("()", "[]", "{}"); - public final static Character POWER_10 = 'E'; + public final static Character EXPONENT = 'E'; public static final String E = "e"; public static final String C = "c"; public final static String NAN = "NaN"; diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java index 022a7e92..334d6971 100644 --- a/jscl/src/main/java/jscl/JsclMathEngine.java +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -21,6 +21,7 @@ import jscl.math.function.Function; import jscl.math.function.FunctionsRegistry; import jscl.math.function.IConstant; import jscl.math.function.PostfixFunctionsRegistry; +import jscl.math.function.*; import jscl.math.operator.Operator; import jscl.math.operator.Percent; import jscl.math.operator.Rand; @@ -30,6 +31,12 @@ import jscl.text.ParseException; import static midpcalc.Real.NumberFormat.FSE_ENG; import static midpcalc.Real.NumberFormat.FSE_NONE; import static midpcalc.Real.NumberFormat.FSE_SCI; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.List; + +import static midpcalc.Real.NumberFormat.*; public class JsclMathEngine implements MathEngine { @@ -65,14 +72,6 @@ public class JsclMathEngine implements MathEngine { return instance; } - private static int integerValue(final double value) throws NotIntegerException { - if (Math.floor(value) == value) { - return (int) value; - } else { - throw NotIntegerException.get(); - } - } - @Nonnull public String evaluate(@Nonnull String expression) throws ParseException { return evaluateGeneric(expression).toString(); @@ -252,21 +251,6 @@ public class JsclMathEngine implements MathEngine { return null; } - @Nonnull - public String convert(@Nonnull Double value, @Nonnull NumeralBase to) { - String ungroupedValue; - try { - // check if double can be converted to integer - integerValue(value); - - ungroupedValue = to.toString(new BigDecimal(value).toBigInteger()); - } catch (NotIntegerException e) { - ungroupedValue = to.toString(value, precision); - } - - return addGroupingSeparators(to, ungroupedValue); - } - @Nonnull public MessageRegistry getMessageRegistry() { return messageRegistry; @@ -277,32 +261,35 @@ public class JsclMathEngine implements MathEngine { } @Nonnull - public String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedDoubleValue) { - if (hasGroupingSeparator()) { - final String groupingSeparator = getGroupingSeparator(nb); - - final int dotIndex = ungroupedDoubleValue.indexOf("."); - - String ungroupedValue; - if (dotIndex >= 0) { - ungroupedValue = ungroupedDoubleValue.substring(0, dotIndex); - } else { - ungroupedValue = ungroupedDoubleValue; - } - // inject group separator in the resulted string - // NOTE: space symbol is always used!!! - StringBuilder result = insertSeparators(nb, groupingSeparator, ungroupedValue, true); - - result = result.reverse(); - - if (dotIndex >= 0) { - result.append(insertSeparators(nb, groupingSeparator, ungroupedDoubleValue.substring(dotIndex), false)); - } - - return result.toString(); - } else { - return ungroupedDoubleValue; + @Override + public String format(@Nonnull String value, @Nonnull NumeralBase nb) { + if (!useGroupingSeparator) { + return value; } + final int dot = value.indexOf('.'); + if (dot >= 0) { + final String intPart = dot != 0 ? insertSeparators(value.substring(0, dot), nb) : ""; + return intPart + value.substring(dot); + } + final int e = nb == NumeralBase.hex ? -1 : value.indexOf('E'); + if (e >= 0) { + final String intPart = e != 0 ? insertSeparators(value.substring(0, e), nb) : ""; + return intPart + value.substring(e); + } + return insertSeparators(value, nb); + } + + @Nonnull + public String insertSeparators(@Nonnull String value, @Nonnull NumeralBase nb) { + final String separator = getGroupingSeparator(nb); + final StringBuilder result = new StringBuilder(value.length() + nb.getGroupingSize() * separator.length()); + for (int i = value.length() - 1; i >= 0; i--) { + result.append(value.charAt(i)); + if (i != 0 && (value.length() - i) % nb.getGroupingSize() == 0) { + result.append(separator); + } + } + return result.reverse().toString(); } private boolean hasGroupingSeparator() { @@ -318,30 +305,8 @@ public class JsclMathEngine implements MathEngine { return nb == NumeralBase.dec ? groupingSeparator : ' '; } - @Nonnull - private StringBuilder insertSeparators(@Nonnull NumeralBase nb, - @Nonnull String groupingSeparator, - @Nonnull String value, - boolean reversed) { - final StringBuilder result = new StringBuilder(value.length() + nb.getGroupingSize() * groupingSeparator.length()); - - if (reversed) { - for (int i = value.length() - 1; i >= 0; i--) { - result.append(value.charAt(i)); - if (i != 0 && (value.length() - i) % nb.getGroupingSize() == 0) { - result.append(groupingSeparator); - } - } - } else { - for (int i = 0; i < value.length(); i++) { - result.append(value.charAt(i)); - if (i != 0 && i != value.length() - 1 && i % nb.getGroupingSize() == 0) { - result.append(groupingSeparator); - } - } - } - - return result; + public void setRoundResult(boolean roundResult) { + this.roundResult = roundResult; } public void setPrecision(int precision) { diff --git a/jscl/src/main/java/jscl/MathContext.java b/jscl/src/main/java/jscl/MathContext.java index 2a9dcdb3..ef9d9155 100644 --- a/jscl/src/main/java/jscl/MathContext.java +++ b/jscl/src/main/java/jscl/MathContext.java @@ -51,7 +51,7 @@ public interface MathContext { String format(double value, @Nonnull NumeralBase nb); @Nonnull - String addGroupingSeparators(@Nonnull NumeralBase nb, @Nonnull String ungroupedIntValue); + String format(@Nonnull String value, @Nonnull NumeralBase nb); void setNotation(int notation); } diff --git a/jscl/src/main/java/jscl/MathEngine.java b/jscl/src/main/java/jscl/MathEngine.java index a082c9a5..e2412c13 100644 --- a/jscl/src/main/java/jscl/MathEngine.java +++ b/jscl/src/main/java/jscl/MathEngine.java @@ -26,9 +26,6 @@ public interface MathEngine extends MathContext { @Nonnull Generic elementaryGeneric(@Nonnull String expression) throws ParseException; - @Nonnull - String convert(@Nonnull Double value, @Nonnull NumeralBase to); - @Nonnull MessageRegistry getMessageRegistry(); From 12715e04a05f14f995eefe46dd617eb8cd6cc42c Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 14:20:27 +0200 Subject: [PATCH 13/16] Store grouping separator in integer preference and remove boolean from Engine --- .../android/calculator/preferences/NumberFormatPreference.java | 1 + jscl/src/test/java/jscl/JsclMathEngineTest.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index f921f8a6..a7424ae4 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -21,6 +21,7 @@ import org.solovyev.common.NumberFormatter; import butterknife.Bind; import butterknife.ButterKnife; +import jscl.JsclMathEngine; import static org.solovyev.android.calculator.Engine.Preferences.Output; diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java index d2e3583f..9f35aa77 100644 --- a/jscl/src/test/java/jscl/JsclMathEngineTest.java +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -6,6 +6,8 @@ import org.solovyev.common.NumberFormatter; import midpcalc.Real; +import midpcalc.Real; + import static org.junit.Assert.assertEquals; /** From 4e3527c91cb136d8b1c6ac5027d292c4c002a808 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 17:16:56 +0200 Subject: [PATCH 14/16] Remove round preference --- .../android/calculator/preferences/NumberFormatPreference.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java index a7424ae4..f921f8a6 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java @@ -21,7 +21,6 @@ import org.solovyev.common.NumberFormatter; import butterknife.Bind; import butterknife.ButterKnife; -import jscl.JsclMathEngine; import static org.solovyev.android.calculator.Engine.Preferences.Output; From 49ab48a44c36baf419a202f73f81e2971bcc92e0 Mon Sep 17 00:00:00 2001 From: serso Date: Mon, 2 May 2016 22:48:12 +0200 Subject: [PATCH 15/16] Fix tests --- jscl/src/main/java/jscl/JsclMathEngine.java | 35 ++---- .../org/solovyev/common/NumberFormatter.java | 14 +-- .../test/java/jscl/JsclMathEngineTest.java | 2 +- jscl/src/test/java/jscl/NumeralBaseTest.java | 2 +- .../test/java/jscl/math/ExpressionTest.java | 104 +++++++++--------- .../math/function/CustomFunctionTest.java | 10 +- .../test/java/jscl/math/function/RadTest.java | 8 +- .../java/jscl/math/function/SqrtTest.java | 8 +- .../math/function/trigonometric/CosTest.java | 6 +- .../math/function/trigonometric/SinTest.java | 8 +- .../math/function/trigonometric/TanTest.java | 6 +- .../java/jscl/math/numeric/ComplexTest.java | 6 +- .../solovyev/common/NumberFormatterTest.java | 9 +- 13 files changed, 97 insertions(+), 121 deletions(-) diff --git a/jscl/src/main/java/jscl/JsclMathEngine.java b/jscl/src/main/java/jscl/JsclMathEngine.java index 334d6971..1ed2adc6 100644 --- a/jscl/src/main/java/jscl/JsclMathEngine.java +++ b/jscl/src/main/java/jscl/JsclMathEngine.java @@ -1,17 +1,5 @@ package jscl; -import org.solovyev.common.NumberFormatter; -import org.solovyev.common.math.MathRegistry; -import org.solovyev.common.msg.MessageRegistry; -import org.solovyev.common.msg.Messages; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import jscl.math.Expression; import jscl.math.Generic; import jscl.math.NotIntegerException; @@ -27,6 +15,10 @@ import jscl.math.operator.Percent; import jscl.math.operator.Rand; import jscl.math.operator.matrix.OperatorsRegistry; import jscl.text.ParseException; +import org.solovyev.common.NumberFormatter; +import org.solovyev.common.math.MathRegistry; +import org.solovyev.common.msg.MessageRegistry; +import org.solovyev.common.msg.Messages; import static midpcalc.Real.NumberFormat.FSE_ENG; import static midpcalc.Real.NumberFormat.FSE_NONE; @@ -177,7 +169,7 @@ public class JsclMathEngine implements MathEngine { private NumberFormatter prepareNumberFormatter(@Nonnull NumeralBase nb) { final NumberFormatter nf = numberFormatter.get(); - nf.setGroupingSeparator(hasGroupingSeparator() ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING); + nf.setGroupingSeparator(hasGroupingSeparator() ? getGroupingSeparator(nb) : NumberFormatter.NO_GROUPING); nf.setPrecision(precision); switch (notation) { case FSE_ENG: @@ -263,7 +255,7 @@ public class JsclMathEngine implements MathEngine { @Nonnull @Override public String format(@Nonnull String value, @Nonnull NumeralBase nb) { - if (!useGroupingSeparator) { + if (!hasGroupingSeparator()) { return value; } final int dot = value.indexOf('.'); @@ -281,8 +273,8 @@ public class JsclMathEngine implements MathEngine { @Nonnull public String insertSeparators(@Nonnull String value, @Nonnull NumeralBase nb) { - final String separator = getGroupingSeparator(nb); - final StringBuilder result = new StringBuilder(value.length() + nb.getGroupingSize() * separator.length()); + final char separator = getGroupingSeparator(nb); + final StringBuilder result = new StringBuilder(value.length() + nb.getGroupingSize()); for (int i = value.length() - 1; i >= 0; i--) { result.append(value.charAt(i)); if (i != 0 && (value.length() - i) % nb.getGroupingSize() == 0) { @@ -296,19 +288,10 @@ public class JsclMathEngine implements MathEngine { return groupingSeparator != NumberFormatter.NO_GROUPING; } - @Nonnull - private String getGroupingSeparator(@Nonnull NumeralBase nb) { - return nb == NumeralBase.dec ? String.valueOf(groupingSeparator) : " "; - } - - private char getGroupingSeparatorChar(@Nonnull NumeralBase nb) { + private char getGroupingSeparator(@Nonnull NumeralBase nb) { return nb == NumeralBase.dec ? groupingSeparator : ' '; } - public void setRoundResult(boolean roundResult) { - this.roundResult = roundResult; - } - public void setPrecision(int precision) { this.precision = precision; } diff --git a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java index e5fa934a..5d424c9f 100644 --- a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java +++ b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java @@ -1,17 +1,13 @@ package org.solovyev.common; -import java.math.BigDecimal; -import java.math.BigInteger; - -import javax.annotation.Nonnull; - import midpcalc.Real; +import javax.annotation.Nonnull; +import java.math.BigDecimal; +import java.math.BigInteger; + import static java.lang.Math.pow; -import static midpcalc.Real.NumberFormat.FSE_ENG; -import static midpcalc.Real.NumberFormat.FSE_FIX; -import static midpcalc.Real.NumberFormat.FSE_NONE; -import static midpcalc.Real.NumberFormat.FSE_SCI; +import static midpcalc.Real.NumberFormat.*; public class NumberFormatter { diff --git a/jscl/src/test/java/jscl/JsclMathEngineTest.java b/jscl/src/test/java/jscl/JsclMathEngineTest.java index 9f35aa77..d3e9273d 100644 --- a/jscl/src/test/java/jscl/JsclMathEngineTest.java +++ b/jscl/src/test/java/jscl/JsclMathEngineTest.java @@ -90,7 +90,7 @@ public class JsclMathEngineTest { @Test public void testPiComputation() throws Exception { - assertEquals("-1+0.0000000000000001*i", me.evaluate("exp(√(-1)*Π)")); + assertEquals("-1+0*i", me.evaluate("exp(√(-1)*Π)")); } @Test diff --git a/jscl/src/test/java/jscl/NumeralBaseTest.java b/jscl/src/test/java/jscl/NumeralBaseTest.java index 055d68b9..e39aae05 100644 --- a/jscl/src/test/java/jscl/NumeralBaseTest.java +++ b/jscl/src/test/java/jscl/NumeralBaseTest.java @@ -77,7 +77,7 @@ public class NumeralBaseTest { assertEquals("11111110", me.evaluate("111001+11000101")); assertEquals("1101100100101111", me.evaluate("11011001001011110/10")); assertEquals("1001000011001010", me.evaluate("11011001001011110/11")); - assertEquals("0.1010101010101011", me.evaluate("10/11")); + assertEquals("0.101010101010101", me.evaluate("10/11")); me.setNumeralBase(NumeralBase.hex); assertEquals("637B", me.evaluate("56CE+CAD")); diff --git a/jscl/src/test/java/jscl/math/ExpressionTest.java b/jscl/src/test/java/jscl/math/ExpressionTest.java index a45fbc7b..6432eabd 100644 --- a/jscl/src/test/java/jscl/math/ExpressionTest.java +++ b/jscl/src/test/java/jscl/math/ExpressionTest.java @@ -1,19 +1,5 @@ package jscl.math; -import org.junit.Test; -import org.solovyev.common.NumberFormatter; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Set; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - import jscl.AngleUnit; import jscl.JsclMathEngine; import jscl.MathEngine; @@ -23,10 +9,20 @@ import jscl.math.function.ExtendedConstant; import jscl.math.function.IConstant; import jscl.text.ParseException; import midpcalc.Real; +import org.junit.Test; +import org.solovyev.common.NumberFormatter; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Set; + +import static org.junit.Assert.*; public class ExpressionTest { @@ -145,7 +141,7 @@ public class ExpressionTest { @Test public void testExpressions() throws Exception { assertEquals("3", Expression.valueOf("3").numeric().toString()); - assertEquals("0.6931471805599453", Expression.valueOf("ln(2)").numeric().toString()); + assertEquals("0.693147180559945", Expression.valueOf("ln(2)").numeric().toString()); assertEquals("1", Expression.valueOf("lg(10)").numeric().toString()); assertEquals("0", Expression.valueOf("eq(0, 1)").numeric().toString()); assertEquals("1", Expression.valueOf("eq(1, 1)").numeric().toString()); @@ -168,7 +164,7 @@ public class ExpressionTest { final AngleUnit angleUnits = me.getAngleUnits(); try { me.setAngleUnits(AngleUnit.rad); - assertEquals("-0.9055783620066238", Expression.valueOf("sin(4!)").numeric().toString()); + assertEquals("-0.905578362006624", Expression.valueOf("sin(4!)").numeric().toString()); } finally { me.setAngleUnits(angleUnits); } @@ -180,7 +176,7 @@ public class ExpressionTest { } catch (NotIntegerException e) { } - assertEquals("0.5235987755982988", Expression.valueOf("3.141592653589793/3!").numeric().toString()); + assertEquals("0.523598775598299", Expression.valueOf("3.141592653589793/3!").numeric().toString()); try { assertEquals("3.141592653589793/3.141592653589793!", Expression.valueOf("3.141592653589793/3.141592653589793!").numeric().toString()); fail(); @@ -212,14 +208,14 @@ public class ExpressionTest { final AngleUnit defaultAngleUnits = me.getAngleUnits(); try { me.setAngleUnits(AngleUnit.rad); - assertEquals("0.0174532925199433", Expression.valueOf("1°").numeric().toString()); - assertEquals("0.0349065850398866", Expression.valueOf("2°").numeric().toString()); - assertEquals("0.0523598775598299", Expression.valueOf("3°").numeric().toString()); - assertEquals("0.2617993877991495", Expression.valueOf("3°*5").numeric().toString()); - assertEquals("0.0027415567780804", Expression.valueOf("3°^2").numeric().toString()); - assertEquals("0.0109662271123215", Expression.valueOf("3!°^2").numeric().toString()); - assertEquals("0.0009138522593601", Expression.valueOf("3°°").numeric().toString()); - assertEquals("0.0872664625997165", Expression.valueOf("5°").numeric().toString()); + assertEquals("0.017453292519943", Expression.valueOf("1°").numeric().toString()); + assertEquals("0.034906585039887", Expression.valueOf("2°").numeric().toString()); + assertEquals("0.05235987755983", Expression.valueOf("3°").numeric().toString()); + assertEquals("0.261799387799149", Expression.valueOf("3°*5").numeric().toString()); + assertEquals("0.00274155677808", Expression.valueOf("3°^2").numeric().toString()); + assertEquals("0.010966227112322", Expression.valueOf("3!°^2").numeric().toString()); + assertEquals("0.00091385225936", Expression.valueOf("3°°").numeric().toString()); + assertEquals("0.087266462599716", Expression.valueOf("5°").numeric().toString()); assertEquals("2.05235987755983", Expression.valueOf("2+3°").numeric().toString()); } finally { me.setAngleUnits(defaultAngleUnits); @@ -377,7 +373,7 @@ public class ExpressionTest { try { me.setAngleUnits(AngleUnit.rad); - assertEquals("0.6931471805599453+Π*i", Expression.valueOf("ln(-2)").numeric().toString()); + assertEquals("0.693147180559945+Π*i", Expression.valueOf("ln(-2)").numeric().toString()); } finally { me.setAngleUnits(AngleUnit.deg); } @@ -387,7 +383,7 @@ public class ExpressionTest { assertEquals("sin(n!)", Expression.valueOf("sin(n!)").expand().toString()); assertEquals("sin(n°)", Expression.valueOf("sin(n°)").expand().toString()); assertEquals("sin(30°)", Expression.valueOf("sin(30°)").expand().toString()); - assertEquals("0.4999999999999999", Expression.valueOf("sin(30°)").expand().numeric().toString()); + assertEquals("0.5", Expression.valueOf("sin(30°)").expand().numeric().toString()); assertEquals("sin(2!)", Expression.valueOf("sin(2!)").expand().toString()); assertEquals("12", Expression.valueOf("3*(3+1)").expand().toString()); @@ -408,7 +404,7 @@ public class ExpressionTest { } catch (ParseException e) { } - assertEquals("0.4999999999999999", Expression.valueOf("sin(30°)").numeric().toString()); + assertEquals("0.5", Expression.valueOf("sin(30°)").numeric().toString()); assertEquals("π", Expression.valueOf("√(π)^2").simplify().toString()); assertEquals("π", Expression.valueOf("√(π^2)").simplify().toString()); assertEquals("π^2", Expression.valueOf("√(π^2*π^2)").simplify().toString()); @@ -420,7 +416,7 @@ public class ExpressionTest { // in deg mode π=180 and factorial of 180 is calculating assertEquals("0", Expression.valueOf("Π/Π!").numeric().toString()); - assertEquals("0.0000000000000001*i", Expression.valueOf("exp((Π*i))+1").numeric().toString()); + assertEquals("0*i", Expression.valueOf("exp((Π*i))+1").numeric().toString()); assertEquals("20*x^3", Expression.valueOf("∂(5*x^4, x)").expand().simplify().toString()); assertEquals("25*x", Expression.valueOf("5*x*5").expand().simplify().toString()); assertEquals("20*x", Expression.valueOf("5*x*4").expand().simplify().toString()); @@ -442,10 +438,10 @@ public class ExpressionTest { try { me.setNumeralBase(NumeralBase.hex); - assertEquals("0.EEEEEEEEEEEEEC88", me.evaluate("0x:E/0x:F")); + assertEquals("0.EEEEEEEEEEEEEC9", me.evaluate("0x:E/0x:F")); assertEquals("E/F", me.simplify("0x:E/0x:F")); - assertEquals("0.EEEEEEEEEEEEEC88", me.evaluate("E/F")); + assertEquals("0.EEEEEEEEEEEEEC9", me.evaluate("E/F")); assertEquals("E/F", me.simplify("E/F")); } finally { @@ -472,9 +468,9 @@ public class ExpressionTest { assertEquals("-1.471127674303735", me.evaluate("atan(-10)")); assertEquals("-1.10714871779409", me.evaluate("atan(-2)")); - assertEquals("-0.7853981633974483", me.evaluate("atan(-1)")); + assertEquals("-0.785398163397448", me.evaluate("atan(-1)")); assertEquals("0", me.evaluate("atan(0)")); - assertEquals("0.7853981633974483", me.evaluate("atan(1)")); + assertEquals("0.785398163397448", me.evaluate("atan(1)")); assertEquals("1.10714871779409", me.evaluate("atan(2)")); assertEquals("1.471127674303735", me.evaluate("atan(10)")); @@ -487,9 +483,9 @@ public class ExpressionTest { assertEquals("1.570796326794897", me.evaluate("acot(0)")); assertEquals("2.677945044588987", me.evaluate("acot(-2)")); assertEquals("2.356194490192345", me.evaluate("acot(-1)")); - assertEquals("0.7853981633974483", me.evaluate("acot(1)")); - assertEquals("0.4636476090008062", me.evaluate("acot(2)")); - assertEquals("0.0996686524911619", me.evaluate("acot(10)")); + assertEquals("0.785398163397448", me.evaluate("acot(1)")); + assertEquals("0.463647609000806", me.evaluate("acot(2)")); + assertEquals("0.099668652491162", me.evaluate("acot(10)")); assertEquals("Π", me.evaluate("π")); assertEquals("Π", me.evaluate("3.14159265358979323846")); @@ -638,12 +634,12 @@ public class ExpressionTest { try { mathEngine.setAngleUnits(AngleUnit.rad); testSinEqualsToSinh(mathEngine, 0d); - testSinEqualsToSinh(mathEngine, 1d, "0.8414709848078965"); - testSinEqualsToSinh(mathEngine, 3d, "0.1411200080598672"); + testSinEqualsToSinh(mathEngine, 1d, "0.841470984807897"); + testSinEqualsToSinh(mathEngine, 3d, "0.141120008059867"); testSinEqualsToSinh(mathEngine, 6d); - testSinEqualsToSinh(mathEngine, -1d, "-0.8414709848078965"); - testSinEqualsToSinh(mathEngine, -3.3d, "0.1577456941432482"); - testSinEqualsToSinh(mathEngine, -232.2d, "0.2742948637368958"); + testSinEqualsToSinh(mathEngine, -1d, "-0.841470984807897"); + testSinEqualsToSinh(mathEngine, -3.3d, "0.157745694143248"); + testSinEqualsToSinh(mathEngine, -232.2d, "0.274294863736896"); } finally { mathEngine.setAngleUnits(defaultAngleUnits); } @@ -651,12 +647,12 @@ public class ExpressionTest { try { mathEngine.setAngleUnits(AngleUnit.deg); testSinEqualsToSinh(mathEngine, 0d); - testSinEqualsToSinh(mathEngine, 1d, "0.0174524064372835"); - testSinEqualsToSinh(mathEngine, 3d, "0.0523359562429438"); - testSinEqualsToSinh(mathEngine, 6d, "0.1045284632676535"); - testSinEqualsToSinh(mathEngine, -1d, "-0.0174524064372835"); - testSinEqualsToSinh(mathEngine, -3.3d, "-0.0575640269595673"); - testSinEqualsToSinh(mathEngine, -232.2d, "0.7901550123756904"); + testSinEqualsToSinh(mathEngine, 1d, "0.017452406437284"); + testSinEqualsToSinh(mathEngine, 3d, "0.052335956242944"); + testSinEqualsToSinh(mathEngine, 6d, "0.104528463267653"); + testSinEqualsToSinh(mathEngine, -1d, "-0.017452406437284"); + testSinEqualsToSinh(mathEngine, -3.3d, "-0.057564026959567"); + testSinEqualsToSinh(mathEngine, -232.2d, "0.79015501237569"); assertEquals("Π/2", mathEngine.simplify("Π/2")); } finally { mathEngine.setAngleUnits(defaultAngleUnits); @@ -732,7 +728,7 @@ public class ExpressionTest { final AngleUnit defaultAngleUnits = JsclMathEngine.getInstance().getAngleUnits(); try { JsclMathEngine.getInstance().setAngleUnits(AngleUnit.rad); - assertEquals("-0.9092974268256817", Expression.valueOf("∂(cos(t),t,2)").numeric().toString()); + assertEquals("-0.909297426825682", Expression.valueOf("∂(cos(t),t,2)").numeric().toString()); assertEquals("∂(cos(t), t, 2, 1)", Expression.valueOf("∂(cos(t),t,2)").simplify().toString()); assertEquals("-2.234741690198506", Expression.valueOf("∂(t*cos(t),t,2)").numeric().toString()); assertEquals("-4.469483380397012", Expression.valueOf("2*∂(t*cos(t),t,2)").numeric().toString()); @@ -760,7 +756,7 @@ public class ExpressionTest { assertEquals(Expression.valueOf("3").numeric().toString(), Expression.valueOf("Σ(n°,n,1,2)").expand().numeric().toString()); assertEquals("200", Expression.valueOf("Σ(n°/n°,n,1,200)").expand().numeric().toString()); assertEquals("-sin(1)-sin(2)", Expression.valueOf("Σ(∂(cos(t),t,n),n,1,2)").expand().toString()); - assertEquals("-0.0523519031397845", Expression.valueOf("Σ(∂(cos(t),t,n),n,1,2)").expand().numeric().toString()); + assertEquals("-0.052351903139784", Expression.valueOf("Σ(∂(cos(t),t,n),n,1,2)").expand().numeric().toString()); } @Test @@ -819,10 +815,10 @@ public class ExpressionTest { assertEquals("1.222E-6", Expression.valueOf("1222/(10^9)").numeric().toString()); me.setNotation(Real.NumberFormat.FSE_NONE); - assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); + assertEquals("0.333333333333333", Expression.valueOf("1/3").numeric().toString()); me.setNotation(Real.NumberFormat.FSE_SCI); - assertEquals("0.3333333333333333", Expression.valueOf("1/3").numeric().toString()); + assertEquals("0.333333333333333", Expression.valueOf("1/3").numeric().toString()); me.setPrecision(10); assertEquals("0.3333333333", Expression.valueOf("1/3").numeric().toString()); diff --git a/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java b/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java index 3d03fc7b..6bd70815 100644 --- a/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java +++ b/jscl/src/test/java/jscl/math/function/CustomFunctionTest.java @@ -37,7 +37,7 @@ public class CustomFunctionTest { assertEquals("∞", Expression.valueOf("log(1, 10)").numeric().toString()); assertEquals("3.321928094887363", Expression.valueOf("log(2, 10)").numeric().toString()); assertEquals("1.430676558073393", Expression.valueOf("log(5, 10)").numeric().toString()); - assertEquals("0.9602525677891275", Expression.valueOf("log(11, 10)").numeric().toString()); + assertEquals("0.960252567789128", Expression.valueOf("log(11, 10)").numeric().toString()); assertEquals("1/b*1/ln(a)", Expression.valueOf("∂(log(a, b), b)").expand().toString()); assertEquals("-1/a*(1/ln(a))^2*ln(b)", Expression.valueOf("∂(log(a, b), a)").expand().toString()); @@ -133,10 +133,10 @@ public class CustomFunctionTest { final CustomFunction.Builder jBuilder4 = new CustomFunction.Builder("testFunction5", asList("a", "b"), "testFunction2(a, b/2, 2, 1) - testFunction(a, b!, 4!, 1)"); mathEngine.getFunctionsRegistry().addOrUpdate(jBuilder4.create()); - assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); - assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); - assertEquals("0.4996954135095478", Expression.valueOf("testFunction5(2*1, 3)").numeric().toString()); - assertEquals("-0.0000000000000001", Expression.valueOf("testFunction5(2*1, 2^2-1+e^0)").numeric().toString()); + assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); + assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2, 3)").numeric().toString()); + assertEquals("0.499695413509548", Expression.valueOf("testFunction5(2*1, 3)").numeric().toString()); + assertEquals("0", Expression.valueOf("testFunction5(2*1, 2^2-1+e^0)").numeric().toString()); try { Expression.valueOf("testFunction5(2, 3.5)").numeric(); diff --git a/jscl/src/test/java/jscl/math/function/RadTest.java b/jscl/src/test/java/jscl/math/function/RadTest.java index 5f9b3719..45e548d8 100644 --- a/jscl/src/test/java/jscl/math/function/RadTest.java +++ b/jscl/src/test/java/jscl/math/function/RadTest.java @@ -10,10 +10,10 @@ public class RadTest { public void testRad() throws Exception { final JsclMathEngine mathEngine = new JsclMathEngine(); - assertEquals("0.0349065850398866", mathEngine.evaluate("rad(2)")); - assertEquals("0.0349065850398866", mathEngine.evaluate("rad(1+1)")); - assertEquals("-0.0349065850398866", mathEngine.evaluate("rad(-2)")); - assertEquals("-0.0349065850398866", mathEngine.evaluate("rad(-1-1)")); + assertEquals("0.034906585039887", mathEngine.evaluate("rad(2)")); + assertEquals("0.034906585039887", mathEngine.evaluate("rad(1+1)")); + assertEquals("-0.034906585039887", mathEngine.evaluate("rad(-2)")); + assertEquals("-0.034906585039887", mathEngine.evaluate("rad(-1-1)")); assertEquals("π", mathEngine.evaluate("rad(180)")); assertEquals(String.valueOf(-Math.PI), mathEngine.evaluate("rad(-180)")); diff --git a/jscl/src/test/java/jscl/math/function/SqrtTest.java b/jscl/src/test/java/jscl/math/function/SqrtTest.java index 0d365858..78634d13 100644 --- a/jscl/src/test/java/jscl/math/function/SqrtTest.java +++ b/jscl/src/test/java/jscl/math/function/SqrtTest.java @@ -13,13 +13,13 @@ public class SqrtTest { final JsclMathEngine me = JsclMathEngine.getInstance(); final AngleUnit defaultAngleUnits = me.getAngleUnits(); - assertEquals("0.9999060498015505+0.0137073546047075*i", me.evaluate("√(√(-1))")); - assertEquals("0.9984971498638638+0.0548036651487895*i", me.evaluate("√(√(-1))^4")); + assertEquals("0.999906049801551+0.013707354604707*i", me.evaluate("√(√(-1))")); + assertEquals("0.998497149863864+0.05480366514879*i", me.evaluate("√(√(-1))^4")); try { me.setAngleUnits(AngleUnit.rad); - assertEquals("0.7071067811865476+0.7071067811865475*i", me.evaluate("√(√(-1))")); - assertEquals("-1+0.0000000000000003*i", me.evaluate("√(√(-1))^4")); + assertEquals("0.707106781186548+0.707106781186548*i", me.evaluate("√(√(-1))")); + assertEquals("-1+0*i", me.evaluate("√(√(-1))^4")); } finally { me.setAngleUnits(defaultAngleUnits); } diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java index 1fa9e052..16631d9d 100644 --- a/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java +++ b/jscl/src/test/java/jscl/math/function/trigonometric/CosTest.java @@ -20,9 +20,9 @@ public class CosTest { me.getConstantsRegistry().addOrUpdate(t.create()); Assert.assertEquals("-sin(t)", me.simplify("∂(cos(t),t,t,1)")); Assert.assertEquals("∂(cos(t), t, t, 1°)", me.simplify("∂(cos(t),t,t,1°)")); - Assert.assertEquals("-0.1736481776669303", me.evaluate("∂(cos(t),t,t,1)")); + Assert.assertEquals("-0.17364817766693", me.evaluate("∂(cos(t),t,t,1)")); Assert.assertEquals("∂(cos(t), t, t, 1°)", me.evaluate("∂(cos(t),t,t,1°)")); - Assert.assertEquals("-0.1736481776669303", me.evaluate("∂(cos(t),t,t,2-1)")); - Assert.assertEquals("-0.1736481776669303", me.evaluate("∂(cos(t),t,t,2^5-31)")); + Assert.assertEquals("-0.17364817766693", me.evaluate("∂(cos(t),t,t,2-1)")); + Assert.assertEquals("-0.17364817766693", me.evaluate("∂(cos(t),t,t,2^5-31)")); } } diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java index f9285248..4599cfe5 100644 --- a/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java +++ b/jscl/src/test/java/jscl/math/function/trigonometric/SinTest.java @@ -26,9 +26,9 @@ public class SinTest { try { me.setAngleUnits(AngleUnit.rad); - Assert.assertEquals("0.5403023058681398", me.evaluate("cos(1)")); - Assert.assertEquals("0.3623577544766736", me.evaluate("cos(1.2)")); - Assert.assertEquals("0.1779445513914661", me.evaluate("∫ab(sin(x), x, 1, 1.2)")); + Assert.assertEquals("0.54030230586814", me.evaluate("cos(1)")); + Assert.assertEquals("0.362357754476674", me.evaluate("cos(1.2)")); + Assert.assertEquals("0.177944551391466", me.evaluate("∫ab(sin(x), x, 1, 1.2)")); } finally { me.setAngleUnits(AngleUnit.deg); } @@ -38,7 +38,7 @@ public class SinTest { try { me.setAngleUnits(AngleUnit.rad); - Assert.assertEquals("0.1339745962155613", me.evaluate("∫ab(sin(x), x, 0, 30°)")); + Assert.assertEquals("0.133974596215561", me.evaluate("∫ab(sin(x), x, 0, 30°)")); } finally { me.setAngleUnits(AngleUnit.deg); } diff --git a/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java b/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java index 45f1358f..728cb939 100644 --- a/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java +++ b/jscl/src/test/java/jscl/math/function/trigonometric/TanTest.java @@ -29,9 +29,9 @@ public class TanTest { me.setAngleUnits(AngleUnit.rad); assertEquals("-2*ln(2)-ln(cos(x))", me.simplify("∫(tan(x), x)")); assertEquals("-(2*ln(2)+ln(cos(x*π)))/π", me.simplify("∫(tan(π*x), x)")); - assertEquals("-0.0153088314659858", me.evaluate("ln(cos(10*π/180))")); - assertEquals("-0.1438410362258904", me.evaluate("ln(cos(30*π/180))")); - assertEquals("0.1285322047599047", me.evaluate("∫ab(tan(x), x, 10*π/180, 30*π/180)")); + assertEquals("-0.015308831465986", me.evaluate("ln(cos(10*π/180))")); + assertEquals("-0.14384103622589", me.evaluate("ln(cos(30*π/180))")); + assertEquals("0.128532204759905", me.evaluate("∫ab(tan(x), x, 10*π/180, 30*π/180)")); } finally { me.setAngleUnits(AngleUnit.deg); } diff --git a/jscl/src/test/java/jscl/math/numeric/ComplexTest.java b/jscl/src/test/java/jscl/math/numeric/ComplexTest.java index e884b8fd..bf233395 100644 --- a/jscl/src/test/java/jscl/math/numeric/ComplexTest.java +++ b/jscl/src/test/java/jscl/math/numeric/ComplexTest.java @@ -11,8 +11,8 @@ public class ComplexTest { @Test public void testSmallImag() throws Exception { - assertEquals("1+0.0000000000000001*i", Complex.valueOf(1, 0.0000000000000001).toString()); - assertEquals("1-0.0000000000000001*i", Complex.valueOf(1, -0.0000000000000001).toString()); + assertEquals("1+0.000000000000001*i", Complex.valueOf(1, 0.000000000000001).toString()); + assertEquals("1-0.000000000000001*i", Complex.valueOf(1, -0.000000000000001).toString()); } @Test @@ -23,7 +23,7 @@ public class ComplexTest { assertEquals("1.175201193643801*i", Expression.valueOf("sin(i)").numeric().toString()); assertEquals("11013.2328747034*i", Expression.valueOf("sin(10*i)").numeric().toString()); assertEquals("11013.23292010332", Expression.valueOf("cos(10*i)").numeric().toString()); - assertEquals("0.4621171572600097*i", Expression.valueOf("tan(i/2)").numeric().toString()); + assertEquals("0.46211715726001*i", Expression.valueOf("tan(i/2)").numeric().toString()); assertEquals("-2.163953413738653*i", Expression.valueOf("cot(i/2)").numeric().toString()); } finally { JsclMathEngine.getInstance().setAngleUnits(JsclMathEngine.DEFAULT_ANGLE_UNITS); diff --git a/jscl/src/test/java/org/solovyev/common/NumberFormatterTest.java b/jscl/src/test/java/org/solovyev/common/NumberFormatterTest.java index e7847319..e9dd8315 100644 --- a/jscl/src/test/java/org/solovyev/common/NumberFormatterTest.java +++ b/jscl/src/test/java/org/solovyev/common/NumberFormatterTest.java @@ -36,11 +36,11 @@ public class NumberFormatterTest { numberFormatter.setPrecision(NO_ROUNDING); assertEquals("1", numberFormatter.format(1d)); - assertEquals("0.3333333333333333", numberFormatter.format(1d / 3)); + assertEquals("0.333333333333333", numberFormatter.format(1d / 3)); assertEquals("3.333333333333333E-19", numberFormatter.format(pow(10, -18) / 3)); assertEquals("1.23456789E18", numberFormatter.format(123456789 * pow(10, 10))); assertEquals("1E-16", numberFormatter.format(pow(10, -16))); - assertEquals("5.9999999999999949E18", numberFormatter.format(5999999999999994999d)); + assertEquals("5.999999999999995E18", numberFormatter.format(5999999999999994999d)); testScientificFormat(); } @@ -68,10 +68,10 @@ public class NumberFormatterTest { assertEquals("1", numberFormatter.format(1d)); assertEquals("0.000001", numberFormatter.format(pow(10, -6))); - assertEquals("0.3333333333333333", numberFormatter.format(1d / 3)); + assertEquals("0.333333333333333", numberFormatter.format(1d / 3)); assertEquals("3.333333333333333E-19", numberFormatter.format(pow(10, -18) / 3)); assertEquals("1234567890000000000", numberFormatter.format(123456789 * pow(10, 10))); - assertEquals("0.0000000000000001", numberFormatter.format(pow(10, -16))); + assertEquals("1E-16", numberFormatter.format(pow(10, -16))); assertEquals("1E-17", numberFormatter.format(pow(10, -17))); assertEquals("1E-18", numberFormatter.format(pow(10, -18))); assertEquals("1.5E-18", numberFormatter.format(1.5 * pow(10, -18))); @@ -102,6 +102,7 @@ public class NumberFormatterTest { // testing simple format with and without rounding private void testSimpleFormat() { assertEquals("0.00001", numberFormatter.format(pow(10, -5))); + assertEquals("0.01", numberFormatter.format(3.11 - 3.1)); assertEquals("100", numberFormatter.format(pow(10, 2))); assertEquals("1", numberFormatter.format(BigInteger.ONE)); From eb1c733153b391d4fd14a29e0aa08c2627743b89 Mon Sep 17 00:00:00 2001 From: serso Date: Wed, 4 May 2016 23:39:46 +0200 Subject: [PATCH 16/16] Number format preferences screen --- .../solovyev/android/calculator/Engine.java | 78 ++++++------ .../NumberFormatExamplesPreference.java | 59 +++++++++ .../preferences/NumberFormatPreference.java | 119 ------------------ .../preferences/PrecisionPreference.java | 72 +++++++++++ .../preferences/PreferencesActivity.java | 1 + .../preferences/PreferencesFragment.java | 99 ++++++++++++++- .../android/prefs/StringPreference.java | 5 + .../solovyev/common/text/CharacterMapper.java | 27 ++++ .../res/layout/preference_number_format.xml | 45 ------- .../main/res/layout/preference_precision.xml | 11 ++ .../main/res/values/text_non_translatable.xml | 1 - app/src/main/res/xml/preferences.xml | 4 + .../main/res/xml/preferences_calculations.xml | 24 ---- .../res/xml/preferences_number_format.xml | 49 ++++++++ .../org/solovyev/common/NumberFormatter.java | 3 +- 15 files changed, 358 insertions(+), 239 deletions(-) create mode 100644 app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatExamplesPreference.java delete mode 100644 app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java create mode 100644 app/src/main/java/org/solovyev/android/calculator/preferences/PrecisionPreference.java create mode 100644 app/src/main/java/org/solovyev/common/text/CharacterMapper.java delete mode 100644 app/src/main/res/layout/preference_number_format.xml create mode 100644 app/src/main/res/layout/preference_precision.xml create mode 100644 app/src/main/res/xml/preferences_number_format.xml diff --git a/app/src/main/java/org/solovyev/android/calculator/Engine.java b/app/src/main/java/org/solovyev/android/calculator/Engine.java index e9939b9d..d9d0f779 100644 --- a/app/src/main/java/org/solovyev/android/calculator/Engine.java +++ b/app/src/main/java/org/solovyev/android/calculator/Engine.java @@ -22,35 +22,12 @@ package org.solovyev.android.calculator; +import android.content.Context; import android.content.SharedPreferences; +import android.support.annotation.NonNull; import android.support.annotation.StringRes; import android.text.TextUtils; - import com.squareup.otto.Bus; - -import org.solovyev.android.Check; -import org.solovyev.android.calculator.functions.FunctionsRegistry; -import org.solovyev.android.calculator.operators.OperatorsRegistry; -import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry; -import org.solovyev.android.prefs.BooleanPreference; -import org.solovyev.android.prefs.CharacterPreference; -import org.solovyev.android.prefs.IntegerPreference; -import org.solovyev.android.prefs.Preference; -import org.solovyev.android.prefs.StringPreference; -import org.solovyev.common.NumberFormatter; -import org.solovyev.common.text.EnumMapper; -import org.solovyev.common.text.NumberMapper; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.Executor; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; - import jscl.AngleUnit; import jscl.JsclMathEngine; import jscl.MathEngine; @@ -59,6 +36,25 @@ import jscl.math.operator.Operator; import jscl.text.Identifier; import jscl.text.Parser; import midpcalc.Real; +import org.solovyev.android.Check; +import org.solovyev.android.calculator.functions.FunctionsRegistry; +import org.solovyev.android.calculator.operators.OperatorsRegistry; +import org.solovyev.android.calculator.operators.PostfixFunctionsRegistry; +import org.solovyev.android.calculator.preferences.PreferenceEntry; +import org.solovyev.android.prefs.*; +import org.solovyev.common.text.CharacterMapper; +import org.solovyev.common.NumberFormatter; +import org.solovyev.common.text.EnumMapper; +import org.solovyev.common.text.NumberMapper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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; @Singleton public class Engine implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -98,13 +94,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene this.mathEngine.setGroupingSeparator(JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); } - private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull BooleanPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { - if (!preferences.contains(oldKey)) { - return; - } - editor.putBoolean(preference.getKey(), preferences.getBoolean(oldKey, false)); - } - private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull StringPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { if (!preferences.contains(oldKey)) { return; @@ -112,15 +101,6 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene editor.putString(preference.getKey(), preferences.getString(oldKey, null)); } - private static void migratePreference(@Nonnull SharedPreferences preferences, @Nonnull CharacterPreference preference, @Nonnull String oldKey, @Nonnull SharedPreferences.Editor editor) { - if (!preferences.contains(oldKey)) { - return; - } - final String s = preferences.getString(oldKey, null); - editor.putInt(preference.getKey(), TextUtils.isEmpty(s) ? 0 : s.charAt(0)); - } - - public static boolean isValidName(@Nullable String name) { if (!TextUtils.isEmpty(name)) { try { @@ -261,7 +241,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene } } - public enum Notation { + public enum Notation implements PreferenceEntry { dec(Real.NumberFormat.FSE_NONE, R.string.cpp_number_format_dec), eng(Real.NumberFormat.FSE_ENG, R.string.cpp_number_format_eng), sci(Real.NumberFormat.FSE_SCI, R.string.cpp_number_format_sci); @@ -274,6 +254,18 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene this.id = id; this.name = name; } + + @NonNull + @Override + public CharSequence getName(@NonNull Context context) { + return context.getString(name); + } + + @NonNull + @Override + public CharSequence getId() { + return name(); + } } public static class ChangedEvent { @@ -307,7 +299,7 @@ public class Engine implements SharedPreferences.OnSharedPreferenceChangeListene public static class Output { public static final StringPreference precision = StringPreference.ofTypedValue("engine.output.precision", "5", NumberMapper.of(Integer.class)); public static final StringPreference notation = StringPreference.ofEnum("engine.output.notation", Notation.dec, Notation.class); - public static final CharacterPreference separator = CharacterPreference.of("engine.output.separator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT); + public static final StringPreference separator = StringPreference.ofTypedValue("engine.output.separator", JsclMathEngine.GROUPING_SEPARATOR_DEFAULT, CharacterMapper.INSTANCE); } } } diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatExamplesPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatExamplesPreference.java new file mode 100644 index 00000000..9eabbbfe --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatExamplesPreference.java @@ -0,0 +1,59 @@ +package org.solovyev.android.calculator.preferences; + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import jscl.JsclMathEngine; +import org.solovyev.android.material.preferences.Preference; + +@SuppressWarnings("unused") +public class NumberFormatExamplesPreference extends Preference { + public NumberFormatExamplesPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public NumberFormatExamplesPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public NumberFormatExamplesPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public NumberFormatExamplesPreference(Context context) { + super(context); + } + + public void update(JsclMathEngine engine) { + final StringBuilder examples = new StringBuilder(); + examples.append(" 1/3 = ").append(engine.format(1d / 3)).append("\n"); + examples.append(" √2 = ").append(engine.format(Math.sqrt(2d))).append("\n"); + examples.append("\n"); + examples.append(" 1000 = ").append(engine.format(1000d)).append("\n"); + examples.append(" 1000000 = ").append(engine.format(1000000d)).append("\n"); + examples.append(" 11^10 = ").append(engine.format(Math.pow(11d, 10))).append("\n"); + examples.append(" 10^24 = ").append(engine.format(Math.pow(10d, 24))).append("\n"); + examples.append("\n"); + examples.append(" 0.001 = ").append(engine.format(0.001d)).append("\n"); + examples.append("0.000001 = ").append(engine.format(0.000001d)).append("\n"); + examples.append(" 11^−10 = ").append(engine.format(Math.pow(11d, -10))).append("\n"); + examples.append(" 10^−24 = ").append(engine.format(Math.pow(10d, -24))); + setSummary(examples); + } + + @Override + protected View onCreateView(ViewGroup parent) { + final View view = super.onCreateView(parent); + final View summary = view.findViewById(android.R.id.summary); + if (summary instanceof TextView) { + final TextView textView = (TextView) summary; + textView.setMaxLines(12); + textView.setLines(12); + textView.setTypeface(Typeface.MONOSPACE); + } + return view; + } +} diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java deleted file mode 100644 index f921f8a6..00000000 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/NumberFormatPreference.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.solovyev.android.calculator.preferences; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Build; -import android.preference.DialogPreference; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.Spinner; - -import org.solovyev.android.calculator.App; -import org.solovyev.android.calculator.Engine; -import org.solovyev.android.calculator.Named; -import org.solovyev.android.calculator.R; -import org.solovyev.android.calculator.text.NaturalComparator; -import org.solovyev.android.views.DiscreteSeekBar; -import org.solovyev.common.NumberFormatter; - -import butterknife.Bind; -import butterknife.ButterKnife; - -import static org.solovyev.android.calculator.Engine.Preferences.Output; - -public class NumberFormatPreference extends DialogPreference { - @Bind(R.id.nf_notation_spinner) - Spinner notationSpinner; - ArrayAdapter> notationAdapter; - @Bind(R.id.nf_precision_seekbar) - DiscreteSeekBar precisionSeekBar; - @Bind(R.id.nf_separator_spinner) - Spinner separatorSpinner; - ArrayAdapter> separatorAdapter; - - { - setPersistent(false); - setDialogLayoutResource(R.layout.preference_number_format); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public NumberFormatPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public NumberFormatPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - public NumberFormatPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public NumberFormatPreference(Context context) { - super(context); - } - - @Override - protected void onBindDialogView(View view) { - super.onBindDialogView(view); - ButterKnife.bind(this, view); - - final SharedPreferences preferences = getSharedPreferences(); - precisionSeekBar.setMax(NumberFormatter.MAX_PRECISION); - precisionSeekBar.setCurrentTick(Math.max(0, Math.min(NumberFormatter.MAX_PRECISION, Output.precision.getPreference(preferences)))); - notationAdapter = makeNotationAdapter(); - notationSpinner.setAdapter(notationAdapter); - notationSpinner.setSelection(indexOf(notationAdapter, Output.notation.getPreference(preferences))); - - separatorAdapter = makeSeparatorAdapter(); - separatorSpinner.setAdapter(separatorAdapter); - separatorSpinner.setSelection(indexOf(separatorAdapter, Output.separator.getPreference(preferences))); - } - - @Override - protected void onDialogClosed(boolean save) { - super.onDialogClosed(save); - if (!save) { - return; - } - final SharedPreferences.Editor editor = getSharedPreferences().edit(); - Output.precision.putPreference(editor, precisionSeekBar.getCurrentTick()); - Output.notation.putPreference(editor, notationAdapter.getItem(notationSpinner.getSelectedItemPosition()).item); - Output.separator.putPreference(editor, separatorAdapter.getItem(separatorSpinner.getSelectedItemPosition()).item); - editor.apply(); - } - - private int indexOf(ArrayAdapter> adapter, T item) { - for (int i = 0; i < adapter.getCount(); i++) { - if (adapter.getItem(i).item.equals(item)) { - return i; - } - } - return -1; - } - - @NonNull - private ArrayAdapter> makeNotationAdapter() { - final Context context = getContext(); - final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); - for (Engine.Notation notation : Engine.Notation.values()) { - adapter.add(Named.create(notation, notation.name, context)); - } - adapter.sort(NaturalComparator.INSTANCE); - return adapter; - } - - @NonNull - private ArrayAdapter> makeSeparatorAdapter() { - final Context context = getContext(); - final ArrayAdapter> adapter = App.makeSimpleSpinnerAdapter(context); - adapter.add(Named.create(NumberFormatter.NO_GROUPING, R.string.p_grouping_separator_no, context)); - adapter.add(Named.create('\'', R.string.p_grouping_separator_apostrophe, context)); - adapter.add(Named.create(' ', R.string.p_grouping_separator_space, context)); - return adapter; - } -} diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/PrecisionPreference.java b/app/src/main/java/org/solovyev/android/calculator/preferences/PrecisionPreference.java new file mode 100644 index 00000000..2b62f450 --- /dev/null +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/PrecisionPreference.java @@ -0,0 +1,72 @@ +package org.solovyev.android.calculator.preferences; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; +import butterknife.Bind; +import butterknife.ButterKnife; +import org.solovyev.android.calculator.Engine; +import org.solovyev.android.calculator.R; +import org.solovyev.android.views.DiscreteSeekBar; + +import static org.solovyev.common.NumberFormatter.MAX_PRECISION; +import static org.solovyev.common.NumberFormatter.MIN_PRECISION; + +@SuppressWarnings("unused") +public class PrecisionPreference extends DialogPreference { + + @Bind(R.id.precision_seekbar) + DiscreteSeekBar seekBar; + + { + setPersistent(false); + setDialogLayoutResource(R.layout.preference_precision); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public PrecisionPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public PrecisionPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public PrecisionPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public PrecisionPreference(Context context) { + super(context); + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + ButterKnife.bind(this, view); + + final SharedPreferences preferences = getSharedPreferences(); + seekBar.setMax(MAX_PRECISION - 1); + final int precision = Math.max(MIN_PRECISION, Math.min(MAX_PRECISION, Engine.Preferences.Output.precision.getPreference(preferences))); + seekBar.setCurrentTick(precision - 1); + } + + @Override + protected void onDialogClosed(boolean save) { + super.onDialogClosed(save); + if (!save) { + return; + } + final int precision = seekBar.getCurrentTick() + 1; + if (callChangeListener(precision)) { + final SharedPreferences.Editor editor = getSharedPreferences().edit(); + Engine.Preferences.Output.precision.putPreference(editor, precision); + editor.apply(); + } + } +} diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java index ca7312cf..930f5313 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesActivity.java @@ -35,6 +35,7 @@ public class PreferencesActivity extends BaseActivity implements SharedPreferenc static { preferenceDefs.append(R.xml.preferences, new PrefDef("screen-main", R.string.cpp_settings)); + preferenceDefs.append(R.xml.preferences_number_format, new PrefDef("screen-number-format", R.string.c_prefs_calculations_category)); preferenceDefs.append(R.xml.preferences_calculations, new PrefDef("screen-calculations", R.string.c_prefs_calculations_category)); preferenceDefs.append(R.xml.preferences_appearance, new PrefDef("screen-appearance", R.string.c_prefs_appearance_category)); preferenceDefs.append(R.xml.preferences_other, new PrefDef("screen-other", R.string.c_prefs_other_category)); diff --git a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java index 1f441473..d46c5751 100644 --- a/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/preferences/PreferencesFragment.java @@ -11,8 +11,11 @@ import android.support.v4.app.FragmentActivity; import android.util.SparseArray; import android.view.View; import android.widget.ListView; - +import com.squareup.otto.Bus; +import com.squareup.otto.Subscribe; +import jscl.JsclMathEngine; import org.solovyev.android.calculator.AdView; +import org.solovyev.android.calculator.Engine; import org.solovyev.android.calculator.Preferences; import org.solovyev.android.calculator.Preferences.Gui.Theme; import org.solovyev.android.calculator.R; @@ -22,14 +25,15 @@ import org.solovyev.android.checkout.BillingRequests; import org.solovyev.android.checkout.Checkout; import org.solovyev.android.checkout.ProductTypes; import org.solovyev.android.checkout.RequestListener; +import org.solovyev.android.prefs.StringPreference; import org.solovyev.android.wizard.Wizards; - -import java.util.Arrays; -import java.util.List; +import org.solovyev.common.text.CharacterMapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.inject.Inject; +import java.util.Arrays; +import java.util.List; import static org.solovyev.android.calculator.App.cast; import static org.solovyev.android.calculator.wizard.CalculatorWizards.DEFAULT_WIZARD_FLOW; @@ -48,11 +52,15 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc Languages languages; @Inject Wizards wizards; + @Inject + JsclMathEngine engine; + @Inject + Bus bus; @Nonnull - public static PreferencesFragment create(int preferencesResId, int layoutResId) { + public static PreferencesFragment create(int preferences, int layout) { final PreferencesFragment fragment = new PreferencesFragment(); - fragment.setArguments(createArguments(preferencesResId, layoutResId, NO_THEME)); + fragment.setArguments(createArguments(preferences, layout, NO_THEME)); return fragment; } @@ -62,6 +70,7 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc cast(this).getComponent().inject(this); preferences.registerOnSharedPreferenceChangeListener(this); + bus.register(this); } private void setPreferenceIntent(int xml, @Nonnull PreferencesActivity.PrefDef def) { @@ -108,6 +117,11 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc } }); } + } else if (preference == R.xml.preferences_number_format) { + prepareListPreference(Engine.Preferences.Output.notation, Engine.Notation.class); + preparePrecisionPreference(); + prepareSeparatorPreference(); + prepareNumberFormatExamplesPreference(); } prepareLanguagePreference(preference); @@ -136,6 +150,73 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc }); } + private void prepareNumberFormatExamplesPreference() { + final NumberFormatExamplesPreference preference = (NumberFormatExamplesPreference) preferenceManager.findPreference("numberFormat.examples"); + if (preference == null) { + return; + } + preference.update(engine); + } + + private void prepareSeparatorPreference() { + final ListPreference preference = (ListPreference) preferenceManager.findPreference(Engine.Preferences.Output.separator.getKey()); + preference.setSummary(separatorName(Engine.Preferences.Output.separator.getPreference(preferences))); + preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference p, Object newValue) { + preference.setSummary(separatorName(CharacterMapper.INSTANCE.parseValue(String.valueOf(newValue)))); + return true; + } + }); + } + + private int separatorName(char separator) { + switch (separator) { + case '\'': + return R.string.p_grouping_separator_apostrophe; + case ' ': + return R.string.p_grouping_separator_space; + case 0: + return R.string.p_grouping_separator_no; + } + return R.string.p_grouping_separator_no; + } + + private void preparePrecisionPreference() { + final PrecisionPreference preference = (PrecisionPreference) preferenceManager.findPreference(Engine.Preferences.Output.precision.getKey()); + preference.setSummary(String.valueOf(Engine.Preferences.Output.precision.getPreference(preferences))); + preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference p, Object newValue) { + preference.setSummary(String.valueOf(newValue)); + return true; + } + }); + } + + private & PreferenceEntry> void prepareListPreference(@Nonnull final StringPreference p, @Nonnull Class type) { + final ListPreference preference = (ListPreference) preferenceManager.findPreference(p.getKey()); + if (preference == null) { + return; + } + final E[] entries = type.getEnumConstants(); + final FragmentActivity activity = getActivity(); + populate(preference, entries); + preference.setSummary(p.getPreference(preferences).getName(activity)); + preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference p, Object newValue) { + for (E entry : entries) { + if (entry.getId().equals(newValue)) { + preference.setSummary(entry.getName(activity)); + break; + } + } + return true; + } + }); + } + private void prepareLayoutPreference(int preference) { if (preference != R.xml.preferences_appearance) { return; @@ -220,6 +301,11 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { } + @Subscribe + public void onEngineChanged(Engine.ChangedEvent e) { + prepareNumberFormatExamplesPreference(); + } + @Override public void onResume() { super.onResume(); @@ -246,6 +332,7 @@ public class PreferencesFragment extends org.solovyev.android.material.preferenc @Override public void onDestroy() { + bus.unregister(this); preferences.unregisterOnSharedPreferenceChangeListener(this); super.onDestroy(); } diff --git a/app/src/main/java/org/solovyev/android/prefs/StringPreference.java b/app/src/main/java/org/solovyev/android/prefs/StringPreference.java index 0341ea4d..0c561e72 100644 --- a/app/src/main/java/org/solovyev/android/prefs/StringPreference.java +++ b/app/src/main/java/org/solovyev/android/prefs/StringPreference.java @@ -56,6 +56,11 @@ public final class StringPreference extends AbstractPreference { return new StringPreference(key, mapper.parseValue(defaultValue), mapper); } + @Nonnull + public static StringPreference ofTypedValue(@Nonnull String key, @Nullable T defaultValue, @Nonnull Mapper mapper) { + return new StringPreference(key, defaultValue, mapper); + } + @Nonnull public static StringPreference ofEnum(@Nonnull String key, @Nullable T defaultValue, @Nonnull Class enumType) { return new StringPreference(key, defaultValue, EnumMapper.of(enumType)); diff --git a/app/src/main/java/org/solovyev/common/text/CharacterMapper.java b/app/src/main/java/org/solovyev/common/text/CharacterMapper.java new file mode 100644 index 00000000..a2b79391 --- /dev/null +++ b/app/src/main/java/org/solovyev/common/text/CharacterMapper.java @@ -0,0 +1,27 @@ +package org.solovyev.common.text; + +import android.text.TextUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class CharacterMapper implements Mapper { + + @Nonnull + public static final CharacterMapper INSTANCE = new CharacterMapper(); + + private CharacterMapper() { + } + + @Nonnull + @Override + public String formatValue(@Nullable Character value) throws IllegalArgumentException { + return value == null || value == 0 ? "" : String.valueOf(value); + } + + @Nonnull + @Override + public Character parseValue(@Nullable String value) throws IllegalArgumentException { + return TextUtils.isEmpty(value) ? 0 : value.charAt(0); + } +} diff --git a/app/src/main/res/layout/preference_number_format.xml b/app/src/main/res/layout/preference_number_format.xml deleted file mode 100644 index 14921c8e..00000000 --- a/app/src/main/res/layout/preference_number_format.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/preference_precision.xml b/app/src/main/res/layout/preference_precision.xml new file mode 100644 index 00000000..072a035f --- /dev/null +++ b/app/src/main/res/layout/preference_precision.xml @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/text_non_translatable.xml b/app/src/main/res/values/text_non_translatable.xml index 85d6359d..ecd1f7b4 100644 --- a/app/src/main/res/values/text_non_translatable.xml +++ b/app/src/main/res/values/text_non_translatable.xml @@ -18,7 +18,6 @@ E %1$s (AMOLED) - 0 1 2 3 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 0ffdadcc..fdebae46 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -35,6 +35,10 @@ a:key="restart_wizard" a:title="@string/cpp_restart_wizard" /> + + diff --git a/app/src/main/res/xml/preferences_calculations.xml b/app/src/main/res/xml/preferences_calculations.xml index bffa19a4..3db7afa5 100644 --- a/app/src/main/res/xml/preferences_calculations.xml +++ b/app/src/main/res/xml/preferences_calculations.xml @@ -24,30 +24,6 @@ - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java index 5d424c9f..c1dadf8f 100644 --- a/jscl/src/main/java/org/solovyev/common/NumberFormatter.java +++ b/jscl/src/main/java/org/solovyev/common/NumberFormatter.java @@ -14,6 +14,7 @@ public class NumberFormatter { public static final char NO_GROUPING = 0; public static final int NO_ROUNDING = -1; public static final int DEFAULT_MAGNITUDE = 5; + public static final int MIN_PRECISION = 1; public static final int MAX_PRECISION = 15; private final Real.NumberFormat numberFormat = new Real.NumberFormat(); @@ -39,7 +40,7 @@ public class NumberFormatter { } public void setPrecision(int precision) { - this.precision = precision; + this.precision = Math.max(MIN_PRECISION, Math.min(precision, MAX_PRECISION)); } public void setGroupingSeparator(char groupingSeparator) {