From df392185f30f15c41a0b161a518f6f49b8a2e344 Mon Sep 17 00:00:00 2001 From: Sergey Solovyev Date: Sun, 18 Dec 2011 17:05:44 +0400 Subject: [PATCH] history changes --- res/layout/history.xml | 32 ++++ res/layout/history_edit.xml | 47 ++++++ res/values/strings.xml | 12 ++ res/values/styles-common-history.xml | 8 +- .../calculator/CalculatorHistoryActivity.java | 154 ++++++++++------- .../history/HistoryItemMenuData.java | 39 +++++ .../history/HistoryItemMenuItem.java | 157 ++++++++++++++++++ .../java/org/solovyev/android/view/AMenu.java | 23 +++ .../org/solovyev/android/view/AMenuItem.java | 23 +++ .../org/solovyev/android/view/EnumMenu.java | 35 ++++ .../org/solovyev/android/view/MenuImpl.java | 52 ++++++ .../view/widgets/DirectionDragButton.java | 2 +- 12 files changed, 521 insertions(+), 63 deletions(-) create mode 100644 res/layout/history_edit.xml create mode 100644 src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuData.java create mode 100644 src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuItem.java create mode 100644 src/main/java/org/solovyev/android/view/AMenu.java create mode 100644 src/main/java/org/solovyev/android/view/AMenuItem.java create mode 100644 src/main/java/org/solovyev/android/view/EnumMenu.java create mode 100644 src/main/java/org/solovyev/android/view/MenuImpl.java diff --git a/res/layout/history.xml b/res/layout/history.xml index 98840f02..43d1db75 100644 --- a/res/layout/history.xml +++ b/res/layout/history.xml @@ -19,6 +19,38 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/history_edit.xml b/res/layout/history_edit.xml new file mode 100644 index 00000000..bb05c09f --- /dev/null +++ b/res/layout/history_edit.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 6caaac91..96c92235 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -301,5 +301,17 @@ Check the \'Round result\' preference in application settings - it should be tur Comment Saved + Not saved + Expression copied to the clipboard + Status: + Comment: + Use + Copy expression + Copy result + Value + Comment + Save history + Modify history + Modify diff --git a/res/values/styles-common-history.xml b/res/values/styles-common-history.xml index cb132b75..0ff121d6 100644 --- a/res/values/styles-common-history.xml +++ b/res/values/styles-common-history.xml @@ -6,10 +6,12 @@ - + \ No newline at end of file diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorHistoryActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorHistoryActivity.java index 9f64ebee..73c64a93 100644 --- a/src/main/java/org/solovyev/android/calculator/CalculatorHistoryActivity.java +++ b/src/main/java/org/solovyev/android/calculator/CalculatorHistoryActivity.java @@ -11,19 +11,17 @@ import android.app.ListActivity; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import android.preference.PreferenceManager; import android.view.*; import android.widget.*; import org.jetbrains.annotations.NotNull; -import org.solovyev.android.calculator.history.CalculatorHistory; -import org.solovyev.android.calculator.history.CalculatorHistoryState; -import org.solovyev.android.calculator.history.EditorHistoryState; +import org.solovyev.android.calculator.history.*; import org.solovyev.android.calculator.jscl.JsclOperation; +import org.solovyev.android.view.AMenu; +import org.solovyev.android.view.AMenuItem; +import org.solovyev.android.view.MenuImpl; import org.solovyev.android.view.prefs.ResourceCache; +import org.solovyev.common.utils.*; import org.solovyev.common.utils.Filter; -import org.solovyev.common.utils.FilterRule; -import org.solovyev.common.utils.FilterRulesChain; -import org.solovyev.common.utils.StringUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -80,20 +78,7 @@ public class CalculatorHistoryActivity extends ListActivity { final int position, final long id) { - final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position); - - CalculatorModel.instance.doTextOperation(new CalculatorModel.TextOperation() { - @Override - public void doOperation(@NotNull EditText editor) { - final EditorHistoryState editorState = historyState.getEditorState(); - editor.setText(editorState.getText()); - editor.setSelection(editorState.getCursorPosition()); - } - }, false, historyState.getDisplayState().getJsclOperation(), true); - - CalculatorModel.instance.setCursorOnEnd(); - - CalculatorHistoryActivity.this.finish(); + useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position), CalculatorHistoryActivity.this); } }); @@ -104,30 +89,30 @@ public class CalculatorHistoryActivity extends ListActivity { final Context context = CalculatorHistoryActivity.this; - final CharSequence[] items = {context.getText(R.string.c_save), context.getText(R.string.c_remove)}; + final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter); + + final List menuItems = CollectionsUtils.asList(HistoryItemMenuItem.values()); + + if (historyState.isSaved()) { + menuItems.remove(HistoryItemMenuItem.save); + } else { + if (isAlreadySaved(historyState)) { + menuItems.remove(HistoryItemMenuItem.save); + } + menuItems.remove(HistoryItemMenuItem.edit); + } + + if (historyState.getDisplayState().isValid() && StringUtils.isEmpty(historyState.getDisplayState().getEditorState().getText())) { + menuItems.remove(HistoryItemMenuItem.copy_result); + } + final AMenu historyItemMenu = new MenuImpl(menuItems); AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setItems(items, new DialogInterface.OnClickListener() { + builder.setItems(historyItemMenu.getMenuCaptions(), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { - if (item == 0) { - if (!historyState.isSaved()) { - final CalculatorHistoryState savedHistoryItem = CalculatorHistory.instance.addSavedState(historyState); - CalculatorHistory.instance.save(context); - adapter.add(savedHistoryItem); - adapter.sort(COMPARATOR); - CalculatorHistoryActivity.this.adapter.notifyDataSetChanged(); - Toast.makeText(context, "History item was successfully saved!", Toast.LENGTH_LONG).show(); - } else { - Toast.makeText(context, "History item was already saved!", Toast.LENGTH_LONG).show(); - } - } else if (item == 1) { - adapter.remove(historyState); - adapter.sort(COMPARATOR); - if (historyState.isSaved()) { - CalculatorHistory.instance.removeSavedHistory(historyState, context, PreferenceManager.getDefaultSharedPreferences(context)); - Toast.makeText(context, "History item was removed!", Toast.LENGTH_LONG).show(); - } - CalculatorHistoryActivity.this.adapter.notifyDataSetChanged(); + final AMenuItem historyItemMenuItem = historyItemMenu.itemAt(item); + if (historyItemMenuItem != null) { + historyItemMenuItem.doAction(data, context); } } }); @@ -137,6 +122,37 @@ public class CalculatorHistoryActivity extends ListActivity { }); } + public static boolean isAlreadySaved(@NotNull CalculatorHistoryState historyState) { + assert !historyState.isSaved(); + + boolean result = false; + try { + historyState.setSaved(true); + if ( CalculatorHistory.instance.getSavedHistory().contains(historyState) ) { + result = true; + } + } finally { + historyState.setSaved(false); + } + return result; + } + + public static void useHistoryItem(@NotNull final CalculatorHistoryState historyState, @NotNull CalculatorHistoryActivity activity) { + + CalculatorModel.instance.doTextOperation(new CalculatorModel.TextOperation() { + @Override + public void doOperation(@NotNull EditText editor) { + final EditorHistoryState editorState = historyState.getEditorState(); + editor.setText(editorState.getText()); + editor.setSelection(editorState.getCursorPosition()); + } + }, false, historyState.getDisplayState().getJsclOperation(), true); + + CalculatorModel.instance.setCursorOnEnd(); + + activity.finish(); + } + private static List getHistoryList() { final List calculatorHistoryStates = new ArrayList(CalculatorHistory.instance.getStates()); calculatorHistoryStates.addAll(CalculatorHistory.instance.getSavedHistory()); @@ -156,7 +172,7 @@ public class CalculatorHistoryActivity extends ListActivity { return calculatorHistoryStates; } - private static class HistoryArrayAdapter extends ArrayAdapter { + public class HistoryArrayAdapter extends ArrayAdapter { private HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @NotNull List historyList) { super(context, resource, textViewResourceId, historyList); @@ -172,33 +188,54 @@ public class CalculatorHistoryActivity extends ListActivity { time.setText(new SimpleDateFormat().format(state.getTime())); final TextView editor = (TextView) result.findViewById(R.id.history_item); - final StringBuilder historyText = new StringBuilder(); - historyText.append(state.getEditorState().getText()); - historyText.append(getIdentitySign(state.getDisplayState().getJsclOperation())); - historyText.append(state.getDisplayState().getEditorState().getText()); + editor.setText(getHistoryText(state)); + + final TextView commentView = (TextView) result.findViewById(R.id.history_item_comment); final String comment = state.getComment(); if (!StringUtils.isEmpty(comment)) { - historyText.append("\n"); - historyText.append(ResourceCache.instance.getCaption("c_comment")).append(": "); - historyText.append(comment); + commentView.setText(comment); + } else { + commentView.setText(""); } - if ( state.isSaved() ) { - historyText.append("\n"); - historyText.append(ResourceCache.instance.getCaption("c_history_item_saved")); + + final TextView status = (TextView) result.findViewById(R.id.history_item_status); + if (state.isSaved() || isAlreadySaved(state)) { + status.setText(ResourceCache.instance.getCaption("c_history_item_saved")); + } else { + status.setText(ResourceCache.instance.getCaption("c_history_item_not_saved")); } - editor.setText(historyText); return result; } - @NotNull - private String getIdentitySign(@NotNull JsclOperation jsclOperation) { - return jsclOperation == JsclOperation.simplify ? "≡" : "="; + @Override + public void notifyDataSetChanged() { + this.setNotifyOnChange(false); + this.sort(COMPARATOR); + this.setNotifyOnChange(true); + super.notifyDataSetChanged(); } } + @NotNull + public static String getHistoryText(@NotNull CalculatorHistoryState state) { + final StringBuilder result = new StringBuilder(); + 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(); + } + + @NotNull + private static String getIdentitySign(@NotNull JsclOperation jsclOperation) { + return jsclOperation == JsclOperation.simplify ? "≡" : "="; + } + @Override - public boolean onCreateOptionsMenu(Menu menu) { + public boolean onCreateOptionsMenu(android.view.Menu menu) { final MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.history_menu, menu); return true; @@ -228,7 +265,6 @@ public class CalculatorHistoryActivity extends ListActivity { } if (adapter.getCount() > 0) { - adapter.sort(COMPARATOR); adapter.notifyDataSetChanged(); } else { Toast.makeText(this, R.string.c_history_is_empty, Toast.LENGTH_SHORT).show(); diff --git a/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuData.java b/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuData.java new file mode 100644 index 00000000..ed7daeaa --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuData.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator.history; + +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.calculator.CalculatorHistoryActivity; + +/** +* User: serso +* Date: 12/18/11 +* Time: 3:10 PM +*/ +public class HistoryItemMenuData { + + @NotNull + private final CalculatorHistoryActivity.HistoryArrayAdapter adapter; + + @NotNull + private final CalculatorHistoryState historyState; + + public HistoryItemMenuData(@NotNull CalculatorHistoryState historyState, CalculatorHistoryActivity.HistoryArrayAdapter adapter) { + this.historyState = historyState; + this.adapter = adapter; + } + + @NotNull + public CalculatorHistoryState getHistoryState() { + return historyState; + } + + @NotNull + public CalculatorHistoryActivity.HistoryArrayAdapter getAdapter() { + return adapter; + } +} diff --git a/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuItem.java b/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuItem.java new file mode 100644 index 00000000..126572af --- /dev/null +++ b/src/main/java/org/solovyev/android/calculator/history/HistoryItemMenuItem.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.calculator.history; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.preference.PreferenceManager; +import android.text.ClipboardManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.calculator.CalculatorHistoryActivity; +import org.solovyev.android.calculator.R; +import org.solovyev.android.view.AMenuItem; +import org.solovyev.android.view.prefs.ResourceCache; +import org.solovyev.common.utils.StringUtils; + +/** +* User: serso +* Date: 12/18/11 +* Time: 3:09 PM +*/ +public enum HistoryItemMenuItem implements AMenuItem { + use("c_use_expression") { + @Override + public void doAction(@NotNull HistoryItemMenuData data, @NotNull Context context) { + if (context instanceof CalculatorHistoryActivity) { + CalculatorHistoryActivity.useHistoryItem(data.getHistoryState(), (CalculatorHistoryActivity) context); + } else { + Log.e(HistoryItemMenuItem.class.getName(), CalculatorHistoryActivity.class + " must be passed as context!"); + } + } + }, + copy_expression("c_copy_expression") { + @Override + public void doAction(@NotNull HistoryItemMenuData data, @NotNull Context context) { + final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); + final String text = calculatorHistoryState.getEditorState().getText(); + if (!StringUtils.isEmpty(text)) { + final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); + clipboard.setText(text); + Toast.makeText(context, context.getText(R.string.c_expression_copied), Toast.LENGTH_SHORT).show(); + } + } + }, + copy_result("c_copy_result") { + @Override + public void doAction(@NotNull HistoryItemMenuData data, @NotNull Context context) { + final CalculatorHistoryState calculatorHistoryState = data.getHistoryState(); + final String text = calculatorHistoryState.getDisplayState().getEditorState().getText(); + if (!StringUtils.isEmpty(text)) { + final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE); + clipboard.setText(text); + Toast.makeText(context, context.getText(R.string.c_result_copied), Toast.LENGTH_SHORT).show(); + } + } + }, + save("c_save") { + @Override + public void doAction(@NotNull final HistoryItemMenuData data, @NotNull final Context context) { + final CalculatorHistoryState historyState = data.getHistoryState(); + if (!historyState.isSaved()) { + createEditHistoryDialog(data, context, true); + } else { + Toast.makeText(context, "History item was already saved!", Toast.LENGTH_LONG).show(); + } + } + }, + edit("c_edit") { + @Override + public void doAction(@NotNull final HistoryItemMenuData data, @NotNull final Context context) { + final CalculatorHistoryState historyState = data.getHistoryState(); + if (historyState.isSaved()) { + createEditHistoryDialog(data, context, false); + } else { + Toast.makeText(context, "History item must be saved before editing!", Toast.LENGTH_LONG).show(); + } + } + }, + remove("c_remove") { + @Override + public void doAction(@NotNull HistoryItemMenuData data, @NotNull Context context) { + final CalculatorHistoryState historyState = data.getHistoryState(); + data.getAdapter().remove(historyState); + if (historyState.isSaved()) { + CalculatorHistory.instance.removeSavedHistory(historyState, context, PreferenceManager.getDefaultSharedPreferences(context)); + Toast.makeText(context, "History item was removed!", Toast.LENGTH_LONG).show(); + } + data.getAdapter().notifyDataSetChanged(); + } + }; + + private static void createEditHistoryDialog(@NotNull final HistoryItemMenuData data, @NotNull final Context context, final boolean save) { + final CalculatorHistoryState historyState = data.getHistoryState(); + + final LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + final View editView = layoutInflater.inflate(R.layout.history_edit, null); + final TextView historyExpression = (TextView)editView.findViewById(R.id.history_edit_expression); + historyExpression.setText(CalculatorHistoryActivity.getHistoryText(historyState)); + + final EditText comment = (EditText)editView.findViewById(R.id.history_edit_comment); + comment.setText(historyState.getComment()); + + final AlertDialog.Builder builder = new AlertDialog.Builder(context) + .setTitle(save ? R.string.c_save_history : R.string.c_edit_history) + .setCancelable(true) + .setNegativeButton(R.string.c_cancel, null) + .setPositiveButton(R.string.c_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (save) { + final CalculatorHistoryState savedHistoryItem = CalculatorHistory.instance.addSavedState(historyState); + savedHistoryItem.setComment(comment.getText().toString()); + CalculatorHistory.instance.save(context); + data.getAdapter().add(savedHistoryItem); + } else { + historyState.setComment(comment.getText().toString()); + CalculatorHistory.instance.save(context); + } + data.getAdapter().notifyDataSetChanged(); + Toast.makeText(context, "History item was successfully saved!", Toast.LENGTH_LONG).show(); + } + }) + .setView(editView); + + builder.create().show(); + } + + @NotNull + private final String captionId; + + private HistoryItemMenuItem(@NotNull String captionId) { + this.captionId = captionId; + } + + @NotNull + @Override + public String getCaption() { + final String caption = ResourceCache.instance.getCaption(getCaptionId()); + return caption == null ? this.name() : caption; + } + + @NotNull + public String getCaptionId() { + return captionId; + } +} diff --git a/src/main/java/org/solovyev/android/view/AMenu.java b/src/main/java/org/solovyev/android/view/AMenu.java new file mode 100644 index 00000000..2b495afb --- /dev/null +++ b/src/main/java/org/solovyev/android/view/AMenu.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: serso + * Date: 12/18/11 + * Time: 1:30 PM + */ +public interface AMenu { + @Nullable + T itemAt(int i); + + @NotNull + CharSequence[] getMenuCaptions(); +} diff --git a/src/main/java/org/solovyev/android/view/AMenuItem.java b/src/main/java/org/solovyev/android/view/AMenuItem.java new file mode 100644 index 00000000..2d3d04ef --- /dev/null +++ b/src/main/java/org/solovyev/android/view/AMenuItem.java @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view; + +import android.content.Context; +import org.jetbrains.annotations.NotNull; + +/** + * User: serso + * Date: 12/18/11 + * Time: 1:29 PM + */ +public interface AMenuItem { + + @NotNull + String getCaption(); + + void doAction(@NotNull T data, @NotNull Context context); +} diff --git a/src/main/java/org/solovyev/android/view/EnumMenu.java b/src/main/java/org/solovyev/android/view/EnumMenu.java new file mode 100644 index 00000000..620c1a0e --- /dev/null +++ b/src/main/java/org/solovyev/android/view/EnumMenu.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view; + +import org.jetbrains.annotations.NotNull; + +/** + * User: serso + * Date: 12/18/11 + * Time: 1:34 PM + */ +public class EnumMenu implements AMenu { + + @NotNull + private final AMenu menu; + + public EnumMenu(Class enumClass) { + this.menu = new MenuImpl(enumClass.getEnumConstants()); + } + + @Override + public T itemAt(int i) { + return this.menu.itemAt(i); + } + + @NotNull + @Override + public CharSequence[] getMenuCaptions() { + return this.menu.getMenuCaptions(); + } +} diff --git a/src/main/java/org/solovyev/android/view/MenuImpl.java b/src/main/java/org/solovyev/android/view/MenuImpl.java new file mode 100644 index 00000000..b2d1a764 --- /dev/null +++ b/src/main/java/org/solovyev/android/view/MenuImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009-2011. Created by serso aka se.solovyev. + * For more information, please, contact se.solovyev@gmail.com + * or visit http://se.solovyev.org + */ + +package org.solovyev.android.view; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.solovyev.common.utils.CollectionsUtils; + +import java.util.ArrayList; +import java.util.List; + +/** +* User: serso +* Date: 12/18/11 +* Time: 1:31 PM +*/ +public class MenuImpl implements AMenu { + + private final List menuItems = new ArrayList(); + + public MenuImpl(T... menuItems) { + this(CollectionsUtils.asList(menuItems)); + } + + public MenuImpl(@NotNull List menuItems) { + this.menuItems.addAll(menuItems); + } + + @Override + @Nullable + public T itemAt(int i) { + if (i >= 0 && i < menuItems.size()) { + return menuItems.get(i); + } else { + return null; + } + } + + @Override + @NotNull + public CharSequence[] getMenuCaptions() { + final CharSequence[] result = new CharSequence[this.menuItems.size()]; + for (int i = 0; i < this.menuItems.size(); i++) { + result[i] = this.menuItems.get(i).getCaption(); + } + return result; + } +} diff --git a/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java b/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java index 1087ed1b..04539c9e 100644 --- a/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java +++ b/src/main/java/org/solovyev/android/view/widgets/DirectionDragButton.java @@ -308,7 +308,7 @@ public class DirectionDragButton extends DragButton { } protected static int getDefaultDirectionTextAlpha() { - return 150; + return 100; } @Nullable