/*
* Copyright (C) 2007 The Android Open Source Project
*
* 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.
*/
package net.redgeek.android.eventrend;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import net.redgeek.android.eventrend.backgroundtasks.UpdateRecentDataTask;
import net.redgeek.android.eventrend.calendar.CalendarActivity;
import net.redgeek.android.eventrend.category.CategoryEditActivity;
import net.redgeek.android.eventrend.category.CategoryListAdapter;
import net.redgeek.android.eventrend.category.CategoryRow;
import net.redgeek.android.eventrend.category.CategoryRowView;
import net.redgeek.android.eventrend.datum.EntryListActivity;
import net.redgeek.android.eventrend.db.CategoryDbTable;
import net.redgeek.android.eventrend.db.EntryDbTable;
import net.redgeek.android.eventrend.db.EvenTrendDbAdapter;
import net.redgeek.android.eventrend.graph.GraphActivity;
import net.redgeek.android.eventrend.primitives.TimeSeries;
import net.redgeek.android.eventrend.primitives.TimeSeriesCollector;
import net.redgeek.android.eventrend.util.DateUtil;
import net.redgeek.android.eventrend.util.GUITask;
import net.redgeek.android.eventrend.util.GUITaskQueue;
import net.redgeek.android.eventrend.util.ProgressIndicator;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.View.OnTouchListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import android.widget.ViewFlipper;
/**
* Main interface screen, aside from the GraphActivity. This is also the root
* activity and interface, were most if not all of the data inputing is
* performed by the user. (The exceptions bring category and entry editing.)
*
* @author barclay
*/
public class InputActivity extends EvenTrendActivity {
// Menu-button IDs
private static final int MENU_ADD_ID = Menu.FIRST;
private static final int MENU_GRAPH_ID = Menu.FIRST + 1;
private static final int MENU_CALENDAR_ID = Menu.FIRST + 2;
private static final int MENU_EDIT_ID = Menu.FIRST + 3;
private static final int MENU_PREFS_ID = Menu.FIRST + 4;
private static final int MENU_HELP_ID = Menu.FIRST + 5;
// Context menu IDs
private static final int CONTEXT_EDIT = Menu.FIRST + 5;
private static final int CONTEXT_MOVE_UP = Menu.FIRST + 6;
private static final int CONTEXT_MOVE_DOWN = Menu.FIRST + 7;
private static final int CONTEXT_DELETE = Menu.FIRST + 8;
// Dialog IDs
private static final int TIME_DIALOG_ID = 0;
private static final int DATE_DIALOG_ID = 1;
private static final int HELP_DIALOG_ID = 2;
private static final int DELETE_DIALOG_ID = 3;
// Generated IDs for flipper listview
public static final int SCROLL_VIEW_ID_BASE = 1000;
public static final int LIST_VIEW_ID_BASE = 2000;
// UI elements
private ViewFlipper mFlipper;
private Button mPickDate;
private Button mPickTime;
private CheckBox mPickNow;
private Button mUndo;
private TextView mTimestampView;
private ArrayList<ListView> mCategories;
private ArrayList<CategoryListAdapter> mCLAs;
private ListView mVisibleCategoriesLayout;
ProgressIndicator.Titlebar mProgress;
private GestureDetector mGestureDetector;
// For undo
private long mLastAddId = -1;
private float mLastAddValue = 0.0f;
private long mLastAddTimestamp = 0;
private TextView mLastAddTextView;
private CategoryRowView mLastAddRowView;
private int mContextPosition = -1;
private Lock mUndoLock;
private int mOldHour = 0;
private DateUtil.DateItem mTimestamp;
private Calendar mCal;
// for delete
private long mDeleteId = 0;
private String mDeleteName = "";
// From preferences
private String mDefaultGroup;
private int mHistory;
private float mSmoothing;
private float mSensitivity;
// Listeners
private OnTouchListener mTouchListener;
private View.OnClickListener mPickDateListener;
private View.OnClickListener mPickTimeListener;
private View.OnClickListener mPickNowListener;
private View.OnClickListener mUndoListener;
private DatePickerDialog.OnDateSetListener mDateSetListener;
private TimePickerDialog.OnTimeSetListener mTimeSetListener;
// Tasks, handlers, etc
private UpdateRecentDataTask mDataUpdater;
private Runnable mUpdateNowTime;
private Handler mNowHandler;
private TimeSeriesCollector mTSC;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
getPrefs();
setupTasksAndData();
setupUI();
fillCategoryData(-1);
setCurrentViews(true);
}
public EvenTrendDbAdapter getDb() {
return getDbh();
}
public TextView getTimestampView() {
return mTimestampView;
}
public long getTimestampMs() {
return mTimestamp.mMillis;
}
public long getLastAddId() {
return mLastAddId;
}
// *** background tasks ***/
@Override
public void executeNonGuiTask() throws Exception {
mDataUpdater.fillAllCategories();
}
@Override
public void onFailure(Throwable t) {
}
// *** main setup routines ***/
private void getPrefs() {
mDefaultGroup = Preferences.getDefaultGroup(getCtx());
mHistory = Preferences.getHistory(getCtx());
mSmoothing = Preferences.getSmoothingConstant(getCtx());
mSensitivity = Preferences.getStdDevSensitivity(getCtx());
}
private void setupTasksAndData() {
mUndoLock = new ReentrantLock();
mTSC = new TimeSeriesCollector(getDbh());
mTSC.setHistory(mHistory);
mTSC.setSmoothing(mSmoothing);
mTSC.setSensitivity(mSensitivity);
mTSC.setInterpolators(((EvenTrendActivity) getCtx()).getInterpolators());
mTSC.updateTimeSeriesMetaLocking(true);
mDataUpdater = new UpdateRecentDataTask(mTSC, mHistory);
// mDataUpdater.setZerofill(true);
// mDataUpdater.setUpdateTrend(true);
// GUITaskQueue.getInstance().addTask(mProgress, this);
mTimestamp = new DateUtil.DateItem();
mCal = Calendar.getInstance();
mOldHour = mCal.get(Calendar.HOUR_OF_DAY);
mUpdateNowTime = new Runnable() {
public void run() {
mCal.setTimeInMillis(System.currentTimeMillis());
int newHour = mCal.get(Calendar.HOUR_OF_DAY);
if (mPickNow.isChecked() == true)
setTimestampNow();
if (newHour != mOldHour) {
mOldHour = newHour;
mDataUpdater.setZerofill(true);
mDataUpdater.setUpdateTrend(true);
GUITaskQueue.getInstance().addTask(mProgress, (GUITask) getCtx());
}
mNowHandler.postDelayed(mUpdateNowTime, DateUtil.SECOND_MS);
}
};
mNowHandler = new Handler();
scheduleUpdateNow();
}
private void setupUI() {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.category_list);
mProgress = new ProgressIndicator.Titlebar(getCtx());
mCategories = new ArrayList<ListView>();
mCLAs = new ArrayList<CategoryListAdapter>();
initListeners();
mTimestampView = (TextView) findViewById(R.id.entry_timestamp);
mPickDate = (Button) findViewById(R.id.entry_set_date);
mPickDate.setOnClickListener(mPickDateListener);
mPickTime = (Button) findViewById(R.id.entry_set_time);
mPickTime.setOnClickListener(mPickTimeListener);
mPickNow = (CheckBox) findViewById(R.id.entry_set_now);
mPickNow.setOnClickListener(mPickNowListener);
mUndo = (Button) findViewById(R.id.entry_undo);
mUndo.setClickable(false);
mUndo.setTextColor(Color.GRAY);
mUndo.setOnClickListener(mUndoListener);
mFlipper = (ViewFlipper) findViewById(R.id.view_flipper);
mFlipper.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.slide_in_left));
mFlipper.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.slide_out_right));
setTimestampNow();
setupGestures();
}
private void initListeners() {
mPickDateListener = new View.OnClickListener() {
public void onClick(View v) {
mPickNow.setChecked(false);
mTimestampView.setBackgroundColor(Color.RED);
showDialog(DATE_DIALOG_ID);
}
};
mPickTimeListener = new View.OnClickListener() {
public void onClick(View v) {
mPickNow.setChecked(false);
mTimestampView.setBackgroundColor(Color.RED);
showDialog(TIME_DIALOG_ID);
}
};
mPickNowListener = new View.OnClickListener() {
public void onClick(View v) {
setTimestampNow();
}
};
mUndoListener = new View.OnClickListener() {
public void onClick(View v) {
undo();
}
};
mDateSetListener = new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
mTimestamp.mYear = year;
mTimestamp.mMonth = monthOfYear;
mTimestamp.mDay = dayOfMonth;
updateDisplay();
}
};
mTimeSetListener = new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
mTimestamp.mHour = hourOfDay;
mTimestamp.mMinute = minute;
updateDisplay();
}
};
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
mContextPosition = position;
l.showContextMenu();
}
// *** All things gesture-related ***//
public void setupGestures() {
mGestureDetector = new GestureDetector(
new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
float deltaX = e2.getRawX() - e1.getRawX();
float deltaY = e2.getRawY() - e1.getRawY();
int minSlideWidth = mFlipper.getWidth() / 3;
if (Math.abs(deltaY) < Math.abs(deltaX)) {
if (deltaX > minSlideWidth) {
slideRight();
return true;
}
if (deltaX < -minSlideWidth) {
slideLeft();
return true;
}
}
return false;
}
});
mGestureDetector.setIsLongpressEnabled(true);
mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
};
mFlipper.setLongClickable(true);
mFlipper.setOnTouchListener(mTouchListener);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mGestureDetector.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
// *** some overrides ***/
@Override
protected void onPause() {
scheduleUpdateStop();
super.onPause();
}
@Override
protected void onResume() {
scheduleUpdateNow();
getPrefs();
mTSC.updateTimeSeriesMetaLocking(false);
fillCategoryData(mFlipper.getDisplayedChild());
setCurrentViews(false);
if (mDataUpdater != null) {
mDataUpdater.setZerofill(true);
mDataUpdater.setUpdateTrend(true);
GUITaskQueue.getInstance().addTask(mProgress, this);
}
super.onResume();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (resultCode == RESULT_DELETED)
mTSC.clearSeriesLocking();
}
// *** clock ***//
private void scheduleUpdateNow() {
mNowHandler.postDelayed(mUpdateNowTime, DateUtil.SECOND_MS);
}
private void scheduleUpdateStop() {
mNowHandler.removeCallbacks(mUpdateNowTime);
}
// *** oh, the menus .... ***//
@Override
public boolean onCreateOptionsMenu(Menu menu) {
boolean result = super.onCreateOptionsMenu(menu);
menu.add(0, MENU_ADD_ID, 0, R.string.menu_category_add).setIcon(
android.R.drawable.ic_menu_add);
menu.add(0, MENU_GRAPH_ID, 0, R.string.menu_graph)
.setIcon(R.drawable.graph);
menu.add(0, MENU_CALENDAR_ID, 0, R.string.menu_calendar).setIcon(
android.R.drawable.ic_menu_today);
menu.add(0, MENU_EDIT_ID, 0, R.string.menu_entry_edit).setIcon(
android.R.drawable.ic_menu_edit);
menu.add(0, MENU_PREFS_ID, 0, R.string.menu_app_prefs).setIcon(
android.R.drawable.ic_menu_preferences);
menu.add(0, MENU_HELP_ID, 0, R.string.menu_app_help).setIcon(
android.R.drawable.ic_menu_help);
return result;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
menu.add(0, CONTEXT_EDIT, 0, R.string.context_edit_category);
menu.add(0, CONTEXT_MOVE_UP, 0, R.string.context_move_up);
menu.add(0, CONTEXT_MOVE_DOWN, 0, R.string.context_move_down);
menu.add(0, CONTEXT_DELETE, 0, R.string.context_delete_category);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ADD_ID:
createCategory();
return true;
case MENU_EDIT_ID:
editEntries();
return true;
case MENU_GRAPH_ID:
graphEntries();
return true;
case MENU_CALENDAR_ID:
calendarView();
return true;
case MENU_PREFS_ID:
editPrefs();
return true;
case MENU_HELP_ID:
showDialog(HELP_DIALOG_ID);
return true;
}
return super.onOptionsItemSelected(item);
}
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item
.getMenuInfo();
int position;
if (menuInfo == null || menuInfo.position < 0) {
position = mContextPosition;
} else {
position = menuInfo.position;
menuInfo.position = -1;
}
int child = mFlipper.getDisplayedChild();
CategoryListAdapter cla = mCLAs.get(child);
long catId;
switch (item.getItemId()) {
case CONTEXT_EDIT:
catId = ((CategoryRow) cla.getItem(position)).getDbRow().getId();
editCategory(catId);
break;
case CONTEXT_MOVE_UP:
if (position > 0)
swapCategoryPositions(cla, position - 1, position);
break;
case CONTEXT_MOVE_DOWN:
if (position + 1 < cla.getCount())
swapCategoryPositions(cla, position, position + 1);
break;
case CONTEXT_DELETE:
catId = ((CategoryRow) cla.getItem(position)).getDbRow().getId();
deleteCategory(catId);
break;
default:
return super.onContextItemSelected(item);
}
return true;
}
// *** dialogs ***//
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case TIME_DIALOG_ID:
return new TimePickerDialog(this, mTimeSetListener, mTimestamp.mHour,
mTimestamp.mMinute, false);
case DATE_DIALOG_ID:
return new DatePickerDialog(this, mDateSetListener, mTimestamp.mYear,
mTimestamp.mMonth, mTimestamp.mDay);
case HELP_DIALOG_ID:
String str = getResources().getString(R.string.overview);
return getDialogUtil().newOkDialog("Help", str);
case DELETE_DIALOG_ID:
String title = "Delete the category \"" + mDeleteName + "\"?";
String msg = "All associated entries will also be deleted!";
return deleteDialog(title, msg, mDeleteId);
}
return null;
}
private Dialog deleteDialog(String title, String msg, final long catId) {
Builder b = new AlertDialog.Builder(getCtx());
b.setTitle(title);
b.setMessage(msg);
b.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
getDbh().deleteCategory(catId);
getDbh().deleteCategoryEntries(catId);
mDeleteId = 0;
mDeleteName = "";
mTSC.clearCache();
mTSC.updateTimeSeriesMetaLocking(false);
fillCategoryData(mFlipper.getDisplayedChild());
setCurrentViews(false);
}
});
b.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
setResult(RESULT_CANCELED);
}
});
Dialog d = b.create();
return d;
}
@Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch (id) {
case TIME_DIALOG_ID:
((TimePickerDialog) dialog).updateTime(mTimestamp.mHour,
mTimestamp.mMinute);
break;
case DATE_DIALOG_ID:
((DatePickerDialog) dialog).updateDate(mTimestamp.mYear,
mTimestamp.mMonth, mTimestamp.mDay);
break;
}
}
// *** Filling out the main listview ***//
private void setCurrentViews(boolean animate) {
// These can't be set until the views have been populated from
// DB in fillCategoryData()
mVisibleCategoriesLayout = (ListView) mFlipper.getCurrentView();
if (mVisibleCategoriesLayout != null) {
mVisibleCategoriesLayout.setOnCreateContextMenuListener(this);
if (animate == true)
slideDown(mVisibleCategoriesLayout, getCtx());
}
setEnabledSeries();
}
private void fillCategoryData(int switchToView) {
int list = 0;
HashMap<String, Integer> hm = new HashMap<String, Integer>();
CategoryDbTable.Row row;
CategoryListAdapter cla = null;
ListView lv = null;
TimeSeries ts;
int defaultGroupId = 0;
mCLAs.clear();
mCategories.clear();
mFlipper.removeAllViews();
for (int i = 0; i < mTSC.numSeries(); i++) {
row = mTSC.getSeriesMetaLocking(i);
if (row == null)
continue;
Integer listNum = hm.get(row.getGroupName());
if (listNum == null) {
listNum = new Integer(list);
cla = new CategoryListAdapter(this, mTSC);
mCLAs.add(cla);
lv = new ListView(this);
lv.setId(LIST_VIEW_ID_BASE + i);
mCategories.add(lv);
mFlipper.addView(lv);
hm.put(row.getGroupName(), listNum);
if (row.getGroupName().equals(mDefaultGroup)) {
defaultGroupId = list;
}
list++;
}
cla = mCLAs.get(listNum.intValue());
cla.addItem(new CategoryRow(row, mTimestamp.mMillis));
}
for (int i = 0; i < list; i++) {
lv = mCategories.get(i);
cla = mCLAs.get(i);
lv.setAdapter(cla);
}
if (switchToView < 0)
switchToView = defaultGroupId;
if (switchToView >= 0 && switchToView < mFlipper.getChildCount())
mFlipper.setDisplayedChild(switchToView);
}
public void redrawSyntheticViews() {
for (int i = 0; i < mFlipper.getChildCount(); i++) {
ListView lv = (ListView) mFlipper.getChildAt(i);
for (int j = 0; j < lv.getChildCount(); j++) {
CategoryRowView row = (CategoryRowView) lv.getChildAt(j);
if (row.getDbRow().getSynthetic() == true) {
row.populateFields();
CategoryRowView.setLayoutAnimationSlideOutLeftIn(row, getCtx());
}
}
}
}
// *** Transitions elsewhere ... ***//
private void createCategory() {
Intent i = new Intent(this, CategoryEditActivity.class);
startActivityForResult(i, CATEGORY_CREATE);
}
private void editCategory(long catId) {
Intent i = new Intent(this, CategoryEditActivity.class);
i.putExtra(CategoryDbTable.KEY_ROWID, catId);
startActivityForResult(i, CATEGORY_EDIT);
}
private void deleteCategory(long catId) {
mDeleteId = catId;
mDeleteName = mTSC.getSeriesByIdLocking(catId).getDbRow().getCategoryName();
showDialog(DELETE_DIALOG_ID);
}
private void editEntries() {
Intent i = new Intent(this, EntryListActivity.class);
mTSC.clearSeriesLocking();
startActivityForResult(i, ENTRY_LIST);
}
private void editPrefs() {
Intent i = new Intent(this, Preferences.class);
startActivityForResult(i, PREFS_EDIT);
}
private void graphEntries() {
Intent i = new Intent(this, GraphActivity.class);
ArrayList<Integer> catIds = new ArrayList<Integer>();
ArrayList<TimeSeries> series = mTSC.getAllEnabledSeries();
for (int j = 0; j < series.size(); j++) {
TimeSeries ts = series.get(j);
if (ts.isEnabled())
catIds.add(new Integer((int) ts.getDbRow().getId()));
}
i.putIntegerArrayListExtra(VIEW_DEFAULT_CATIDS, catIds);
startActivityForResult(i, GRAPH_VIEW);
}
private void calendarView() {
Intent i = new Intent(this, CalendarActivity.class);
ArrayList<Integer> catIds = new ArrayList<Integer>();
ArrayList<TimeSeries> series = mTSC.getAllEnabledSeries();
for (int j = 0; j < series.size(); j++) {
TimeSeries ts = series.get(j);
catIds.add(new Integer((int) ts.getDbRow().getId()));
}
i.putIntegerArrayListExtra(VIEW_DEFAULT_CATIDS, catIds);
startActivityForResult(i, CALENDAR_VIEW);
}
// *** display update routines ***/
public void setTimestampNow() {
mCal.setTimeInMillis(System.currentTimeMillis());
mTimestamp.setTo(mCal);
updateDisplay();
}
private void updateDisplay() {
mCal.set(Calendar.YEAR, mTimestamp.mYear);
mCal.set(Calendar.MONTH, mTimestamp.mMonth);
mCal.set(Calendar.DAY_OF_MONTH, mTimestamp.mDay);
mCal.set(Calendar.HOUR_OF_DAY, mTimestamp.mHour);
mCal.set(Calendar.MINUTE, mTimestamp.mMinute);
mCal.set(Calendar.SECOND, mTimestamp.mSecond);
mTimestamp.setTo(mCal);
mTimestampView.setText(DateUtil.toTimestamp(mCal));
mTimestampView.setTextColor(Color.LTGRAY);
if (mPickNow.isChecked() == true) {
mTimestampView.setBackgroundColor(Color.BLACK);
} else {
mTimestampView.setBackgroundColor(Color.RED);
}
}
// used for undo
public void setLastAdd(long id, float val, long timestamp, TextView textView,
CategoryRowView rowView) {
while (mUndoLock.tryLock() == false) {
}
mUndo.setClickable(true);
mUndo.setTextColor(Color.BLACK);
mLastAddId = id;
mLastAddValue = val;
mLastAddTimestamp = timestamp;
mLastAddTextView = textView;
mLastAddRowView = rowView;
mUndoLock.unlock();
}
public void undo() {
while (mUndoLock.tryLock() == false) {
}
EntryDbTable.Row entry = getDbh().fetchEntry(mLastAddId);
if (entry == null)
return;
CategoryDbTable.Row cat = getDbh().fetchCategory(entry.getCategoryId());
if (cat == null)
return;
float oldValue = entry.getValue();
String newValueStr;
if (entry.getNEntries() == 1) {
getDbh().deleteEntry(mLastAddId);
newValueStr = "(deleted)";
} else {
newValueStr = "" + mLastAddValue;
entry.setValue(mLastAddValue);
entry.setNEntries(entry.getNEntries() - 1);
getDbh().updateEntry(entry);
}
mUndoLock.unlock();
mTSC.updateCategoryTrend(cat.getId());
String shortStr = "Undid @ " + DateUtil.toShortTimestamp(mLastAddTimestamp)
+ ": " + oldValue + " -> " + newValueStr;
String longStr = "Undid " + cat.getCategoryName() + " @ "
+ DateUtil.toTimestamp(mLastAddTimestamp) + ": " + oldValue + " -> "
+ newValueStr;
mLastAddTextView.setText(shortStr);
Toast.makeText(this, longStr, Toast.LENGTH_LONG).show();
slideOutRightIn(mLastAddRowView, getCtx());
mUndo.setClickable(false);
mUndo.setTextColor(Color.GRAY);
}
private void setEnabledSeries() {
if (mTSC.numSeries() > 0) {
for (int i = 0; i < mTSC.numSeries(); i++) {
long id = mTSC.getSeriesIdLocking(i);
mTSC.setSeriesEnabled(id, false);
}
int childIndex = mFlipper.getDisplayedChild();
CategoryListAdapter cla = mCLAs.get(childIndex);
if (cla != null) {
for (int i = 0; i < cla.getCount(); i++) {
CategoryRow row = (CategoryRow) cla.getItem(i);
mTSC.setSeriesEnabled(row.getDbRow().getId(), true);
}
}
}
return;
}
// *** Animations ***//
private void swapCategoryPositions(CategoryListAdapter cla, int higher,
int lower) {
TimeSeries ts;
CategoryRow above = (CategoryRow) cla.getItem(higher);
CategoryRow below = (CategoryRow) cla.getItem(lower);
int rank = below.getDbRow().getRank();
below.getDbRow().setRank(above.getDbRow().getRank());
above.getDbRow().setRank(rank);
getDbh().updateCategoryRank(below.getDbRow().getId(),
below.getDbRow().getRank());
getDbh().updateCategoryRank(above.getDbRow().getId(),
above.getDbRow().getRank());
ts = mTSC.getSeriesByIdLocking(above.getDbRow().getId());
if (ts != null)
ts.getDbRow().setRank(above.getDbRow().getRank());
ts = mTSC.getSeriesByIdLocking(below.getDbRow().getId());
if (ts != null)
ts.getDbRow().setRank(below.getDbRow().getRank());
CategoryRowView top = (CategoryRowView) mVisibleCategoriesLayout
.getChildAt(higher);
CategoryRowView bottom = (CategoryRowView) mVisibleCategoriesLayout
.getChildAt(lower);
swapUpDown(top, bottom, getCtx());
fillCategoryData(mFlipper.getDisplayedChild());
setCurrentViews(false);
}
public static void slideDown(ViewGroup group, Context ctx) {
AnimationSet set = new AnimationSet(true);
Animation animation = new AlphaAnimation(0.0f, 1.0f);
animation.setDuration(100);
set.addAnimation(animation);
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,
Animation.RELATIVE_TO_SELF, 0.0f);
animation.setDuration(500);
set.addAnimation(animation);
LayoutAnimationController controller = new LayoutAnimationController(set,
0.25f);
group.setLayoutAnimation(controller);
}
protected void slideLeft() {
Animation slideInLeft = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
Animation slideOutRight = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
slideInLeft.setDuration(500);
slideOutRight.setDuration(500);
mFlipper.setInAnimation(slideInLeft);
mFlipper.setOutAnimation(slideOutRight);
mFlipper.showNext();
setCurrentViews(false);
}
protected void slideRight() {
Animation slideOutLeft = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
Animation slideInRight = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
-1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
slideOutLeft.setDuration(500);
slideInRight.setDuration(500);
mFlipper.setInAnimation(slideInRight);
mFlipper.setOutAnimation(slideOutLeft);
mFlipper.showPrevious();
setCurrentViews(false);
}
public static void swapUpDown(ViewGroup top, ViewGroup bottom, Context ctx) {
AnimationSet s1 = new AnimationSet(true);
AnimationSet s2 = new AnimationSet(true);
Animation moveUp = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -1.0f);
moveUp.setStartOffset(0);
moveUp.setDuration(500);
s1.addAnimation(moveUp);
s1.setDuration(500);
Animation moveDown = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 1.0f);
moveUp.setStartOffset(0);
moveUp.setDuration(500);
s2.addAnimation(moveDown);
s2.setDuration(500);
LayoutAnimationController c1 = new LayoutAnimationController(s1, 0.25f);
LayoutAnimationController c2 = new LayoutAnimationController(s2, 0.25f);
top.setLayoutAnimation(c2);
bottom.setLayoutAnimation(c1);
}
public static void slideOutRightIn(ViewGroup group, Context ctx) {
AnimationSet set = new AnimationSet(true);
Animation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
animation.setStartOffset(0);
animation.setDuration(500);
animation.setRepeatCount(1);
animation.setRepeatMode(Animation.REVERSE);
set.addAnimation(animation);
set.setDuration(500);
LayoutAnimationController controller = new LayoutAnimationController(set,
0.25f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
group.setLayoutAnimation(controller);
}
}