Save history states
This commit is contained in:
parent
5813f41f4c
commit
5c663e7b24
@ -70,6 +70,7 @@ import java.util.Arrays;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -136,6 +137,15 @@ public final class App {
|
|||||||
return new Thread(r, "Init");
|
return new Thread(r, "Init");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@Nonnull
|
||||||
|
private static final Executor background = Executors.newFixedThreadPool(5, new ThreadFactory() {
|
||||||
|
@NonNull
|
||||||
|
private final AtomicInteger counter = new AtomicInteger();
|
||||||
|
@Override
|
||||||
|
public Thread newThread(@Nonnull Runnable r) {
|
||||||
|
return new Thread(r, "Background #" + counter.getAndIncrement());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private App() {
|
private App() {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
@ -271,6 +281,11 @@ public final class App {
|
|||||||
return initThread;
|
return initThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static Executor getBackground() {
|
||||||
|
return background;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) {
|
public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) {
|
||||||
if (context instanceof CalculatorOnscreenService) {
|
if (context instanceof CalculatorOnscreenService) {
|
||||||
|
@ -105,4 +105,13 @@ public class DisplayState {
|
|||||||
json.put(JSON_TEXT, text);
|
json.put(JSON_TEXT, text);
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DisplayState{" +
|
||||||
|
"valid=" + valid +
|
||||||
|
", sequence=" + sequence +
|
||||||
|
", operation=" + operation +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.solovyev.android.Check;
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -35,7 +37,7 @@ public class EditorState {
|
|||||||
public static final long NO_SEQUENCE = -1;
|
public static final long NO_SEQUENCE = -1;
|
||||||
private static final String JSON_TEXT = "t";
|
private static final String JSON_TEXT = "t";
|
||||||
private static final String JSON_SELECTION = "s";
|
private static final String JSON_SELECTION = "s";
|
||||||
private static long counter = NO_SEQUENCE + 1;
|
private static AtomicLong counter = new AtomicLong(NO_SEQUENCE + 1);
|
||||||
|
|
||||||
public final long sequence;
|
public final long sequence;
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@ -49,8 +51,7 @@ public class EditorState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private EditorState(@Nonnull CharSequence text, int selection) {
|
private EditorState(@Nonnull CharSequence text, int selection) {
|
||||||
Check.isMainThread();
|
this.sequence = counter.getAndIncrement();
|
||||||
this.sequence = counter++;
|
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
}
|
}
|
||||||
@ -91,11 +92,20 @@ public class EditorState {
|
|||||||
return TextUtils.equals(text, that.text) && selection == that.selection;
|
return TextUtils.equals(text, that.text) && selection == that.selection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "EditorState{" +
|
||||||
|
"sequence=" + sequence +
|
||||||
|
", text=" + text +
|
||||||
|
", selection=" + selection +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public String toJson() throws JSONException {
|
public JSONObject toJson() throws JSONException {
|
||||||
final JSONObject json = new JSONObject();
|
final JSONObject json = new JSONObject();
|
||||||
json.put(JSON_TEXT, getTextString());
|
json.put(JSON_TEXT, getTextString());
|
||||||
json.put(JSON_SELECTION, selection);
|
json.put(JSON_SELECTION, selection);
|
||||||
return json.toString();
|
return json;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
package org.solovyev.android.calculator.history;
|
package org.solovyev.android.calculator.history;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Handler;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
@ -54,10 +55,16 @@ import javax.annotation.Nullable;
|
|||||||
public class History {
|
public class History {
|
||||||
|
|
||||||
public static final String TAG = App.subTag("History");
|
public static final String TAG = App.subTag("History");
|
||||||
|
@NonNull
|
||||||
|
private final Runnable writeCurrent = new WriteTask(true);
|
||||||
|
@NonNull
|
||||||
|
private final Runnable writeSaved = new WriteTask(false);
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final HistoryList current = new HistoryList();
|
private final HistoryList current = new HistoryList();
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final List<HistoryState> saved = new ArrayList<>();
|
private final List<HistoryState> saved = new ArrayList<>();
|
||||||
|
@Nonnull
|
||||||
|
private final Handler handler = App.getHandler();
|
||||||
@Nullable
|
@Nullable
|
||||||
private EditorState lastEditorState;
|
private EditorState lastEditorState;
|
||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
@ -131,9 +138,11 @@ public class History {
|
|||||||
migrateOldHistory();
|
migrateOldHistory();
|
||||||
final List<HistoryState> currentStates = loadStates(getCurrentHistoryFile());
|
final List<HistoryState> currentStates = loadStates(getCurrentHistoryFile());
|
||||||
final List<HistoryState> savedStates = loadStates(getSavedHistoryFile());
|
final List<HistoryState> savedStates = loadStates(getSavedHistoryFile());
|
||||||
App.getHandler().post(new Runnable() {
|
handler.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
Check.isTrue(current.isEmpty());
|
||||||
|
Check.isTrue(saved.isEmpty());
|
||||||
current.addAll(currentStates);
|
current.addAll(currentStates);
|
||||||
saved.addAll(savedStates);
|
saved.addAll(savedStates);
|
||||||
initialized = true;
|
initialized = true;
|
||||||
@ -155,11 +164,13 @@ public class History {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onCurrentChanged() {
|
private void onCurrentChanged() {
|
||||||
// todo serso: implement
|
handler.removeCallbacks(writeCurrent);
|
||||||
|
handler.postDelayed(writeCurrent, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onSavedChanged() {
|
private void onSavedChanged() {
|
||||||
// todo serso: implement
|
handler.removeCallbacks(writeSaved);
|
||||||
|
handler.postDelayed(writeSaved, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@ -184,10 +195,10 @@ public class History {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
public List<HistoryState> getSaved() {
|
public List<HistoryState> getSaved() {
|
||||||
Check.isMainThread();
|
Check.isMainThread();
|
||||||
return Collections.unmodifiableList(saved);
|
return new ArrayList<>(saved);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIntermediate(@Nonnull String newerText,
|
private static boolean isIntermediate(@Nonnull String newerText,
|
||||||
@Nonnull String olderText) {
|
@Nonnull String olderText) {
|
||||||
final int diff = newerText.length() - olderText.length();
|
final int diff = newerText.length() - olderText.length();
|
||||||
if (diff == 1) {
|
if (diff == 1) {
|
||||||
@ -268,4 +279,27 @@ public class History {
|
|||||||
addCurrent(HistoryState.newBuilder(lastEditorState, e.newState).build());
|
addCurrent(HistoryState.newBuilder(lastEditorState, e.newState).build());
|
||||||
lastEditorState = null;
|
lastEditorState = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class WriteTask implements Runnable {
|
||||||
|
private final boolean current;
|
||||||
|
|
||||||
|
public WriteTask(boolean current) {
|
||||||
|
this.current = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Check.isMainThread();
|
||||||
|
// don't need to save intermediate states, thus {@link History#getCurrent}
|
||||||
|
final List<HistoryState> states = current ? getCurrent() : getSaved();
|
||||||
|
App.getBackground().execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final File file = current ? getCurrentHistoryFile() : getSavedHistoryFile();
|
||||||
|
final JSONArray array = HistoryList.toJson(states);
|
||||||
|
FileSaver.save(file, array.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -81,6 +81,16 @@ public class HistoryState {
|
|||||||
return this.editor.same(that.editor) && this.display.same(that.display);
|
return this.editor.same(that.editor) && this.display.same(that.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "HistoryState{" +
|
||||||
|
"editor=" + editor +
|
||||||
|
", display=" + display +
|
||||||
|
", time=" + time +
|
||||||
|
", comment='" + comment + '\'' +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
public static final class Builder extends HistoryState {
|
public static final class Builder extends HistoryState {
|
||||||
|
|
||||||
private boolean built;
|
private boolean built;
|
||||||
|
@ -26,7 +26,6 @@ import org.solovyev.android.calculator.CalculatorFragmentType;
|
|||||||
import org.solovyev.android.calculator.Locator;
|
import org.solovyev.android.calculator.Locator;
|
||||||
import org.solovyev.android.calculator.R;
|
import org.solovyev.android.calculator.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -45,7 +44,7 @@ public class SavedHistoryFragment extends BaseHistoryFragment {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
protected List<HistoryState> getHistoryItems() {
|
protected List<HistoryState> getHistoryItems() {
|
||||||
return new ArrayList<>(Locator.getInstance().getHistory().getSaved());
|
return Locator.getInstance().getHistory().getSaved();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user