diff --git a/README.md b/README.md index c98c5ae..2914774 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,13 @@ - 2023/4/21 完成新功能需求文档 - 2023/4/28 新体系结构初稿设计完成 - 2023/4/28 新功能UI雏形设计完成 +- 2023/5/26 久违的更新了readme文件 +- 2023/5/26 完成了回收站的雏形 ## TODO -- [x] 新功能需求分析 -- [ ] 新功能实现 +- [ ] 回收站 - [ ] BUG修复 -- [x] 体系结构 -- [ ] UI设计 \ No newline at end of file +- [ ] 背景切换 +- [ ] 代码质量分析报告 +- [ ] 需求与设计方案 +- [ ] 汇报PPT \ No newline at end of file diff --git a/src/.idea/deploymentTargetDropDown.xml b/src/.idea/deploymentTargetDropDown.xml index a35bc82..efbebf5 100644 --- a/src/.idea/deploymentTargetDropDown.xml +++ b/src/.idea/deploymentTargetDropDown.xml @@ -12,6 +12,6 @@ - + \ No newline at end of file diff --git a/src/app/src/main/AndroidManifest.xml b/src/app/src/main/AndroidManifest.xml index 006f76f..25017cc 100644 --- a/src/app/src/main/AndroidManifest.xml +++ b/src/app/src/main/AndroidManifest.xml @@ -40,17 +40,27 @@ android:configChanges="keyboardHidden|orientation|screenSize" android:label="@string/app_name" android:launchMode="singleTop" - android:theme="@style/Theme.AppCompat" - android:uiOptions="splitActionBarWhenNarrow" + android:theme="@style/NoteTheme" android:windowSoftInputMode="adjustPan" android:exported="true" > + + + + + + + >() { protected HashSet doInBackground(Void... unused) { HashSet widgets = mNotesListAdapter.getSelectedWidget(); - if (!isSyncMode()) { - // if not synced, delete notes directly - if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter - .getSelectedItemIds())) { - } else { - Log.e(TAG, "Delete notes error, should not happens"); - } - } else { - // in sync mode, we'll move the deleted note into the trash - // folder +// if (!isSyncMode()) { +// // if not synced, delete notes directly +// if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter +// .getSelectedItemIds())) { +// } else { +// Log.e(TAG, "Delete notes error, should not happens"); +// } +// } else { +// // in sync mode, we'll move the deleted note into the trash +// // folder +// if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter +// .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { +// Log.e(TAG, "Move notes to trash folder error, should not happens"); +// } +// } +// return widgets; + + mCurrentFolderId = mFocusNoteDataItem.getFolderId(); + + + //move to trash if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { Log.e(TAG, "Move notes to trash folder error, should not happens"); } - } return widgets; } @@ -814,12 +825,31 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe case R.id.menu_search: onSearchRequested(); break; + case R.id.RecycleBin: + recycleBin(); + break; default: break; } return true; } +// private void recycleBin(){ +// mState = ListEditState.SUB_FOLDER; +// mCurrentFolderId = Notes.ID_TRASH_FOLER; +// startAsyncNotesListQuery(); +// mTitleBar.setText("trash folder"); +// mTitleBar.setVisibility(View.VISIBLE); +// } + + private void recycleBin() { + Intent intent=new Intent(NotesListActivity.this,RecycleBinActivity.class); + startActivity(intent); + mTitleBar.setText("trash folder"); + mTitleBar.setVisibility(View.VISIBLE); + finish(); + } + @Override public boolean onSearchRequested() { startSearch(null, false, null /* appData */, false); diff --git a/src/app/src/main/java/net/micode/notes/ui/RecycleBinActivity.java b/src/app/src/main/java/net/micode/notes/ui/RecycleBinActivity.java new file mode 100644 index 0000000..b49fdf7 --- /dev/null +++ b/src/app/src/main/java/net/micode/notes/ui/RecycleBinActivity.java @@ -0,0 +1,247 @@ +package net.micode.notes.ui; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.AsyncQueryHandler; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +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.Toast; + +import net.micode.notes.R; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.tool.DataUtils; + +public class RecycleBinActivity extends Activity { + private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; + + private static final int FOLDER_LIST_QUERY_TOKEN = 1; + + private BackgroundQueryHandler mBackgroundQueryHandler; + + private NotesListAdapter mNotesListAdapter; + + private ListView mNotesListView; + + private long mCurrentFolderId; + + private ContentResolver mContentResolver; + + private static final String TAG = "RecycleActivity"; + + private MenuItem menuItem; + + private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; + + private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR (" + + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND " + + NoteColumns.NOTES_COUNT + ">0)"; + + private final static int REQUEST_CODE_OPEN_NODE = 102; + private final static int REQUEST_CODE_NEW_NODE = 103; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.recycle_bin); + initResources(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK + && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { + mNotesListAdapter.changeCursor(null); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + protected void onStart() { + super.onStart(); + startAsyncNotesListQuery(); + } + + @SuppressLint("InflateParams") + private void initResources() { + mContentResolver = this.getContentResolver(); + mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); + mCurrentFolderId = Notes.ID_TRASH_FOLER; + mNotesListView = findViewById(R.id.recycle_list); + mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), + null, false); + mNotesListView.setOnItemClickListener(new OnListItemClickListener()); + mNotesListAdapter = new NotesListAdapter(this); + mNotesListAdapter.setChoiceMode(true); + mNotesListView.setAdapter(mNotesListAdapter); + } + + /** + * 重置选择器状态 + */ + private void reset_ChoiseMode() { + mNotesListAdapter.setChoiceMode(false); + mNotesListAdapter.setChoiceMode(true); + } + + + private void startAsyncNotesListQuery() { + String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION + : NORMAL_SELECTION; + mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, + Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[]{ + String.valueOf(mCurrentFolderId) + }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); + } + + @SuppressLint("HandlerLeak") + private final class BackgroundQueryHandler extends AsyncQueryHandler { + public BackgroundQueryHandler(ContentResolver contentResolver) { + super(contentResolver); + } + + @Override + protected void onQueryComplete(int token, Object cookie, Cursor cursor) { + switch (token) { + case FOLDER_NOTE_LIST_QUERY_TOKEN: + mNotesListAdapter.changeCursor(cursor); + break; + case FOLDER_LIST_QUERY_TOKEN: + if (cursor != null && cursor.getCount() > 0) { + showFolderListMenu(cursor); + } else { + Log.e(TAG, "Query folder failed"); + } + break; + default: + } + } + } + + private void showFolderListMenu(Cursor cursor) { + AlertDialog.Builder builder = new AlertDialog.Builder(RecycleBinActivity.this); + builder.setTitle(R.string.menu_title_select_folder); + final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor); + builder.setAdapter(adapter, (dialog, which) -> { + DataUtils.batchMoveToFolder(mContentResolver, + mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which)); + Toast.makeText( + RecycleBinActivity.this, + getString(R.string.format_move_notes_to_folder, + mNotesListAdapter.getSelectedCount(), + adapter.getFolderName(RecycleBinActivity.this, which)), + Toast.LENGTH_SHORT).show(); + }); + builder.show(); + } + + // TODO: 2023/5/26 修改一下删除函数 + private void batchDelete() { + // delete notes directly + if (!DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter + .getSelectedItemIds())) { + Log.e(TAG, "Delete notes error, should not happens"); + } + } + + @Override + public void onBackPressed() { + Intent intent = new Intent(RecycleBinActivity.this, NotesListActivity.class); + startActivity(intent); + finish(); + } + + @Override + public void onContextMenuClosed(Menu menu) { + super.onContextMenuClosed(menu); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + return true; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.recyclebin_options, menu); + + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + + menu.clear(); + getMenuInflater().inflate(R.menu.recyclebin_options, menu); + menuItem = menu.findItem(R.id.select_all); + + return true; + } + + /** + * 当顶部菜单项被选择时所执行的函数 + */ + @Override + public boolean onOptionsItemSelected(MenuItem item) { + +// TODO: 2023/5/26 为这两个选项加入弹窗 + if (item.getItemId() == R.id.recover) { + if (!DataUtils.batchMoveToFolder(mContentResolver, + mNotesListAdapter.getSelectedItemIds(), Notes.ID_ROOT_FOLDER)) + Log.e(TAG, "Recover error, should not happens"); + } else if (item.getItemId() == R.id.realdelete) { + batchDelete(); + } else if (item.getItemId() == R.id.select_all) { + if (!mNotesListAdapter.isAllSelected()) { + item.setTitle("deselect_all"); + mNotesListAdapter.selectAll(true); + } else { + item.setTitle("selected_all"); + mNotesListAdapter.selectAll(false); + } + return true; + } + reset_ChoiseMode(); + return true; + } + + @Override + public boolean onSearchRequested() { + startSearch(null, false, null /* appData */, false); + return true; + } + + // TODO: 2023/5/26 将title改成一个icon + private class OnListItemClickListener implements OnItemClickListener { + + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (view instanceof NotesListItem) { + NoteItemData item = ((NotesListItem) view).getItemData(); + + if (item.getType() == Notes.TYPE_NOTE) { + position = position - mNotesListView.getHeaderViewsCount(); + mNotesListAdapter.setCheckedItem(position, !mNotesListAdapter.isSelectedItem(position)); + + if (mNotesListAdapter.isAllSelected()) + menuItem.setTitle("deselected_all"); + else if (menuItem.getTitle() == "deselected_all") + menuItem.setTitle("selected_all"); + } + } + } + + } +} diff --git a/src/app/src/main/res/layout/note_list.xml b/src/app/src/main/res/layout/note_list.xml index 6b25d38..711f443 100644 --- a/src/app/src/main/res/layout/note_list.xml +++ b/src/app/src/main/res/layout/note_list.xml @@ -31,11 +31,11 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="@drawable/title_bar_bg" - android:visibility="gone" android:gravity="center_vertical" android:singleLine="true" android:textColor="#FFEAD1AE" - android:textSize="@dimen/text_font_size_medium" /> + android:textSize="@dimen/text_font_size_medium" + android:visibility="gone" /> + + + + + + + + + diff --git a/src/app/src/main/res/menu/note_list.xml b/src/app/src/main/res/menu/note_list.xml index 42ea736..3bc14f2 100644 --- a/src/app/src/main/res/menu/note_list.xml +++ b/src/app/src/main/res/menu/note_list.xml @@ -36,4 +36,8 @@ + + diff --git a/src/app/src/main/res/menu/recyclebin_options.xml b/src/app/src/main/res/menu/recyclebin_options.xml new file mode 100644 index 0000000..bdaaa61 --- /dev/null +++ b/src/app/src/main/res/menu/recyclebin_options.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/src/app/src/main/res/values/strings.xml b/src/app/src/main/res/values/strings.xml index 55df868..b52ff32 100644 --- a/src/app/src/main/res/values/strings.xml +++ b/src/app/src/main/res/values/strings.xml @@ -126,6 +126,8 @@ Notes set cancel + realdelete + recover %1$s result for \"%2$s\" diff --git a/src/app/src/main/res/values/styles.xml b/src/app/src/main/res/values/styles.xml index d750e65..ad0d90d 100644 --- a/src/app/src/main/res/values/styles.xml +++ b/src/app/src/main/res/values/styles.xml @@ -64,6 +64,6 @@ \ No newline at end of file