第六次合并 #6

Merged
m6omickaf merged 3 commits from dev into master 2 years ago

@ -10,10 +10,13 @@
- 2023/4/21 完成新功能需求文档 - 2023/4/21 完成新功能需求文档
- 2023/4/28 新体系结构初稿设计完成 - 2023/4/28 新体系结构初稿设计完成
- 2023/4/28 新功能UI雏形设计完成 - 2023/4/28 新功能UI雏形设计完成
- 2023/5/26 久违的更新了readme文件
- 2023/5/26 完成了回收站的雏形
## TODO ## TODO
- [x] 新功能需求分析 - [ ] 回收站
- [ ] 新功能实现
- [ ] BUG修复 - [ ] BUG修复
- [x] 体系结构 - [ ] 背景切换
- [ ] UI设计 - [ ] 代码质量分析报告
- [ ] 需求与设计方案
- [ ] 汇报PPT

@ -12,6 +12,6 @@
</deviceKey> </deviceKey>
</Target> </Target>
</targetSelectedWithDropDown> </targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-04-10T13:04:51.122769700Z" /> <timeTargetWasSelectedWithDropDown value="2023-05-26T06:09:38.060917300Z" />
</component> </component>
</project> </project>

@ -40,17 +40,27 @@
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/Theme.AppCompat" android:theme="@style/NoteTheme"
android:uiOptions="splitActionBarWhenNarrow"
android:windowSoftInputMode="adjustPan" android:windowSoftInputMode="adjustPan"
android:exported="true" > android:exported="true" >
<!-- android:theme="@style/Theme.AppCompat"-->
<!-- android:uiOptions="splitActionBarWhenNarrow"-->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".ui.RecycleBinActivity"
android:configChanges="keyboardHidden|orientation|screenLayout"
android:launchMode="singleTop"
android:theme="@style/NoteTheme"
android:exported="true">
</activity>
<activity <activity
android:name=".ui.NoteEditActivity" android:name=".ui.NoteEditActivity"
android:configChanges="keyboardHidden|orientation|screenSize" android:configChanges="keyboardHidden|orientation|screenSize"

@ -17,6 +17,7 @@
package net.micode.notes.ui; package net.micode.notes.ui;
import android.app.Activity; import android.app.Activity;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.PendingIntent; import android.app.PendingIntent;

@ -80,7 +80,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.HashSet; import java.util.HashSet;
public class NotesListActivity extends AppCompatActivity implements OnClickListener, OnItemLongClickListener { public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
private static final int FOLDER_LIST_QUERY_TOKEN = 1; private static final int FOLDER_LIST_QUERY_TOKEN = 1;
@ -472,24 +472,35 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe
} }
private void batchDelete() { private void batchDelete() {
new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() { new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() {
protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) { protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget(); HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
if (!isSyncMode()) { // if (!isSyncMode()) {
// if not synced, delete notes directly // // if not synced, delete notes directly
if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter // if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
.getSelectedItemIds())) { // .getSelectedItemIds())) {
} else { // } else {
Log.e(TAG, "Delete notes error, should not happens"); // Log.e(TAG, "Delete notes error, should not happens");
} // }
} else { // } else {
// in sync mode, we'll move the deleted note into the trash // // in sync mode, we'll move the deleted note into the trash
// folder // // 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 if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
.getSelectedItemIds(), Notes.ID_TRASH_FOLER)) { .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens"); Log.e(TAG, "Move notes to trash folder error, should not happens");
} }
}
return widgets; return widgets;
} }
@ -814,12 +825,31 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe
case R.id.menu_search: case R.id.menu_search:
onSearchRequested(); onSearchRequested();
break; break;
case R.id.RecycleBin:
recycleBin();
break;
default: default:
break; break;
} }
return true; 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 @Override
public boolean onSearchRequested() { public boolean onSearchRequested() {
startSearch(null, false, null /* appData */, false); startSearch(null, false, null /* appData */, false);

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

@ -31,11 +31,11 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/title_bar_bg" android:background="@drawable/title_bar_bg"
android:visibility="gone"
android:gravity="center_vertical" android:gravity="center_vertical"
android:singleLine="true" android:singleLine="true"
android:textColor="#FFEAD1AE" android:textColor="#FFEAD1AE"
android:textSize="@dimen/text_font_size_medium" /> android:textSize="@dimen/text_font_size_medium"
android:visibility="gone" />
<ListView <ListView
android:id="@+id/notes_list" android:id="@+id/notes_list"

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/list_background">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:ignore="UselessParent">
<ListView
android:id="@+id/recycle_list"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:cacheColorHint="@null"
android:listSelector="@android:color/transparent"
android:divider="@null"
android:fadingEdge="none" />
</LinearLayout>
</FrameLayout>

@ -36,4 +36,8 @@
<item <item
android:id="@+id/menu_search" android:id="@+id/menu_search"
android:title="@string/menu_search"/> android:title="@string/menu_search"/>
<item
android:id='@+id/RecycleBin'
android:title="RecycleBin"/>
</menu> </menu>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/select_all"
android:title="@android:string/selectAll"
android:showAsAction="always"/>
<item
android:id="@+id/recover"
android:title="@string/recover"
android:icon="@drawable/menu_move"
android:showAsAction="always" />
<item
android:id="@+id/realdelete"
android:title="@string/realdelete"
android:icon="@drawable/menu_delete"
android:showAsAction="always" />
</menu>

@ -126,6 +126,8 @@
<string name="search">Notes</string> <string name="search">Notes</string>
<string name="datetime_dialog_ok">set</string> <string name="datetime_dialog_ok">set</string>
<string name="datetime_dialog_cancel">cancel</string> <string name="datetime_dialog_cancel">cancel</string>
<string name="realdelete">realdelete</string>
<string name="recover">recover</string>
<plurals name="search_results_title"> <plurals name="search_results_title">
<item quantity="one"><xliff:g id="number" example="1">%1$s</xliff:g> result for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item> <item quantity="one"><xliff:g id="number" example="1">%1$s</xliff:g> result for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
<!-- Case of 0 or 2 or more results. --> <!-- Case of 0 or 2 or more results. -->

@ -64,6 +64,6 @@
<style name="NoteActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid"> <style name="NoteActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid">
<item name="android:displayOptions" /> <item name="android:displayOptions" />
<item name="android:visibility">gone</item> <item name="android:visibility">visible</item>
</style> </style>
</resources> </resources>
Loading…
Cancel
Save