history changes

This commit is contained in:
Sergey Solovyev 2011-12-18 17:05:44 +04:00
parent 9d785e4b1e
commit df392185f3
12 changed files with 521 additions and 63 deletions

View File

@ -19,6 +19,38 @@
<TextView a:id="@+id/history_item" <TextView a:id="@+id/history_item"
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="fill_parent" a:layout_height="fill_parent"
a:textColor="@color/button_operator_text_color"
style="@style/history_item"/> style="@style/history_item"/>
<LinearLayout a:orientation="horizontal"
a:layout_width="fill_parent"
a:layout_height="fill_parent">
<TextView a:id="@+id/history_item_comment_label"
a:layout_width="wrap_content"
a:layout_height="fill_parent"
a:text="@string/c_history_item_comment"
style="@style/history_item_label"/>
<TextView a:id="@+id/history_item_comment"
a:layout_width="fill_parent"
a:layout_height="fill_parent"
style="@style/history_item"/>
</LinearLayout>
<LinearLayout a:orientation="horizontal"
a:layout_width="fill_parent"
a:layout_height="fill_parent">
<TextView a:layout_width="wrap_content"
a:layout_height="fill_parent"
a:text="@string/c_history_item_status"
style="@style/history_item_label"/>
<TextView a:id="@+id/history_item_status"
a:layout_width="fill_parent"
a:layout_height="fill_parent"
style="@style/history_item"/>
</LinearLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<ScrollView xmlns:a="http://schemas.android.com/apk/res/android"
a:layout_width="fill_parent"
a:layout_height="fill_parent">
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/history_edit"
a:orientation="vertical"
a:layout_width="fill_parent"
a:layout_height="fill_parent"
a:scrollbars="vertical"
a:scrollbarAlwaysDrawVerticalTrack="true">
<TextView a:layout_height="fill_parent"
a:layout_width="fill_parent"
a:padding="6dp"
style="@style/default_text_size"
a:text="@string/c_history_expression"/>
<TextView a:id="@+id/history_edit_expression"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
style="@style/default_text_size">
</TextView>
<TextView a:layout_height="fill_parent"
a:layout_width="fill_parent"
style="@style/default_text_size"
a:padding="6dp"
a:text="@string/c_history_comment"/>
<EditText a:id="@+id/history_edit_comment"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
style="@style/default_text_size">
</EditText>
</LinearLayout>
</ScrollView>

View File

@ -301,5 +301,17 @@ Check the \'Round result\' preference in application settings - it should be tur
<string name="c_comment">Comment</string> <string name="c_comment">Comment</string>
<string name="c_history_item_saved">Saved</string> <string name="c_history_item_saved">Saved</string>
<string name="c_history_item_not_saved">Not saved</string>
<string name="c_expression_copied">Expression copied to the clipboard</string>
<string name="c_history_item_status">Status: </string>
<string name="c_history_item_comment">Comment: </string>
<string name="c_use_expression">Use</string>
<string name="c_copy_expression">Copy expression</string>
<string name="c_copy_result">Copy result</string>
<string name="c_history_expression">Value</string>
<string name="c_history_comment">Comment</string>
<string name="c_save_history">Save history</string>
<string name="c_edit_history">Modify history</string>
<string name="c_edit">Modify</string>
</resources> </resources>

View File

@ -6,10 +6,12 @@
<resources> <resources>
<style name="history_time" parent="var_text"> <style name="history_time" parent="var_text"/>
</style>
<style name="history_item" parent="var_description"> <style name="history_item" parent="var_description"/>
<style name="history_item_label" parent="var_description">
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/white</item>
</style> </style>
</resources> </resources>

View File

@ -11,19 +11,17 @@ import android.app.ListActivity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.history.CalculatorHistory; import org.solovyev.android.calculator.history.*;
import org.solovyev.android.calculator.history.CalculatorHistoryState;
import org.solovyev.android.calculator.history.EditorHistoryState;
import org.solovyev.android.calculator.jscl.JsclOperation; 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.android.view.prefs.ResourceCache;
import org.solovyev.common.utils.*;
import org.solovyev.common.utils.Filter; 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.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -80,8 +78,67 @@ public class CalculatorHistoryActivity extends ListActivity {
final int position, final int position,
final long id) { final long id) {
useHistoryItem((CalculatorHistoryState) parent.getItemAtPosition(position), CalculatorHistoryActivity.this);
}
});
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position); final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
final Context context = CalculatorHistoryActivity.this;
final HistoryItemMenuData data = new HistoryItemMenuData(historyState, adapter);
final List<HistoryItemMenuItem> 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<HistoryItemMenuItem> historyItemMenu = new MenuImpl<HistoryItemMenuItem>(menuItems);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setItems(historyItemMenu.getMenuCaptions(), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
final AMenuItem<HistoryItemMenuData> historyItemMenuItem = historyItemMenu.itemAt(item);
if (historyItemMenuItem != null) {
historyItemMenuItem.doAction(data, context);
}
}
});
builder.create().show();
return true;
}
});
}
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() { CalculatorModel.instance.doTextOperation(new CalculatorModel.TextOperation() {
@Override @Override
public void doOperation(@NotNull EditText editor) { public void doOperation(@NotNull EditText editor) {
@ -93,48 +150,7 @@ public class CalculatorHistoryActivity extends ListActivity {
CalculatorModel.instance.setCursorOnEnd(); CalculatorModel.instance.setCursorOnEnd();
CalculatorHistoryActivity.this.finish(); activity.finish();
}
});
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
final CalculatorHistoryState historyState = (CalculatorHistoryState) parent.getItemAtPosition(position);
final Context context = CalculatorHistoryActivity.this;
final CharSequence[] items = {context.getText(R.string.c_save), context.getText(R.string.c_remove)};
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setItems(items, 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();
}
}
});
builder.create().show();
return true;
}
});
} }
private static List<CalculatorHistoryState> getHistoryList() { private static List<CalculatorHistoryState> getHistoryList() {
@ -156,7 +172,7 @@ public class CalculatorHistoryActivity extends ListActivity {
return calculatorHistoryStates; return calculatorHistoryStates;
} }
private static class HistoryArrayAdapter extends ArrayAdapter<CalculatorHistoryState> { public class HistoryArrayAdapter extends ArrayAdapter<CalculatorHistoryState> {
private HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @NotNull List<CalculatorHistoryState> historyList) { private HistoryArrayAdapter(Context context, int resource, int textViewResourceId, @NotNull List<CalculatorHistoryState> historyList) {
super(context, resource, textViewResourceId, historyList); super(context, resource, textViewResourceId, historyList);
@ -172,33 +188,54 @@ public class CalculatorHistoryActivity extends ListActivity {
time.setText(new SimpleDateFormat().format(state.getTime())); time.setText(new SimpleDateFormat().format(state.getTime()));
final TextView editor = (TextView) result.findViewById(R.id.history_item); final TextView editor = (TextView) result.findViewById(R.id.history_item);
final StringBuilder historyText = new StringBuilder(); editor.setText(getHistoryText(state));
historyText.append(state.getEditorState().getText());
historyText.append(getIdentitySign(state.getDisplayState().getJsclOperation())); final TextView commentView = (TextView) result.findViewById(R.id.history_item_comment);
historyText.append(state.getDisplayState().getEditorState().getText());
final String comment = state.getComment(); final String comment = state.getComment();
if (!StringUtils.isEmpty(comment)) { if (!StringUtils.isEmpty(comment)) {
historyText.append("\n"); commentView.setText(comment);
historyText.append(ResourceCache.instance.getCaption("c_comment")).append(": "); } else {
historyText.append(comment); commentView.setText("");
} }
if ( state.isSaved() ) {
historyText.append("\n"); final TextView status = (TextView) result.findViewById(R.id.history_item_status);
historyText.append(ResourceCache.instance.getCaption("c_history_item_saved")); 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; return result;
} }
@NotNull @Override
private String getIdentitySign(@NotNull JsclOperation jsclOperation) { public void notifyDataSetChanged() {
return jsclOperation == JsclOperation.simplify ? "" : "="; 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 @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(android.view.Menu menu) {
final MenuInflater menuInflater = getMenuInflater(); final MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.history_menu, menu); menuInflater.inflate(R.menu.history_menu, menu);
return true; return true;
@ -228,7 +265,6 @@ public class CalculatorHistoryActivity extends ListActivity {
} }
if (adapter.getCount() > 0) { if (adapter.getCount() > 0) {
adapter.sort(COMPARATOR);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} else { } else {
Toast.makeText(this, R.string.c_history_is_empty, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.c_history_is_empty, Toast.LENGTH_SHORT).show();

View File

@ -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;
}
}

View File

@ -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<HistoryItemMenuData> {
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;
}
}

View File

@ -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<T extends AMenuItem> {
@Nullable
T itemAt(int i);
@NotNull
CharSequence[] getMenuCaptions();
}

View File

@ -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<T> {
@NotNull
String getCaption();
void doAction(@NotNull T data, @NotNull Context context);
}

View File

@ -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<T extends Enum & AMenuItem> implements AMenu<T> {
@NotNull
private final AMenu<T> menu;
public EnumMenu(Class<T> enumClass) {
this.menu = new MenuImpl<T>(enumClass.getEnumConstants());
}
@Override
public T itemAt(int i) {
return this.menu.itemAt(i);
}
@NotNull
@Override
public CharSequence[] getMenuCaptions() {
return this.menu.getMenuCaptions();
}
}

View File

@ -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<T extends AMenuItem> implements AMenu<T> {
private final List<T> menuItems = new ArrayList<T>();
public MenuImpl(T... menuItems) {
this(CollectionsUtils.asList(menuItems));
}
public MenuImpl(@NotNull List<T> 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;
}
}

View File

@ -308,7 +308,7 @@ public class DirectionDragButton extends DragButton {
} }
protected static int getDefaultDirectionTextAlpha() { protected static int getDefaultDirectionTextAlpha() {
return 150; return 100;
} }
@Nullable @Nullable