|
|
|
|
@ -0,0 +1,355 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
|
|
|
|
|
*
|
|
|
|
|
* 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.micode.notes.ui;
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
|
import android.app.AlertDialog;
|
|
|
|
|
import android.content.AsyncQueryHandler;
|
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
import android.view.ActionMode;
|
|
|
|
|
import android.view.Menu;
|
|
|
|
|
import android.view.MenuItem;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
import android.widget.AdapterView;
|
|
|
|
|
import android.widget.AdapterView.OnItemClickListener;
|
|
|
|
|
import android.widget.ListView;
|
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
|
|
import net.micode.notes.R;
|
|
|
|
|
import net.micode.notes.data.Notes;
|
|
|
|
|
import net.micode.notes.data.Notes.NoteColumns;
|
|
|
|
|
import net.micode.notes.data.TrashException;
|
|
|
|
|
import net.micode.notes.data.TrashManager;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 回收站Activity
|
|
|
|
|
* <p>
|
|
|
|
|
* 显示回收站中的所有便签,支持恢复、永久删除和清空回收站操作
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
|
|
|
|
public class TrashActivity extends Activity {
|
|
|
|
|
private static final String TAG = "TrashActivity";
|
|
|
|
|
|
|
|
|
|
private static final int TRASH_LIST_QUERY_TOKEN = 0;
|
|
|
|
|
|
|
|
|
|
private ListView mTrashListView;
|
|
|
|
|
private NotesListAdapter mTrashListAdapter;
|
|
|
|
|
private BackgroundQueryHandler mBackgroundQueryHandler;
|
|
|
|
|
private ContentResolver mContentResolver;
|
|
|
|
|
private TrashManager mTrashManager;
|
|
|
|
|
private ModeCallback mModeCallback;
|
|
|
|
|
private TextView mEmptyView;
|
|
|
|
|
private TextView mTitleBar;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
setContentView(R.layout.trash_list);
|
|
|
|
|
|
|
|
|
|
initResources();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void initResources() {
|
|
|
|
|
mContentResolver = getContentResolver();
|
|
|
|
|
mBackgroundQueryHandler = new BackgroundQueryHandler(mContentResolver);
|
|
|
|
|
mTrashManager = TrashManager.getInstance(this);
|
|
|
|
|
mModeCallback = new ModeCallback();
|
|
|
|
|
|
|
|
|
|
mTrashListView = (ListView) findViewById(R.id.trash_list);
|
|
|
|
|
mEmptyView = (TextView) findViewById(R.id.empty_view);
|
|
|
|
|
mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
|
|
|
|
|
|
|
|
|
|
mTrashListView.setEmptyView(mEmptyView);
|
|
|
|
|
mTrashListView.setOnItemClickListener(new OnTrashItemClickListener());
|
|
|
|
|
mTrashListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
|
|
|
|
mTrashListView.setMultiChoiceModeListener(mModeCallback);
|
|
|
|
|
|
|
|
|
|
mTrashListAdapter = new NotesListAdapter(this);
|
|
|
|
|
mTrashListView.setAdapter(mTrashListAdapter);
|
|
|
|
|
|
|
|
|
|
mTitleBar.setText(R.string.trash_folder_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void startAsyncTrashQuery() {
|
|
|
|
|
String selection = NoteColumns.PARENT_ID + "=?";
|
|
|
|
|
mBackgroundQueryHandler.startQuery(
|
|
|
|
|
TRASH_LIST_QUERY_TOKEN,
|
|
|
|
|
null,
|
|
|
|
|
Notes.CONTENT_NOTE_URI,
|
|
|
|
|
NoteItemData.PROJECTION,
|
|
|
|
|
selection,
|
|
|
|
|
new String[]{String.valueOf(Notes.ID_TRASH_FOLER)},
|
|
|
|
|
NoteColumns.MODIFIED_DATE + " DESC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class BackgroundQueryHandler extends AsyncQueryHandler {
|
|
|
|
|
public BackgroundQueryHandler(ContentResolver contentResolver) {
|
|
|
|
|
super(contentResolver);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
|
|
|
|
|
if (token == TRASH_LIST_QUERY_TOKEN) {
|
|
|
|
|
mTrashListAdapter.changeCursor(cursor);
|
|
|
|
|
updateEmptyView();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateEmptyView() {
|
|
|
|
|
int count = mTrashManager.getTrashCount();
|
|
|
|
|
if (count == 0) {
|
|
|
|
|
mEmptyView.setText(R.string.trash_empty);
|
|
|
|
|
mEmptyView.setVisibility(View.VISIBLE);
|
|
|
|
|
} else {
|
|
|
|
|
mEmptyView.setVisibility(View.GONE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class OnTrashItemClickListener implements OnItemClickListener {
|
|
|
|
|
@Override
|
|
|
|
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
|
|
|
|
if (view instanceof NotesListItem) {
|
|
|
|
|
NoteItemData item = ((NotesListItem) view).getItemData();
|
|
|
|
|
if (mTrashListAdapter.isInChoiceMode()) {
|
|
|
|
|
if (item.getType() == Notes.TYPE_NOTE) {
|
|
|
|
|
position = position - mTrashListView.getHeaderViewsCount();
|
|
|
|
|
mModeCallback.onItemCheckedStateChanged(null, position, id,
|
|
|
|
|
!mTrashListAdapter.isSelectedItem(position));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
showNoteDetailDialog(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void showNoteDetailDialog(final NoteItemData item) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle(item.getSnippet());
|
|
|
|
|
builder.setMessage(item.getSnippet());
|
|
|
|
|
|
|
|
|
|
builder.setPositiveButton(R.string.menu_restore, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
restoreNote(item.getId());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.setNegativeButton(R.string.menu_permanently_delete, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
permanentlyDeleteNote(item.getId());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
builder.setNeutralButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void restoreNote(long noteId) {
|
|
|
|
|
try {
|
|
|
|
|
mTrashManager.restoreFromTrash(noteId);
|
|
|
|
|
Toast.makeText(this, R.string.toast_restore_success, Toast.LENGTH_SHORT).show();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
} catch (TrashException e) {
|
|
|
|
|
Toast.makeText(this, getErrorMessage(e), Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void permanentlyDeleteNote(long noteId) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle(R.string.alert_title_permanently_delete);
|
|
|
|
|
builder.setMessage(R.string.alert_message_permanently_delete);
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
try {
|
|
|
|
|
mTrashManager.permanentlyDelete(noteId);
|
|
|
|
|
Toast.makeText(TrashActivity.this, R.string.toast_delete_success, Toast.LENGTH_SHORT).show();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
} catch (TrashException e) {
|
|
|
|
|
Toast.makeText(TrashActivity.this, getErrorMessage(e), Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class ModeCallback implements ListView.MultiChoiceModeListener {
|
|
|
|
|
private ActionMode mActionMode;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
|
|
|
|
getMenuInflater().inflate(R.menu.trash_options, menu);
|
|
|
|
|
mActionMode = mode;
|
|
|
|
|
mTrashListAdapter.setChoiceMode(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
|
|
|
|
int selectedCount = mTrashListAdapter.getSelectedCount();
|
|
|
|
|
if (selectedCount == 0) {
|
|
|
|
|
Toast.makeText(TrashActivity.this, R.string.menu_select_none, Toast.LENGTH_SHORT).show();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
|
if (itemId == R.id.menu_restore) {
|
|
|
|
|
restoreSelectedNotes();
|
|
|
|
|
} else if (itemId == R.id.menu_permanently_delete) {
|
|
|
|
|
permanentlyDeleteSelectedNotes();
|
|
|
|
|
} else if (itemId == R.id.menu_empty_trash) {
|
|
|
|
|
emptyTrash();
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
|
mTrashListAdapter.setChoiceMode(false);
|
|
|
|
|
mActionMode = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
|
|
|
|
|
mTrashListAdapter.setCheckedItem(position, checked);
|
|
|
|
|
if (mActionMode != null) {
|
|
|
|
|
int count = mTrashListAdapter.getSelectedCount();
|
|
|
|
|
mActionMode.setTitle(getResources().getString(R.string.menu_select_title, count));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void finishActionMode() {
|
|
|
|
|
if (mActionMode != null) {
|
|
|
|
|
mActionMode.finish();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void restoreSelectedNotes() {
|
|
|
|
|
long[] selectedIds = getSelectedNoteIds();
|
|
|
|
|
if (selectedIds.length > 0) {
|
|
|
|
|
try {
|
|
|
|
|
mTrashManager.batchRestoreFromTrash(selectedIds);
|
|
|
|
|
Toast.makeText(this, getString(R.string.toast_restore_multiple, selectedIds.length),
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
mModeCallback.finishActionMode();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
} catch (TrashException e) {
|
|
|
|
|
Toast.makeText(this, getErrorMessage(e), Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void permanentlyDeleteSelectedNotes() {
|
|
|
|
|
final long[] selectedIds = getSelectedNoteIds();
|
|
|
|
|
if (selectedIds.length > 0) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle(R.string.alert_title_permanently_delete);
|
|
|
|
|
builder.setMessage(getString(R.string.alert_message_permanently_delete_multiple, selectedIds.length));
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
try {
|
|
|
|
|
mTrashManager.batchPermanentlyDelete(selectedIds);
|
|
|
|
|
Toast.makeText(TrashActivity.this,
|
|
|
|
|
getString(R.string.toast_delete_multiple, selectedIds.length),
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
mModeCallback.finishActionMode();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
} catch (TrashException e) {
|
|
|
|
|
Toast.makeText(TrashActivity.this, getErrorMessage(e), Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void emptyTrash() {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle(R.string.alert_title_empty_trash);
|
|
|
|
|
builder.setMessage(R.string.alert_message_empty_trash);
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
try {
|
|
|
|
|
mTrashManager.emptyTrash();
|
|
|
|
|
Toast.makeText(TrashActivity.this, R.string.toast_empty_trash_success,
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
} catch (TrashException e) {
|
|
|
|
|
Toast.makeText(TrashActivity.this, getErrorMessage(e), Toast.LENGTH_SHORT).show();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private long[] getSelectedNoteIds() {
|
|
|
|
|
java.util.HashSet<Long> selectedIds = mTrashListAdapter.getSelectedItemIds();
|
|
|
|
|
long[] ids = new long[selectedIds.size()];
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (Long id : selectedIds) {
|
|
|
|
|
ids[i++] = id;
|
|
|
|
|
}
|
|
|
|
|
return ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getErrorMessage(TrashException e) {
|
|
|
|
|
switch (e.getErrorType()) {
|
|
|
|
|
case INVALID_NOTE_ID:
|
|
|
|
|
return getString(R.string.error_note_not_exist);
|
|
|
|
|
case NOT_IN_TRASH:
|
|
|
|
|
return getString(R.string.toast_restore_failed);
|
|
|
|
|
case NOTE_NOT_FOUND:
|
|
|
|
|
return getString(R.string.error_note_not_exist);
|
|
|
|
|
case DATABASE_ERROR:
|
|
|
|
|
return getString(R.string.toast_restore_failed);
|
|
|
|
|
default:
|
|
|
|
|
return getString(R.string.toast_restore_failed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onResume() {
|
|
|
|
|
super.onResume();
|
|
|
|
|
startAsyncTrashQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onBackPressed() {
|
|
|
|
|
super.onBackPressed();
|
|
|
|
|
finish();
|
|
|
|
|
}
|
|
|
|
|
}
|