From 5c663e7b24574666393b267d7dfdb6a3cd0e53c5 Mon Sep 17 00:00:00 2001 From: serso Date: Tue, 12 Jan 2016 14:26:29 +0100 Subject: [PATCH] Save history states --- .../org/solovyev/android/calculator/App.java | 15 +++++++ .../android/calculator/DisplayState.java | 9 ++++ .../android/calculator/EditorState.java | 22 +++++++--- .../android/calculator/history/History.java | 44 ++++++++++++++++--- .../calculator/history/HistoryState.java | 10 +++++ .../history/SavedHistoryFragment.java | 3 +- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/solovyev/android/calculator/App.java b/app/src/main/java/org/solovyev/android/calculator/App.java index 74940937..469fcd93 100644 --- a/app/src/main/java/org/solovyev/android/calculator/App.java +++ b/app/src/main/java/org/solovyev/android/calculator/App.java @@ -70,6 +70,7 @@ import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -136,6 +137,15 @@ public final class App { 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() { throw new AssertionError(); @@ -271,6 +281,11 @@ public final class App { return initThread; } + @Nonnull + public static Executor getBackground() { + return background; + } + @Nonnull public static Preferences.Gui.Theme getThemeFor(@Nonnull Context context) { if (context instanceof CalculatorOnscreenService) { diff --git a/app/src/main/java/org/solovyev/android/calculator/DisplayState.java b/app/src/main/java/org/solovyev/android/calculator/DisplayState.java index 382cc68d..41c86fb7 100644 --- a/app/src/main/java/org/solovyev/android/calculator/DisplayState.java +++ b/app/src/main/java/org/solovyev/android/calculator/DisplayState.java @@ -105,4 +105,13 @@ public class DisplayState { json.put(JSON_TEXT, text); return json; } + + @Override + public String toString() { + return "DisplayState{" + + "valid=" + valid + + ", sequence=" + sequence + + ", operation=" + operation + + '}'; + } } diff --git a/app/src/main/java/org/solovyev/android/calculator/EditorState.java b/app/src/main/java/org/solovyev/android/calculator/EditorState.java index e1e6d1fc..40acd7a1 100644 --- a/app/src/main/java/org/solovyev/android/calculator/EditorState.java +++ b/app/src/main/java/org/solovyev/android/calculator/EditorState.java @@ -23,9 +23,11 @@ package org.solovyev.android.calculator; import android.text.TextUtils; + import org.json.JSONException; import org.json.JSONObject; -import org.solovyev.android.Check; + +import java.util.concurrent.atomic.AtomicLong; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -35,7 +37,7 @@ public class EditorState { public static final long NO_SEQUENCE = -1; private static final String JSON_TEXT = "t"; 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; @Nonnull @@ -49,8 +51,7 @@ public class EditorState { } private EditorState(@Nonnull CharSequence text, int selection) { - Check.isMainThread(); - this.sequence = counter++; + this.sequence = counter.getAndIncrement(); this.text = text; this.selection = selection; } @@ -91,11 +92,20 @@ public class EditorState { return TextUtils.equals(text, that.text) && selection == that.selection; } + @Override + public String toString() { + return "EditorState{" + + "sequence=" + sequence + + ", text=" + text + + ", selection=" + selection + + '}'; + } + @Nonnull - public String toJson() throws JSONException { + public JSONObject toJson() throws JSONException { final JSONObject json = new JSONObject(); json.put(JSON_TEXT, getTextString()); json.put(JSON_SELECTION, selection); - return json.toString(); + return json; } } 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 66c3f115..a1e8dcc5 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 @@ -23,6 +23,7 @@ package org.solovyev.android.calculator.history; import android.content.SharedPreferences; +import android.os.Handler; import android.support.annotation.NonNull; import android.text.TextUtils; @@ -54,10 +55,16 @@ import javax.annotation.Nullable; public class 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 private final HistoryList current = new HistoryList(); @Nonnull private final List saved = new ArrayList<>(); + @Nonnull + private final Handler handler = App.getHandler(); @Nullable private EditorState lastEditorState; private boolean initialized; @@ -131,9 +138,11 @@ public class History { migrateOldHistory(); final List currentStates = loadStates(getCurrentHistoryFile()); final List savedStates = loadStates(getSavedHistoryFile()); - App.getHandler().post(new Runnable() { + handler.post(new Runnable() { @Override public void run() { + Check.isTrue(current.isEmpty()); + Check.isTrue(saved.isEmpty()); current.addAll(currentStates); saved.addAll(savedStates); initialized = true; @@ -155,11 +164,13 @@ public class History { } private void onCurrentChanged() { - // todo serso: implement + handler.removeCallbacks(writeCurrent); + handler.postDelayed(writeCurrent, 500); } private void onSavedChanged() { - // todo serso: implement + handler.removeCallbacks(writeSaved); + handler.postDelayed(writeSaved, 500); } @Nonnull @@ -184,10 +195,10 @@ public class History { @Nonnull public List getSaved() { 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) { final int diff = newerText.length() - olderText.length(); if (diff == 1) { @@ -268,4 +279,27 @@ public class History { addCurrent(HistoryState.newBuilder(lastEditorState, e.newState).build()); 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 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()); + } + }); + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java b/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java index 0854d953..9a48d7d4 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/HistoryState.java @@ -81,6 +81,16 @@ public class HistoryState { 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 { private boolean built; diff --git a/app/src/main/java/org/solovyev/android/calculator/history/SavedHistoryFragment.java b/app/src/main/java/org/solovyev/android/calculator/history/SavedHistoryFragment.java index 3395f163..4d245e62 100644 --- a/app/src/main/java/org/solovyev/android/calculator/history/SavedHistoryFragment.java +++ b/app/src/main/java/org/solovyev/android/calculator/history/SavedHistoryFragment.java @@ -26,7 +26,6 @@ import org.solovyev.android.calculator.CalculatorFragmentType; import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.R; -import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; @@ -45,7 +44,7 @@ public class SavedHistoryFragment extends BaseHistoryFragment { @Nonnull @Override protected List getHistoryItems() { - return new ArrayList<>(Locator.getInstance().getHistory().getSaved()); + return Locator.getInstance().getHistory().getSaved(); } @Override