History refactor

This commit is contained in:
serso 2016-01-11 20:57:19 +01:00
parent 3fd671877d
commit a57d4aab57
29 changed files with 320 additions and 670 deletions

View File

@ -27,9 +27,7 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import jscl.NumeralBase; import jscl.NumeralBase;
import jscl.math.Generic; import jscl.math.Generic;
import org.solovyev.android.calculator.history.OldHistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.history.HistoryAction;
import org.solovyev.common.msg.Message; import org.solovyev.common.msg.Message;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -149,22 +147,6 @@ public class AndroidCalculator implements Calculator, CalculatorEventListener, S
calculator.fireCalculatorEvents(calculatorEvents); calculator.fireCalculatorEvents(calculatorEvents);
} }
@Override
public void doHistoryAction(@Nonnull HistoryAction historyAction) {
calculator.doHistoryAction(historyAction);
}
@Override
@Nonnull
public OldHistoryState getCurrentHistoryState() {
return calculator.getCurrentHistoryState();
}
@Override
public void setCurrentHistoryState(@Nonnull OldHistoryState editorHistoryState) {
calculator.setCurrentHistoryState(editorHistoryState);
}
@Override @Override
public void evaluate() { public void evaluate() {
calculator.evaluate(); calculator.evaluate();

View File

@ -335,6 +335,11 @@ public final class App {
return Locator.getInstance().getEditor(); return Locator.getInstance().getEditor();
} }
@Nonnull
public static Display getDisplay() {
return Locator.getInstance().getDisplay();
}
private static class MyBus extends Bus { private static class MyBus extends Bus {
@Override @Override
public void post(final Object event) { public void post(final Object event) {

View File

@ -33,25 +33,18 @@ import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Views; import org.solovyev.android.Views;
import org.solovyev.android.views.dragbutton.DirectionDragButton;
import org.solovyev.android.views.dragbutton.DragButton;
import org.solovyev.android.views.dragbutton.DragDirection;
import org.solovyev.android.views.dragbutton.DragListener;
import org.solovyev.android.views.dragbutton.SimpleDragListener;
import org.solovyev.android.calculator.history.OldHistoryState;
import org.solovyev.android.calculator.history.HistoryDragProcessor; import org.solovyev.android.calculator.history.HistoryDragProcessor;
import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.AngleUnitsButton;
import org.solovyev.android.calculator.view.LongClickEraser; import org.solovyev.android.calculator.view.LongClickEraser;
import org.solovyev.android.calculator.view.NumeralBasesButton; import org.solovyev.android.calculator.view.NumeralBasesButton;
import org.solovyev.android.calculator.view.ViewsCache; import org.solovyev.android.calculator.view.ViewsCache;
import org.solovyev.android.views.dragbutton.*;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple;
import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile; import static org.solovyev.android.calculator.Preferences.Gui.Layout.simple_mobile;
@ -165,7 +158,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
final ViewsCache views = ViewsCache.forView(root); final ViewsCache views = ViewsCache.forView(root);
setOnDragListeners(views, activity); setOnDragListeners(views, activity);
HistoryDragProcessor<OldHistoryState> historyDragProcessor = new HistoryDragProcessor<>(); HistoryDragProcessor historyDragProcessor = new HistoryDragProcessor();
final DragListener historyDragListener = newDragListener(historyDragProcessor, activity); final DragListener historyDragListener = newDragListener(historyDragProcessor, activity);
final DragButton historyButton = getButton(views, R.id.cpp_button_history); final DragButton historyButton = getButton(views, R.id.cpp_button_history);
if (historyButton != null) { if (historyButton != null) {

View File

@ -32,13 +32,8 @@ import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.view.KeyEvent; import android.view.*;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.Window;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.Activities; import org.solovyev.android.Activities;
import org.solovyev.android.Android; import org.solovyev.android.Android;
import org.solovyev.android.Threads; import org.solovyev.android.Threads;
@ -49,7 +44,6 @@ import org.solovyev.android.prefs.Preference;
import org.solovyev.android.wizard.Wizard; import org.solovyev.android.wizard.Wizard;
import org.solovyev.android.wizard.Wizards; import org.solovyev.android.wizard.Wizards;
import org.solovyev.common.Objects; import org.solovyev.common.Objects;
import org.solovyev.common.history.HistoryAction;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -59,9 +53,7 @@ import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static org.solovyev.android.calculator.Preferences.Gui.preventScreenFromFading; import static org.solovyev.android.calculator.Preferences.Gui.preventScreenFromFading;
import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes; import static org.solovyev.android.calculator.release.ReleaseNotes.hasReleaseNotes;
import static org.solovyev.android.wizard.WizardUi.continueWizard; import static org.solovyev.android.wizard.WizardUi.*;
import static org.solovyev.android.wizard.WizardUi.createLaunchIntent;
import static org.solovyev.android.wizard.WizardUi.startWizard;
public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener { public class CalculatorActivity extends BaseActivity implements SharedPreferences.OnSharedPreferenceChangeListener, CalculatorEventListener {
@ -211,7 +203,7 @@ public class CalculatorActivity extends BaseActivity implements SharedPreference
public boolean onKeyDown(int keyCode, KeyEvent event) { public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) { if (keyCode == KeyEvent.KEYCODE_BACK) {
if (useBackAsPrev) { if (useBackAsPrev) {
getCalculator().doHistoryAction(HistoryAction.undo); Locator.getInstance().getHistory().undo();
return true; return true;
} }
} }

View File

@ -23,9 +23,15 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.text.TextUtils; import android.text.TextUtils;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.math.function.Function;
import jscl.math.function.IConstant;
import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.CalculatorHistory;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.calculator.model.Var; import org.solovyev.android.calculator.model.Var;
@ -39,24 +45,14 @@ import org.solovyev.common.text.Strings;
import org.solovyev.common.units.ConversionException; import org.solovyev.common.units.ConversionException;
import org.solovyev.common.units.Conversions; import org.solovyev.common.units.Conversions;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.AbstractJsclArithmeticException;
import jscl.NumeralBase;
import jscl.NumeralBaseException;
import jscl.math.Generic;
import jscl.math.function.Function;
import jscl.math.function.IConstant;
import jscl.math.operator.Operator;
import jscl.text.ParseInterruptedException;
/** /**
* User: Solovyev_S * User: Solovyev_S
* Date: 20.09.12 * Date: 20.09.12
@ -209,7 +205,6 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
@Override @Override
public void init() { public void init() {
Locator.getInstance().getEngine().init(); Locator.getInstance().getEngine().init();
Locator.getInstance().getHistory().load();
} }
@Override @Override
@ -509,11 +504,6 @@ public class CalculatorImpl implements Calculator, CalculatorEventListener {
CalculatorVarsRegistry.saveVariable(varsRegistry, builder, ansVar, this, false); CalculatorVarsRegistry.saveVariable(varsRegistry, builder, ansVar, this, false);
} }
public void onHistoryChanged(@Nonnull CalculatorHistory.ChangedEvent e) {
getEditor().setState(e.state.getEditor());
getDisplay().setState(e.state.getDisplay());
}
@Override @Override
public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) { public void onCalculatorEvent(@Nonnull CalculatorEventData calculatorEventData, @Nonnull CalculatorEventType calculatorEventType, @Nullable Object data) {

View File

@ -150,7 +150,7 @@ public class Display implements CalculatorEventListener {
private void processCalculationResult(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorOutput data) { private void processCalculationResult(@Nonnull CalculatorEvaluationEventData calculatorEventData, @Nonnull CalculatorOutput data) {
final String stringResult = data.getStringResult(); final String stringResult = data.getStringResult();
setState(DisplayState.createValid(calculatorEventData.getOperation(), data.getResult(), stringResult, 0, calculatorEventData.getSequenceId())); setState(DisplayState.createValid(calculatorEventData.getOperation(), data.getResult(), stringResult, calculatorEventData.getSequenceId()));
} }
private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) { private void processConversationResult(@Nonnull CalculatorConversionEventData calculatorEventData, @Nonnull String result) {
@ -160,6 +160,6 @@ public class Display implements CalculatorEventListener {
} }
final DisplayState displayState = calculatorEventData.getDisplayState(); final DisplayState displayState = calculatorEventData.getDisplayState();
setState(DisplayState.createValid(displayState.getOperation(), displayState.getResult(), result, 0, calculatorEventData.getSequenceId())); setState(DisplayState.createValid(displayState.getOperation(), displayState.getResult(), result, calculatorEventData.getSequenceId()));
} }
} }

View File

@ -22,7 +22,9 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.text.TextUtils;
import jscl.math.Generic; import jscl.math.Generic;
import org.json.JSONObject;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
@ -31,6 +33,8 @@ import javax.annotation.Nullable;
public class DisplayState { public class DisplayState {
@Nonnull
private static final String JSON_OPERATION = "o";
@Nonnull @Nonnull
private JsclOperation operation = JsclOperation.numeric; private JsclOperation operation = JsclOperation.numeric;
@ -45,18 +49,26 @@ public class DisplayState {
@Nullable @Nullable
private String errorMessage; private String errorMessage;
private int selection;
private long sequence; private long sequence;
private DisplayState() { private DisplayState() {
} }
private DisplayState(@Nonnull JSONObject json) {
operation = JsclOperation.values()[json.optInt(JSON_OPERATION, JsclOperation.numeric.ordinal())];
}
@Nonnull @Nonnull
public static DisplayState empty() { public static DisplayState empty() {
return new DisplayState(); return new DisplayState();
} }
@Nonnull
public static DisplayState create(@Nonnull JSONObject json) {
return new DisplayState(json);
}
@Nonnull @Nonnull
public static DisplayState createError(@Nonnull JsclOperation operation, public static DisplayState createError(@Nonnull JsclOperation operation,
@Nonnull String errorMessage, @Nonnull String errorMessage,
@ -73,14 +85,12 @@ public class DisplayState {
public static DisplayState createValid(@Nonnull JsclOperation operation, public static DisplayState createValid(@Nonnull JsclOperation operation,
@Nullable Generic result, @Nullable Generic result,
@Nonnull String stringResult, @Nonnull String stringResult,
int selection,
long sequence) { long sequence) {
final DisplayState state = new DisplayState(); final DisplayState state = new DisplayState();
state.valid = true; state.valid = true;
state.result = result; state.result = result;
state.stringResult = stringResult; state.stringResult = stringResult;
state.operation = operation; state.operation = operation;
state.selection = selection;
state.sequence = sequence; state.sequence = sequence;
return state; return state;
} }
@ -90,10 +100,6 @@ public class DisplayState {
return Strings.getNotEmpty(isValid() ? stringResult : errorMessage, ""); return Strings.getNotEmpty(isValid() ? stringResult : errorMessage, "");
} }
public int getSelection() {
return selection;
}
@Nullable @Nullable
public Generic getResult() { public Generic getResult() {
return this.result; return this.result;
@ -121,4 +127,8 @@ public class DisplayState {
public long getSequence() { public long getSequence() {
return sequence; return sequence;
} }
public boolean same(@Nonnull DisplayState that) {
return TextUtils.equals(stringResult, that.stringResult) && TextUtils.equals(errorMessage, that.errorMessage) && operation == that.operation;
}
} }

View File

@ -104,7 +104,7 @@ public class Editor {
@Nonnull @Nonnull
public EditorState setState(@Nonnull EditorState state) { public EditorState setState(@Nonnull EditorState state) {
Check.isMainThread(); Check.isMainThread();
return setText(state.getTextString(), state.selection); return onTextChanged(state);
} }
@Nonnull @Nonnull

View File

@ -22,6 +22,9 @@
package org.solovyev.android.calculator; package org.solovyev.android.calculator;
import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -30,6 +33,10 @@ import javax.annotation.Nullable;
public class EditorState { public class EditorState {
public static final long NO_SEQUENCE = -1; public static final long NO_SEQUENCE = -1;
@Nonnull
private static final String JSON_TEXT = "t";
@Nonnull
private static final String JSON_SELECTION = "s";
private static long counter = NO_SEQUENCE + 1; private static long counter = NO_SEQUENCE + 1;
public final long sequence; public final long sequence;
@ -50,6 +57,10 @@ public class EditorState {
this.selection = selection; this.selection = selection;
} }
private EditorState(@Nonnull JSONObject json) {
this(json.optString(JSON_TEXT), json.optInt(JSON_SELECTION));
}
@Nonnull @Nonnull
public static EditorState empty() { public static EditorState empty() {
return new EditorState(); return new EditorState();
@ -65,6 +76,11 @@ public class EditorState {
return new EditorState(text, selection); return new EditorState(text, selection);
} }
@Nonnull
public static EditorState create(@Nonnull JSONObject json) {
return new EditorState(json);
}
@Nonnull @Nonnull
public String getTextString() { public String getTextString() {
if (textString == null) { if (textString == null) {
@ -72,4 +88,16 @@ public class EditorState {
} }
return textString; return textString;
} }
public boolean same(@Nonnull EditorState that) {
return TextUtils.equals(text, that.text) && selection == that.selection;
}
@Nonnull
public String toJson() throws JSONException {
final JSONObject json = new JSONObject();
json.put(JSON_TEXT, getTextString());
json.put(JSON_SELECTION, selection);
return json.toString();
}
} }

View File

@ -377,10 +377,4 @@ public final class Preferences {
public static class Graph { public static class Graph {
public static final Preference<Boolean> plotImag = BooleanPreference.of("graph_plot_imag", false); public static final Preference<Boolean> plotImag = BooleanPreference.of("graph_plot_imag", false);
} }
public static class History {
public static final Preference<Boolean> showIntermediateCalculations = BooleanPreference.of("history_show_intermediate_calculations", false);
public static final Preference<Boolean> showDatetime = BooleanPreference.of("history_show_datetime", true);
}
} }

View File

@ -26,34 +26,20 @@ import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.ListFragment; import android.support.v4.app.ListFragment;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import com.melnykov.fab.FloatingActionButton; import com.melnykov.fab.FloatingActionButton;
import org.solovyev.android.calculator.*; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.menu.*;
import org.solovyev.android.plotter.Check;
import org.solovyev.common.JPredicate;
import org.solovyev.common.collections.Collections;
import org.solovyev.common.equals.Equalizer;
import org.solovyev.common.filter.Filter;
import org.solovyev.common.filter.FilterRulesChain;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; import java.util.List;
import static android.view.Menu.NONE; import static android.view.Menu.NONE;
@ -61,26 +47,6 @@ import static org.solovyev.android.calculator.CalculatorEventType.clear_history_
public abstract class BaseHistoryFragment extends ListFragment implements CalculatorEventListener { public abstract class BaseHistoryFragment extends ListFragment implements CalculatorEventListener {
public static final Comparator<OldHistoryState> COMPARATOR = new Comparator<OldHistoryState>() {
@Override
public int compare(OldHistoryState state1, OldHistoryState state2) {
if (state1.isSaved() == state2.isSaved()) {
long l = state2.getTime() - state1.getTime();
return l > 0l ? 1 : (l < 0l ? -1 : 0);
} else if (state1.isSaved()) {
return -1;
} else if (state2.isSaved()) {
return 1;
}
return 0;
}
};
@Nonnull
private static final String TAG = "CalculatorHistoryFragment";
private final ActivityMenu<Menu, MenuItem> menu = ListActivityMenu.fromResource(R.menu.history_menu, HistoryMenu.class, AndroidMenuHelper.getInstance(), new HistoryMenuFilter());
@Nonnull
private final SharedPreferences.OnSharedPreferenceChangeListener preferencesListener = new HistoryOnPreferenceChangeListener();
@Nonnull @Nonnull
private final DialogInterface.OnClickListener clearDialogListener = new DialogInterface.OnClickListener() { private final DialogInterface.OnClickListener clearDialogListener = new DialogInterface.OnClickListener() {
@Override @Override
@ -103,48 +69,18 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
ui = new FragmentUi(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false); ui = new FragmentUi(fragmentType.getDefaultLayoutId(), fragmentType.getDefaultTitleResId(), false);
} }
public static boolean isAlreadySaved(@Nonnull OldHistoryState historyState) { @Nonnull
Check.isTrue(!historyState.isSaved()); public static String getHistoryText(@Nonnull HistoryState state) {
return state.editor.getTextString() + getIdentitySign(state.display.getOperation()) + state.display.getText();
boolean result = false;
try {
historyState.setSaved(true);
if (Collections.contains(historyState, Locator.getInstance().getHistory().getSavedHistory(), new Equalizer<OldHistoryState>() {
@Override
public boolean areEqual(@Nullable OldHistoryState first, @Nullable OldHistoryState second) {
return first != null && second != null &&
first.getTime() == second.getTime() &&
first.getDisplayState().equals(second.getDisplayState()) &&
first.getEditorState().equals(second.getEditorState());
}
})) {
result = true;
}
} finally {
historyState.setSaved(false);
}
return result;
} }
@Nonnull @Nonnull
public static String getHistoryText(@Nonnull OldHistoryState state) { private static String getIdentitySign(@Nonnull JsclOperation operation) {
final StringBuilder result = new StringBuilder(); return operation == JsclOperation.simplify ? "" : "=";
result.append(state.getEditorState().getText());
result.append(getIdentitySign(state.getDisplayState().getJsclOperation()));
final String expressionResult = state.getDisplayState().getEditorState().getText();
if (expressionResult != null) {
result.append(expressionResult);
}
return result.toString();
} }
@Nonnull public void useState(@Nonnull final HistoryState state) {
private static String getIdentitySign(@Nonnull JsclOperation jsclOperation) { App.getEditor().setState(state.editor);
return jsclOperation == JsclOperation.simplify ? "" : "=";
}
public void useState(@Nonnull final OldHistoryState state) {
App.getEditor().setState(state.getEditorState());
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
if (!(activity instanceof CalculatorActivity)) { if (!(activity instanceof CalculatorActivity)) {
activity.finish(); activity.finish();
@ -156,14 +92,6 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
ui.onCreate(this); ui.onCreate(this);
setHasOptionsMenu(true);
logDebug("onCreate");
}
private int logDebug(@Nonnull String msg) {
return Log.d(TAG + ": " + getTag(), msg);
} }
@Override @Override
@ -175,12 +103,9 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
public void onViewCreated(View root, Bundle savedInstanceState) { public void onViewCreated(View root, Bundle savedInstanceState) {
super.onViewCreated(root, savedInstanceState); super.onViewCreated(root, savedInstanceState);
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences);
ui.onViewCreated(this, root); ui.onViewCreated(this, root);
adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), org.solovyev.android.calculator.R.id.history_item, new ArrayList<OldHistoryState>(), showDatetime); adapter = new HistoryArrayAdapter(this.getActivity(), getItemLayoutId(), R.id.history_item, new ArrayList<HistoryState>());
setListAdapter(adapter); setListAdapter(adapter);
final ListView lv = getListView(); final ListView lv = getListView();
@ -200,7 +125,7 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
final View view, final View view,
final int position, final int position,
final long id) { final long id) {
useState((OldHistoryState) parent.getItemAtPosition(position)); useState((HistoryState) parent.getItemAtPosition(position));
} }
}); });
@ -214,16 +139,16 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
this.ui.onResume(this); this.ui.onResume(this);
updateAdapter(); updateAdapter();
PreferenceManager.getDefaultSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(preferencesListener);
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo); super.onCreateContextMenu(menu, v, menuInfo);
final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
final OldHistoryState state = (OldHistoryState) getListView().getItemAtPosition(info.position); final HistoryState state = (HistoryState) getListView().getItemAtPosition(info.position);
if (state.isSaved()) { // todo serso: fix
if (true) {
menu.add(NONE, R.string.c_use, NONE, R.string.c_use); menu.add(NONE, R.string.c_use, NONE, R.string.c_use);
menu.add(NONE, R.string.c_copy_expression, NONE, R.string.c_copy_expression); menu.add(NONE, R.string.c_copy_expression, NONE, R.string.c_copy_expression);
if (shouldHaveCopyResult(state)) { if (shouldHaveCopyResult(state)) {
@ -237,24 +162,22 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
if (shouldHaveCopyResult(state)) { if (shouldHaveCopyResult(state)) {
menu.add(NONE, R.string.c_copy_result, NONE, R.string.c_copy_result); menu.add(NONE, R.string.c_copy_result, NONE, R.string.c_copy_result);
} }
if (!isAlreadySaved(state)) {
menu.add(NONE, R.string.c_save, NONE, R.string.c_save); menu.add(NONE, R.string.c_save, NONE, R.string.c_save);
} }
} }
}
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
final Context context = getActivity(); final Context context = getActivity();
final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
final OldHistoryState state = (OldHistoryState) getListView().getItemAtPosition(info.position); final HistoryState state = (HistoryState) getListView().getItemAtPosition(info.position);
switch (item.getItemId()) { switch (item.getItemId()) {
case R.string.c_use: case R.string.c_use:
useState(state); useState(state);
return true; return true;
case R.string.c_copy_expression: case R.string.c_copy_expression:
final String editorText = state.getEditorState().getText(); final String editorText = state.editor.getTextString();
if (!Strings.isEmpty(editorText)) { if (!Strings.isEmpty(editorText)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(editorText); clipboard.setText(editorText);
@ -262,7 +185,7 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
} }
return true; return true;
case R.string.c_copy_result: case R.string.c_copy_result:
final String displayText = state.getDisplayState().getEditorState().getText(); final String displayText = state.display.getText();
if (!Strings.isEmpty(displayText)) { if (!Strings.isEmpty(displayText)) {
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(displayText); clipboard.setText(displayText);
@ -270,33 +193,23 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
} }
return true; return true;
case R.string.c_save: case R.string.c_save:
if (!state.isSaved()) {
createEditHistoryDialog(state, context, true); createEditHistoryDialog(state, context, true);
} else {
Toast.makeText(context, context.getText(R.string.c_history_already_saved), Toast.LENGTH_LONG).show();
}
return true; return true;
case R.string.c_edit: case R.string.c_edit:
if (state.isSaved()) {
createEditHistoryDialog(state, context, false); createEditHistoryDialog(state, context, false);
} else {
Toast.makeText(context, context.getText(R.string.c_history_must_be_saved), Toast.LENGTH_LONG).show();
}
return true; return true;
case R.string.c_remove: case R.string.c_remove:
if (state.isSaved()) {
getAdapter().remove(state); getAdapter().remove(state);
Locator.getInstance().getHistory().removeSavedHistory(state); Locator.getInstance().getHistory().removeSavedHistory(state);
Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_was_removed), Toast.LENGTH_LONG).show();
getAdapter().notifyDataSetChanged(); getAdapter().notifyDataSetChanged();
}
return true; return true;
} }
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
} }
private void createEditHistoryDialog(@Nonnull final OldHistoryState state, @Nonnull final Context context, final boolean save) { private void createEditHistoryDialog(@Nonnull final HistoryState state, @Nonnull final Context context, final boolean save) {
final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View editView = layoutInflater.inflate(R.layout.history_edit, null); final View editView = layoutInflater.inflate(R.layout.history_edit, null);
final TextView historyExpression = (TextView) editView.findViewById(R.id.history_edit_expression); final TextView historyExpression = (TextView) editView.findViewById(R.id.history_edit_expression);
@ -312,8 +225,8 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
.setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (save) { /*if (save) {
final OldHistoryState savedHistoryItem = Locator.getInstance().getHistory().addSavedState(state); final HistoryState savedHistoryItem = Locator.getInstance().getHistory().addSavedState(state);
savedHistoryItem.setComment(comment.getText().toString()); savedHistoryItem.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save(); Locator.getInstance().getHistory().save();
// we don't need to add element to the adapter as adapter of another activity must be updated and not this // we don't need to add element to the adapter as adapter of another activity must be updated and not this
@ -322,7 +235,7 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
state.setComment(comment.getText().toString()); state.setComment(comment.getText().toString());
Locator.getInstance().getHistory().save(); Locator.getInstance().getHistory().save();
} }
getAdapter().notifyDataSetChanged(); getAdapter().notifyDataSetChanged();*/
Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show(); Toast.makeText(context, context.getText(R.string.c_history_saved), Toast.LENGTH_LONG).show();
} }
}) })
@ -331,16 +244,13 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
builder.create().show(); builder.create().show();
} }
private boolean shouldHaveCopyResult(@Nonnull OldHistoryState state) { private boolean shouldHaveCopyResult(@Nonnull HistoryState state) {
return !state.getDisplayState().isValid() || !Strings.isEmpty(state.getDisplayState().getEditorState().getText()); return !state.display.isValid() || !Strings.isEmpty(state.display.getText());
} }
@Override @Override
public void onPause() { public void onPause() {
PreferenceManager.getDefaultSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(preferencesListener); ui.onPause(this);
this.ui.onPause(this);
super.onPause(); super.onPause();
} }
@ -352,7 +262,6 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
@Override @Override
public void onDestroy() { public void onDestroy() {
logDebug("onDestroy");
if (clearDialog != null) { if (clearDialog != null) {
clearDialog.dismiss(); clearDialog.dismiss();
clearDialog = null; clearDialog = null;
@ -365,13 +274,13 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
protected abstract int getItemLayoutId(); protected abstract int getItemLayoutId();
private void updateAdapter() { private void updateAdapter() {
final List<OldHistoryState> historyList = getHistoryList(); final List<HistoryState> historyList = getHistoryItems();
final ArrayAdapter<OldHistoryState> adapter = getAdapter(); final ArrayAdapter<HistoryState> adapter = getAdapter();
try { try {
adapter.setNotifyOnChange(false); adapter.setNotifyOnChange(false);
adapter.clear(); adapter.clear();
for (OldHistoryState historyState : historyList) { for (HistoryState historyState : historyList) {
adapter.add(historyState); adapter.add(historyState);
} }
} finally { } finally {
@ -381,25 +290,6 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} }
@Nonnull
private List<OldHistoryState> getHistoryList() {
final List<OldHistoryState> historyStates = getHistoryItems();
java.util.Collections.sort(historyStates, COMPARATOR);
final FilterRulesChain<OldHistoryState> filterRulesChain = new FilterRulesChain<>();
filterRulesChain.addFilterRule(new JPredicate<OldHistoryState>() {
@Override
public boolean apply(OldHistoryState object) {
return object == null || Strings.isEmpty(object.getEditorState().getText());
}
});
new Filter<>(filterRulesChain).filter(historyStates.iterator());
return historyStates;
}
@Nonnull @Nonnull
protected abstract List<HistoryState> getHistoryItems(); protected abstract List<HistoryState> getHistoryItems();
@ -417,7 +307,6 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
getActivity().runOnUiThread(new Runnable() { getActivity().runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
logDebug("onCalculatorEvent");
updateAdapter(); updateAdapter();
} }
}); });
@ -438,78 +327,4 @@ public abstract class BaseHistoryFragment extends ListFragment implements Calcul
} }
} }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
this.menu.onCreateOptionsMenu(this.getActivity(), menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
this.menu.onPrepareOptionsMenu(this.getActivity(), menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return this.menu.onOptionsItemSelected(this.getActivity(), item);
}
private static enum HistoryMenu implements IdentifiableMenuItem<MenuItem> {
toggle_datetime(R.id.menu_history_toggle_datetime) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
final SharedPreferences preferences = App.getPreferences();
final Boolean showDatetime = Preferences.History.showDatetime.getPreference(preferences);
Preferences.History.showDatetime.putPreference(preferences, !showDatetime);
}
},
fullscreen(R.id.menu_history_fullscreen) {
@Override
public void onClick(@Nonnull MenuItem data, @Nonnull Context context) {
context.startActivity(new Intent(context, CalculatorHistoryActivity.class));
}
};
private final int itemId;
HistoryMenu(int itemId) {
this.itemId = itemId;
}
@Nonnull
@Override
public Integer getItemId() {
return this.itemId;
}
}
private class HistoryMenuFilter implements JPredicate<AMenuItem<MenuItem>> {
@Override
public boolean apply(@Nullable AMenuItem<MenuItem> menuItem) {
boolean result = false;
if (menuItem instanceof IdentifiableMenuItem<?>) {
switch (((IdentifiableMenuItem) menuItem).getItemId()) {
case R.id.menu_history_fullscreen:
result = !ui.isPane(BaseHistoryFragment.this);
break;
}
}
return result;
}
}
private final class HistoryOnPreferenceChangeListener implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (Preferences.History.showDatetime.isSameKey(key)) {
getAdapter().setShowDatetime(Preferences.History.showDatetime.getPreference(preferences));
}
}
}
} }

View File

@ -24,29 +24,21 @@ package org.solovyev.android.calculator.history;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.text.TextUtils; import android.text.TextUtils;
import com.google.common.base.Strings;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.App; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.CalculatorEventType; import org.solovyev.android.io.FileSaver;
import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.Locator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class CalculatorHistory { public class CalculatorHistory {
private final AtomicInteger counter = new AtomicInteger(0);
@Nonnull @Nonnull
private final HistoryList current = new HistoryList(); private final HistoryList current = new HistoryList();
@Nonnull @Nonnull
@ -75,8 +67,16 @@ public class CalculatorHistory {
// strange, history seems to be broken. Avoid clearing the preference // strange, history seems to be broken. Avoid clearing the preference
return; return;
} }
final List<HistoryState> states = new ArrayList<>();
for (OldHistoryState state : history.getItems()) { for (OldHistoryState state : history.getItems()) {
state.setSaved(true); final OldEditorHistoryState oldEditorState = state.getEditorState();
final OldDisplayHistoryState oldDisplayState = state.getDisplayState();
final String editorText = oldEditorState.getText();
final EditorState editor = EditorState.create(Strings.nullToEmpty(editorText), oldEditorState.getCursorPosition());
final DisplayState display = oldDisplayState.isValid()
? DisplayState.createValid(oldDisplayState.getJsclOperation(), null, Strings.nullToEmpty(oldDisplayState.getEditorState().getText()), EditorState.NO_SEQUENCE)
: DisplayState.createError(oldDisplayState.getJsclOperation(), "", EditorState.NO_SEQUENCE);
states.add(HistoryState.newBuilder(editor, display).build());
} }
} }
@ -92,7 +92,7 @@ public class CalculatorHistory {
public void addCurrentState(@Nonnull HistoryState state) { public void addCurrentState(@Nonnull HistoryState state) {
Check.isMainThread(); Check.isMainThread();
current.addState(state); current.add(state);
Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.history_state_added, state); Locator.getInstance().getCalculator().fireCalculatorEvent(CalculatorEventType.history_state_added, state);
// todo serso: schedule save // todo serso: schedule save
} }
@ -146,7 +146,7 @@ public class CalculatorHistory {
if (state == null) { if (state == null) {
return; return;
} }
App.getBus().post(new ChangedEvent(state)); onCurrentStateChanged(state);
} }
public void redo() { public void redo() {
@ -154,7 +154,12 @@ public class CalculatorHistory {
if (state == null) { if (state == null) {
return; return;
} }
App.getBus().post(new ChangedEvent(state)); onCurrentStateChanged(state);
}
private void onCurrentStateChanged(@Nonnull HistoryState state) {
App.getEditor().setState(state.editor);
App.getDisplay().setState(state.display);
} }
@Nonnull @Nonnull
@ -186,13 +191,4 @@ public class CalculatorHistory {
addCurrentState(HistoryState.newBuilder(lastEditorState, e.newState).build()); addCurrentState(HistoryState.newBuilder(lastEditorState, e.newState).build());
lastEditorState = null; lastEditorState = null;
} }
public static final class ChangedEvent {
@Nonnull
public final HistoryState state;
public ChangedEvent(@Nonnull HistoryState state) {
this.state = state;
}
}
} }

View File

@ -27,50 +27,32 @@ import android.text.format.DateUtils;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.text.Strings; import org.solovyev.common.text.Strings;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.List;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static org.solovyev.android.calculator.CalculatorFragmentType.saved_history;
import static org.solovyev.android.calculator.history.BaseHistoryFragment.isAlreadySaved;
/** public class HistoryArrayAdapter extends ArrayAdapter<HistoryState> {
* User: serso
* Date: 12/18/11
* Time: 7:39 PM
*/
public class HistoryArrayAdapter extends ArrayAdapter<OldHistoryState> {
private static final int DATETIME_FORMAT = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_ABBREV_TIME; private static final int DATETIME_FORMAT = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_ABBREV_TIME;
private boolean showDatetime;
HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @Nonnull List<OldHistoryState> historyList, boolean showDatetime) { HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @Nonnull List<HistoryState> historyList) {
super(context, resource, textViewResourceId, historyList); super(context, resource, textViewResourceId, historyList);
this.showDatetime = showDatetime;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
final ViewGroup result = (ViewGroup) super.getView(position, convertView, parent); final ViewGroup result = (ViewGroup) super.getView(position, convertView, parent);
final OldHistoryState state = getItem(position); final HistoryState state = getItem(position);
final TextView time = (TextView) result.findViewById(R.id.history_time); final TextView time = (TextView) result.findViewById(R.id.history_time);
if (showDatetime) {
time.setVisibility(VISIBLE);
time.setText(DateUtils.formatDateTime(getContext(), state.getTime(), DATETIME_FORMAT)); time.setText(DateUtils.formatDateTime(getContext(), state.getTime(), DATETIME_FORMAT));
} else {
time.setVisibility(GONE);
time.setText(null);
}
final TextView editor = (TextView) result.findViewById(R.id.history_item); final TextView editor = (TextView) result.findViewById(R.id.history_item);
editor.setText(BaseHistoryFragment.getHistoryText(state)); editor.setText(BaseHistoryFragment.getHistoryText(state));
@ -86,42 +68,6 @@ public class HistoryArrayAdapter extends ArrayAdapter<OldHistoryState> {
commentView.setVisibility(GONE); commentView.setVisibility(GONE);
} }
} }
final ImageView status = (ImageView) result.findViewById(R.id.history_item_status_icon);
if (status != null) {
if (state.isSaved() || isAlreadySaved(state)) {
status.setVisibility(VISIBLE);
status.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final Context context = getContext();
if (context instanceof CalculatorHistoryActivity) {
final CalculatorHistoryActivity activity = (CalculatorHistoryActivity) context;
activity.getUi().selectTab(activity, saved_history);
}
}
});
} else {
status.setVisibility(GONE);
status.setOnClickListener(null);
}
}
return result; return result;
} }
@Override
public void notifyDataSetChanged() {
this.setNotifyOnChange(false);
this.sort(BaseHistoryFragment.COMPARATOR);
this.setNotifyOnChange(true);
super.notifyDataSetChanged();
}
public void setShowDatetime(boolean showDatetime) {
if (this.showDatetime != showDatetime) {
this.showDatetime = showDatetime;
notifyDataSetChanged();
}
}
} }

View File

@ -32,7 +32,7 @@ import org.solovyev.android.views.dragbutton.SimpleDragListener;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class HistoryDragProcessor<T> implements SimpleDragListener.DragProcessor { public class HistoryDragProcessor implements SimpleDragListener.DragProcessor {
@Override @Override
public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) { public boolean processDragEvent(@Nonnull DragDirection direction, @Nonnull DragButton button, @Nonnull PointF startPoint, @Nonnull MotionEvent motionEvent) {

View File

@ -2,7 +2,6 @@ package org.solovyev.android.calculator.history;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import java.util.Collections; import java.util.Collections;
@ -17,12 +16,15 @@ public class HistoryList {
private final List<HistoryState> list = new LinkedList<>(); private final List<HistoryState> list = new LinkedList<>();
private int current = -1; private int current = -1;
public void addState(@NonNull HistoryState e) { public void add(@NonNull HistoryState state) {
Check.isMainThread(); Check.isMainThread();
if (isCurrent(state)) {
return;
}
while (current != list.size() - 1) { while (current != list.size() - 1) {
list.remove(list.size() - 1); list.remove(list.size() - 1);
} }
list.add(e); list.add(state);
current++; current++;
if (list.size() > MAX_HISTORY) { if (list.size() > MAX_HISTORY) {
current--; current--;
@ -30,6 +32,14 @@ public class HistoryList {
} }
} }
private boolean isCurrent(@NonNull HistoryState state) {
final HistoryState current = getCurrent();
if (current == null) {
return false;
}
return current.same(state);
}
@Nullable @Nullable
public HistoryState getCurrent() { public HistoryState getCurrent() {
Check.isMainThread(); Check.isMainThread();

View File

@ -1,7 +1,8 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.Check; import org.solovyev.android.Check;
import org.solovyev.android.calculator.DisplayState; import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.EditorState;
@ -11,9 +12,13 @@ import javax.annotation.Nonnull;
public class HistoryState { public class HistoryState {
@Nonnull @Nonnull
protected final EditorState editor; private static final String JSON_EDITOR = "e";
@Nonnull @Nonnull
protected final DisplayState display; private static final String JSON_DISPLAY = "d";
@Nonnull
public final EditorState editor;
@Nonnull
public final DisplayState display;
protected long time; protected long time;
@Nullable @Nullable
protected String comment; protected String comment;
@ -23,6 +28,10 @@ public class HistoryState {
this.display = display; this.display = display;
} }
private HistoryState(@Nonnull JSONObject json) throws JSONException {
this(EditorState.create(json.getJSONObject(JSON_EDITOR)), DisplayState.create(json.getJSONObject(JSON_DISPLAY)));
}
@Nonnull @Nonnull
public static Builder newBuilder(@Nonnull EditorState editor, @Nonnull DisplayState display) { public static Builder newBuilder(@Nonnull EditorState editor, @Nonnull DisplayState display) {
return new Builder(editor, display); return new Builder(editor, display);
@ -47,6 +56,10 @@ public class HistoryState {
return comment; return comment;
} }
public boolean same(@Nonnull HistoryState that) {
return this.editor.same(that.editor) && this.display.same(that.display);
}
public static final class Builder extends HistoryState { public static final class Builder extends HistoryState {
private boolean built; private boolean built;

View File

@ -23,13 +23,11 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Transient;
import java.util.Date;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Date;
public class OldBaseHistoryState implements Cloneable { class OldBaseHistoryState implements Cloneable {
@Element @Element
private long time = new Date().getTime(); private long time = new Date().getTime();
@ -38,20 +36,6 @@ public class OldBaseHistoryState implements Cloneable {
@Nullable @Nullable
private String comment; private String comment;
@Transient
private boolean saved;
@Transient
private int id = 0;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public long getTime() { public long getTime() {
return time; return time;
} }
@ -69,14 +53,6 @@ public class OldBaseHistoryState implements Cloneable {
this.comment = comment; this.comment = comment;
} }
public boolean isSaved() {
return saved;
}
public void setSaved(boolean saved) {
this.saved = saved;
}
@SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
@Override @Override
protected OldBaseHistoryState clone() { protected OldBaseHistoryState clone() {

View File

@ -22,29 +22,19 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import jscl.math.Generic;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.simpleframework.xml.Transient; import org.simpleframework.xml.Transient;
import org.solovyev.android.calculator.Display;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.jscl.JsclOperation; import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@Root(name = "DisplayHistoryState") @Root(name = "DisplayHistoryState")
public class OldDisplayHistoryState implements Cloneable { class OldDisplayHistoryState implements Cloneable {
@Transient @Transient
private boolean valid = true; private boolean valid = true;
@Transient
@Nullable
private String errorMessage = null;
@Element @Element
@Nonnull @Nonnull
private OldEditorHistoryState editorState; private OldEditorHistoryState editorState;
@ -53,37 +43,10 @@ public class OldDisplayHistoryState implements Cloneable {
@Nonnull @Nonnull
private JsclOperation jsclOperation; private JsclOperation jsclOperation;
@Transient
@Nullable
private Generic genericResult;
private OldDisplayHistoryState() { private OldDisplayHistoryState() {
// for xml // for xml
} }
@Nonnull
public static OldDisplayHistoryState newInstance(@Nonnull DisplayState viewState) {
final OldDisplayHistoryState result = new OldDisplayHistoryState();
result.editorState = OldEditorHistoryState.create(viewState);
result.valid = viewState.isValid();
result.jsclOperation = viewState.getOperation();
result.genericResult = viewState.getResult();
result.errorMessage = viewState.getErrorMessage();
return result;
}
public void setValuesFromHistory(@Nonnull Display display) {
if (this.isValid()) {
display.setState(DisplayState.createValid(this.getJsclOperation(), this.getGenericResult(), Strings.getNotEmpty(this.getEditorState().getText(), ""), this.getEditorState().getCursorPosition(), EditorState.NO_SEQUENCE));
} else {
display.setState(DisplayState.createError(this.getJsclOperation(), Strings.getNotEmpty(this.getErrorMessage(), ""), EditorState.NO_SEQUENCE));
}
}
public boolean isValid() { public boolean isValid() {
return valid; return valid;
} }
@ -98,17 +61,6 @@ public class OldDisplayHistoryState implements Cloneable {
return jsclOperation; return jsclOperation;
} }
@Nullable
public String getErrorMessage() {
return errorMessage;
}
@Nullable
public Generic getGenericResult() {
return genericResult;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@ -132,9 +84,7 @@ public class OldDisplayHistoryState implements Cloneable {
@Override @Override
public String toString() { public String toString() {
return "CalculatorDisplayHistoryState{" + return "CalculatorDisplayHistoryState{" +
"valid=" + valid + "editorHistoryState=" + editorState +
", errorMessage='" + errorMessage + '\'' +
", editorHistoryState=" + editorState +
", jsclOperation=" + jsclOperation + ", jsclOperation=" + jsclOperation +
'}'; '}';
} }

View File

@ -24,16 +24,13 @@ package org.solovyev.android.calculator.history;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.EditorState; import org.solovyev.android.calculator.EditorState;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@Root(name = "EditorHistoryState") @Root(name = "EditorHistoryState")
public class OldEditorHistoryState implements Cloneable { class OldEditorHistoryState implements Cloneable {
@Element @Element
private int cursorPosition; private int cursorPosition;
@ -56,21 +53,6 @@ public class OldEditorHistoryState implements Cloneable {
return result; return result;
} }
@Nonnull
public static OldEditorHistoryState create(@Nonnull DisplayState viewState) {
final OldEditorHistoryState result = new OldEditorHistoryState();
result.text = viewState.getText();
result.cursorPosition = viewState.getSelection();
return result;
}
public void setValuesFromHistory(@Nonnull Editor editor) {
editor.setText(Strings.getNotEmpty(this.getText(), ""));
editor.setSelection(this.getCursorPosition());
}
@Nullable @Nullable
public String getText() { public String getText() {
return text; return text;

View File

@ -35,7 +35,7 @@ import java.util.Collection;
import java.util.List; import java.util.List;
@Root(name = "History") @Root(name = "History")
public class OldHistory { class OldHistory {
@Nonnull @Nonnull
@ElementList(type = OldHistoryState.class, name = "historyItems") @ElementList(type = OldHistoryState.class, name = "historyItems")

View File

@ -24,15 +24,11 @@ package org.solovyev.android.calculator.history;
import org.simpleframework.xml.Element; import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root; import org.simpleframework.xml.Root;
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 javax.annotation.Nonnull; import javax.annotation.Nonnull;
@Root(name = "HistoryState") @Root(name = "HistoryState")
public class OldHistoryState extends OldBaseHistoryState { class OldHistoryState extends OldBaseHistoryState {
@Element @Element
@Nonnull @Nonnull
@ -46,24 +42,6 @@ public class OldHistoryState extends OldBaseHistoryState {
// for xml // for xml
} }
private OldHistoryState(@Nonnull OldEditorHistoryState editorState,
@Nonnull OldDisplayHistoryState displayState) {
this.editorState = editorState;
this.displayState = displayState;
}
@Nonnull
public static OldHistoryState create(@Nonnull Editor editor,
@Nonnull Display display) {
return create(editor.getState(), display.getState());
}
@Nonnull
public static OldHistoryState create(@Nonnull EditorState editorState,
@Nonnull DisplayState displayState) {
return new OldHistoryState(OldEditorHistoryState.create(editorState), OldDisplayHistoryState.newInstance(displayState));
}
@Nonnull @Nonnull
public OldEditorHistoryState getEditorState() { public OldEditorHistoryState getEditorState() {
return editorState; return editorState;

View File

@ -0,0 +1,48 @@
package org.solovyev.android.io;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
abstract class BaseFileLoader {
@NonNull
protected final Context context;
public BaseFileLoader(@NonNull Context context) {
this.context = context;
}
@Nullable
public CharSequence load() {
BufferedReader reader = null;
try {
final InputStream is = getInputStream();
if (is == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(is));
final StringBuilder result = new StringBuilder();
String line = reader.readLine();
while (line != null) {
result.append(line).append("\n");
line = reader.readLine();
}
return result;
} catch (IOException e) {
Log.e(getClass().getSimpleName(), e.getMessage(), e);
} finally {
Io.close(reader);
}
return null;
}
@Nullable
protected abstract InputStream getInputStream() throws IOException;
}

View File

@ -0,0 +1,39 @@
package org.solovyev.android.io;
import android.support.annotation.NonNull;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public abstract class BaseFileSaver implements Runnable {
@NonNull
private final CharSequence data;
protected BaseFileSaver(@NonNull CharSequence data) {
this.data = data;
}
public void save() {
OutputStreamWriter out = null;
try {
out = new OutputStreamWriter(getOutputStream());
out.write(data.toString());
} catch (IOException e) {
Log.e("FileSaver", e.getMessage(), e);
} finally {
Io.close(out);
}
}
@NonNull
protected abstract FileOutputStream getOutputStream() throws FileNotFoundException;
@Override
public void run() {
save();
}
}

View File

@ -0,0 +1,28 @@
package org.solovyev.android.io;
import android.support.annotation.NonNull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
public class FileSaver extends BaseFileSaver {
@NonNull
private final File file;
private FileSaver(@NonNull File file, @NonNull CharSequence data) {
super(data);
this.file = file;
}
public static void save(@NonNull File file, @NonNull CharSequence data) {
final FileSaver fileSaver = new FileSaver(file, data);
fileSaver.save();
}
@NonNull
protected FileOutputStream getOutputStream() throws FileNotFoundException {
return new FileOutputStream(file);
}
}

View File

@ -0,0 +1,22 @@
package org.solovyev.android.io;
import android.util.Log;
import java.io.Closeable;
import java.io.IOException;
public final class Io {
private Io() {
}
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException e) {
Log.e("Io", e.getMessage(), e);
}
}
}

View File

@ -25,13 +25,6 @@
<LinearLayout <LinearLayout
xmlns:a="http://schemas.android.com/apk/res/android" xmlns:a="http://schemas.android.com/apk/res/android"
style="@style/CppListViewItem" style="@style/CppListViewItem"
a:orientation="horizontal">
<LinearLayout
a:layout_width="0dp"
a:layout_height="wrap_content"
a:layout_weight="1"
a:orientation="vertical"> a:orientation="vertical">
<TextView <TextView
@ -46,15 +39,4 @@
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="fill_parent" /> a:layout_height="fill_parent" />
</LinearLayout>
<ImageView
a:id="@+id/history_item_status_icon"
a:layout_width="30dp"
a:layout_height="30dp"
a:layout_gravity="center_vertical|right"
a:scaleType="centerInside"
a:src="@drawable/ic_save_grey600_48dp"
a:visibility="gone" />
</LinearLayout> </LinearLayout>

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<menu xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
a:id="@+id/menu_history_fullscreen"
a:icon="@drawable/ab_expand"
a:title="@string/cpp_fullscreen"
app:showAsAction="ifRoom" />
<item
a:id="@+id/menu_history_toggle_datetime"
a:icon="@drawable/ab_clock"
a:title="@string/c_toggle_datetime"
app:showAsAction="ifRoom" />
</menu>

View File

@ -62,13 +62,13 @@ public class CalculatorHistoryTest {
addState(calculatorHistory, "2354"); addState(calculatorHistory, "2354");
addState(calculatorHistory, "23547"); addState(calculatorHistory, "23547");
final List<OldHistoryState> states = calculatorHistory.getCurrentHistory(); final List<HistoryState> states = calculatorHistory.getCurrentHistory();
Assert.assertEquals(2, states.size()); Assert.assertEquals(2, states.size());
Assert.assertEquals("23547", states.get(1).getEditorState().getText()); Assert.assertEquals("23547", states.get(1).getEditor().getTextString());
Assert.assertEquals("123+3", states.get(0).getEditorState().getText()); Assert.assertEquals("123+3", states.get(0).getEditor().getTextString());
} }
private void addState(@Nonnull CalculatorHistory calculatorHistory, @Nonnull String text) { private void addState(@Nonnull CalculatorHistory calculatorHistory, @Nonnull String text) {
calculatorHistory.addCurrentState(OldHistoryState.create(EditorState.create(text, 3), DisplayState.empty())); calculatorHistory.addCurrentState(HistoryState.newBuilder(EditorState.create(text, 3), DisplayState.empty()));
} }
} }

View File

@ -22,20 +22,7 @@
package org.solovyev.android.calculator.history; package org.solovyev.android.calculator.history;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.solovyev.android.calculator.DisplayState;
import org.solovyev.android.calculator.EditorState;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.common.Objects;
import org.solovyev.common.equals.CollectionEqualizer;
import org.solovyev.common.history.HistoryHelper;
import org.solovyev.common.history.SimpleHistoryHelper;
import javax.annotation.Nonnull;
import java.util.Date;
import static org.junit.Assert.assertEquals;
/** /**
* User: serso * User: serso
@ -131,80 +118,4 @@ public class HistoryUtilsTest {
} }
@Test
public void testToXml() throws Exception {
final Date date = new Date(100000000);
HistoryHelper<OldHistoryState> history = SimpleHistoryHelper.newInstance();
DisplayState calculatorDisplay = DisplayState.createError(JsclOperation.simplify, "Error", EditorState.NO_SEQUENCE);
EditorState calculatorEditor = EditorState.create("1+1", 3);
OldHistoryState state = OldHistoryState.create(calculatorEditor, calculatorDisplay);
state.setTime(date.getTime());
history.addState(state);
assertEquals(emptyHistory, createHistory(history).toXml());
state.setSaved(true);
assertEquals(toXml1, createHistory(history).toXml());
calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "5/6", 3, EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("5/6", 2);
state = OldHistoryState.create(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date.getTime());
history.addState(state);
calculatorDisplay = DisplayState.createError(JsclOperation.elementary, "Error", EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("", 1);
state = OldHistoryState.create(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date.getTime());
history.addState(state);
calculatorDisplay = DisplayState.createValid(JsclOperation.numeric, null, "4+5/35sin(41)+dfdsfsdfs", 1, EditorState.NO_SEQUENCE);
calculatorEditor = EditorState.create("4+5/35sin(41)+dfdsfsdfs", 0);
state = OldHistoryState.create(calculatorEditor, calculatorDisplay);
state.setSaved(true);
state.setTime(date.getTime());
history.addState(state);
String xml = createHistory(history).toXml();
assertEquals(toXml2, xml);
final HistoryHelper<OldHistoryState> historyFromXml = SimpleHistoryHelper.newInstance();
final OldHistory actual = OldHistory.fromXml(xml);
for (OldHistoryState historyState : actual.getItems()) {
historyFromXml.addState(historyState);
}
assertEquals(history.getStates().size(), historyFromXml.getStates().size());
for (OldHistoryState historyState : history.getStates()) {
historyState.setId(0);
historyState.setSaved(true);
}
for (OldHistoryState historyState : historyFromXml.getStates()) {
historyState.setId(0);
historyState.setSaved(true);
}
Assert.assertTrue(Objects.areEqual(history.getStates(), historyFromXml.getStates(), new CollectionEqualizer<OldHistoryState>(null)));
}
@Nonnull
private OldHistory createHistory(HistoryHelper<OldHistoryState> history) {
final OldHistory result = new OldHistory();
result.addAll(history.getStates());
return result;
}
} }