|
|
|
@ -78,6 +78,19 @@ import java.io.InputStream;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @ProjectName:
|
|
|
|
|
* @Package: net.micode.notes.ui
|
|
|
|
|
* @ClassName: NotesListActivity
|
|
|
|
|
* @Description: 显示和管理便签列表的主要界面。
|
|
|
|
|
* @Author: xumingyang
|
|
|
|
|
* @CreateDate: 2024-01-09 11:02
|
|
|
|
|
* @UpdateUser: 更新者:
|
|
|
|
|
* @UpdateDate: 2024-01-09 11:02
|
|
|
|
|
* @UpdateRemark: 更新说明:
|
|
|
|
|
* @Version: 1.0
|
|
|
|
|
*/
|
|
|
|
|
public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener {
|
|
|
|
|
private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0;
|
|
|
|
|
|
|
|
|
@ -135,39 +148,66 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
private final static int REQUEST_CODE_OPEN_NODE = 102;
|
|
|
|
|
private final static int REQUEST_CODE_NEW_NODE = 103;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onCreate
|
|
|
|
|
* @description 用于初始化资源
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
/*
|
|
|
|
|
需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。
|
|
|
|
|
final类不能被继承,没有子类,final类中的方法默认是final的。
|
|
|
|
|
final方法不能被子类的方法覆盖,但可以被继承。
|
|
|
|
|
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
|
|
|
|
|
final不能用于修饰构造方法。
|
|
|
|
|
*/
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
// 调用父类的onCreate函数
|
|
|
|
|
setContentView(R.layout.note_list);
|
|
|
|
|
//绑定视图
|
|
|
|
|
initResources();
|
|
|
|
|
|
|
|
|
|
//调用初始化函数进行初始化 包括数据和视图的关联
|
|
|
|
|
/**
|
|
|
|
|
* Insert an introduction when user firstly use this application
|
|
|
|
|
*/
|
|
|
|
|
setAppInfoFromRawRes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onActivityResult
|
|
|
|
|
* @description 返回一些子模块完成的数据交给主Activity处理
|
|
|
|
|
*/
|
|
|
|
|
@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);
|
|
|
|
|
// 调用 Activity 的onActivityResult()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method setAppInfoFromRawRes
|
|
|
|
|
* @description 用于从应用的原始资源文件中读取介绍内容,并将其保存为一个便签。
|
|
|
|
|
*/
|
|
|
|
|
private void setAppInfoFromRawRes() {
|
|
|
|
|
// Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。
|
|
|
|
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
|
|
|
|
if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
InputStream in = null;
|
|
|
|
|
try {
|
|
|
|
|
in = getResources().openRawResource(R.raw.introduction);
|
|
|
|
|
// 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后,
|
|
|
|
|
// 以openRawResource方法(不带后缀的资源文件名)打开这个文件。
|
|
|
|
|
in = getResources().openRawResource(R.raw.introduction);
|
|
|
|
|
if (in != null) {
|
|
|
|
|
InputStreamReader isr = new InputStreamReader(in);
|
|
|
|
|
BufferedReader br = new BufferedReader(isr);
|
|
|
|
|
char [] buf = new char[1024];
|
|
|
|
|
char [] buf = new char[1024]; // 自行定义的数值,使用者不知道有什么意义
|
|
|
|
|
int len = 0;
|
|
|
|
|
while ((len = br.read(buf)) > 0) {
|
|
|
|
|
sb.append(buf, 0, len);
|
|
|
|
@ -180,7 +220,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
return;
|
|
|
|
|
} finally {
|
|
|
|
|
if(in != null) {
|
|
|
|
|
if (in != null) {
|
|
|
|
|
try {
|
|
|
|
|
in.close();
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
@ -190,11 +230,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建空的WorkingNote
|
|
|
|
|
WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER,
|
|
|
|
|
AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE,
|
|
|
|
|
ResourceParser.RED);
|
|
|
|
|
note.setWorkingText(sb.toString());
|
|
|
|
|
if (note.saveNote()) {
|
|
|
|
|
// 更新保存note的信息
|
|
|
|
|
sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit();
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Save introduction note error");
|
|
|
|
@ -203,17 +245,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onStart
|
|
|
|
|
* @description 启动时执行异步查询操作,以获取数据并在 UI 中显示结果。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
protected void onStart() {
|
|
|
|
|
super.onStart();
|
|
|
|
|
//调用父类的 onStart() 方法
|
|
|
|
|
startAsyncNotesListQuery();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method initResources
|
|
|
|
|
* @description 进行资源的初始化
|
|
|
|
|
*/
|
|
|
|
|
private void initResources() {
|
|
|
|
|
mContentResolver = this.getContentResolver();
|
|
|
|
|
// 获取应用程序的数据,得到类似数据表的东西
|
|
|
|
|
mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
|
|
|
|
|
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
|
|
|
|
|
|
|
|
|
// findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名
|
|
|
|
|
mNotesListView = (ListView) findViewById(R.id.notes_list);
|
|
|
|
|
// 绑定XML中的ListView,作为Item的容器
|
|
|
|
|
mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null),
|
|
|
|
|
null, false);
|
|
|
|
|
mNotesListView.setOnItemClickListener(new OnListItemClickListener());
|
|
|
|
@ -221,6 +276,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mNotesListAdapter = new NotesListAdapter(this);
|
|
|
|
|
mNotesListView.setAdapter(mNotesListAdapter);
|
|
|
|
|
mAddNewNote = (Button) findViewById(R.id.btn_new_note);
|
|
|
|
|
// 在activity中要获取该按钮
|
|
|
|
|
mAddNewNote.setOnClickListener(this);
|
|
|
|
|
mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
|
|
|
|
|
mDispatch = false;
|
|
|
|
@ -231,6 +287,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mModeCallBack = new ModeCallback();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener
|
|
|
|
|
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
|
|
|
|
|
private DropdownMenu mDropDownMenu;
|
|
|
|
|
private ActionMode mActionMode;
|
|
|
|
@ -269,14 +326,22 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method updateMenu
|
|
|
|
|
* @description 新下拉菜单的内容。
|
|
|
|
|
* 根据已选择的项目数量和选择状态更新下拉菜单的标题和菜单项。它用于在用户选择项目时动态更新菜单的显示内容。
|
|
|
|
|
*/
|
|
|
|
|
private void updateMenu() {
|
|
|
|
|
int selectedCount = mNotesListAdapter.getSelectedCount();
|
|
|
|
|
//取已选择的项目数量。
|
|
|
|
|
// Update dropdown menu
|
|
|
|
|
String format = getResources().getString(R.string.menu_select_title, selectedCount);
|
|
|
|
|
mDropDownMenu.setTitle(format);
|
|
|
|
|
//获取一个格式化的字符串,其中包含已选择的项目数量。然后,将该字符串设置为下拉菜单的标题
|
|
|
|
|
mDropDownMenu.setTitle(format); // 更改标题
|
|
|
|
|
MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
|
|
|
|
|
if (item != null) {
|
|
|
|
|
if (mNotesListAdapter.isAllSelected()) {
|
|
|
|
|
//检查是否所有项目都被选择。
|
|
|
|
|
item.setChecked(true);
|
|
|
|
|
item.setTitle(R.string.menu_deselect_all);
|
|
|
|
|
} else {
|
|
|
|
@ -285,40 +350,73 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onPrepareActionMode
|
|
|
|
|
* @description 进入操作模式时对菜单进行特定的修改或更新
|
|
|
|
|
* @return 方法直接返回 false,表示不需要进行任何额外的操作或更新。
|
|
|
|
|
*/
|
|
|
|
|
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onActionItemClicked
|
|
|
|
|
* @description 并用于处理操作模式菜单项的点击事件。
|
|
|
|
|
* @param mode 和 item 其中,mode 表示当前的操作模式对象,而 item 表示被点击的菜单项对象。
|
|
|
|
|
* @return 直接返回 false 表示菜单项的点击事件未被处理。 返回 true 表示已经处理了相应的菜单项点击事件。
|
|
|
|
|
*/
|
|
|
|
|
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onDestroyActionMode
|
|
|
|
|
* @description 它实现了 ActionMode.Callback 接口中的方法,并用于销毁操作模式。
|
|
|
|
|
*/
|
|
|
|
|
public void onDestroyActionMode(ActionMode mode) {
|
|
|
|
|
mNotesListAdapter.setChoiceMode(false);
|
|
|
|
|
//取消列表的选择模式。
|
|
|
|
|
mNotesListView.setLongClickable(true);
|
|
|
|
|
//重新启用列表项的长按事件。
|
|
|
|
|
mAddNewNote.setVisibility(View.VISIBLE);
|
|
|
|
|
//将新建笔记按钮设置为可见状态。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//用于结束当前的操作模式。
|
|
|
|
|
public void finishActionMode() {
|
|
|
|
|
mActionMode.finish();
|
|
|
|
|
//在调用 finish() 方法之前,需要确保当前存在一个有效的操作模式对象 mActionMode。
|
|
|
|
|
// 如果当前不存在任何操作模式对象,则调用 finish() 方法将抛出异常。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onItemCheckedStateChanged
|
|
|
|
|
* @description 它实现了 ActionMode.Callback 接口中的方法,并用于处理列表项的选中状态变化事件。
|
|
|
|
|
* @param mode 表示当前的操作模式对象,position 表示列表项的位置,id 表示列表项的唯一标识符,checked 表示列表项的选中状态。
|
|
|
|
|
*/
|
|
|
|
|
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
|
|
|
|
boolean checked) {
|
|
|
|
|
mNotesListAdapter.setCheckedItem(position, checked);
|
|
|
|
|
//将列表项的选中状态传递给列表适配器,在适配器中更新相应的数据。
|
|
|
|
|
updateMenu();
|
|
|
|
|
//根据当前选中的列表项的数量,更新操作模式的菜单项。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onMenuItemClick
|
|
|
|
|
* @description 它实现了 MenuItem.OnMenuItemClickListener 接口中的方法,并用于处理操作模式菜单项的单击事件。
|
|
|
|
|
* @param *方法接收一个参数 item,表示被单击的菜单项。
|
|
|
|
|
*/
|
|
|
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
|
|
|
if (mNotesListAdapter.getSelectedCount() == 0) {
|
|
|
|
|
Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none),
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根据被单击的菜单项 ID,执行不同的操作。
|
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
|
if (itemId == R.id.delete) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
|
|
|
@ -339,11 +437,17 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
startQueryDestinationFolders();
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
//如果被单击的菜单项不是删除或移动菜单项,则返回 false
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
//如果成功处理了菜单项,则返回 true。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method
|
|
|
|
|
* @description 实现了OnTouchListener接口。主要功能是处理触摸。
|
|
|
|
|
*/
|
|
|
|
|
private class NewNoteOnTouchListener implements OnTouchListener {
|
|
|
|
|
|
|
|
|
|
public boolean onTouch(View v, MotionEvent event) {
|
|
|
|
@ -354,6 +458,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
int newNoteViewHeight = mAddNewNote.getHeight();
|
|
|
|
|
int start = screenHeight - newNoteViewHeight;
|
|
|
|
|
int eventY = start + (int) event.getY();
|
|
|
|
|
//首先获取屏幕高度和新笔记视图的高度,并计算出起始位置。如果当前状态是子文件夹状态,则还需减去标题栏的高度。
|
|
|
|
|
/**
|
|
|
|
|
* Minus TitleBar's height
|
|
|
|
|
*/
|
|
|
|
@ -371,6 +476,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
* also change. This is very bad, just for the UI designer's strong requirement.
|
|
|
|
|
*/
|
|
|
|
|
if (event.getY() < (event.getX() * (-0.12) + 94)) {
|
|
|
|
|
//通过判断触摸点的坐标是否在"New Note"按钮的透明部分上方,来决定是否将事件转发给位于按钮后面的列表视图。
|
|
|
|
|
View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1
|
|
|
|
|
- mNotesListView.getFooterViewsCount());
|
|
|
|
|
if (view != null && view.getBottom() > start
|
|
|
|
@ -389,6 +495,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mDispatchY += (int) event.getY() - mOriginY;
|
|
|
|
|
event.setLocation(event.getX(), mDispatchY);
|
|
|
|
|
return mNotesListView.dispatchTouchEvent(event);
|
|
|
|
|
//当动作为ACTION_MOVE(移动)时,如果之前已经开始转发事件,则更新转发的Y坐标,并将事件重新定位后转发给列表视图。
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -397,6 +504,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
event.setLocation(event.getX(), mDispatchY);
|
|
|
|
|
mDispatch = false;
|
|
|
|
|
return mNotesListView.dispatchTouchEvent(event);
|
|
|
|
|
//如果没有进行事件转发,则返回false,表示本类未处理该事件。
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -406,13 +514,24 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method startAsyncNotesListQuery
|
|
|
|
|
* @description 它通过异步查询数据库,获取指定文件夹下的笔记列表,并将结果显示在UI上。
|
|
|
|
|
* @param
|
|
|
|
|
* *FOLDER_NOTE_LIST_QUERY_TOKEN是一个常量值,用于标识该次查询(可以理解为查询ID)。
|
|
|
|
|
* 第二个参数为null,表示不需要传递额外的数据。
|
|
|
|
|
* 第三个参数是查询的URI,即Notes.CONTENT_NOTE_URI,表示查询笔记内容的URI。
|
|
|
|
|
* 第四个参数是查询需要返回的列名数组(NoteItemData.PROJECTION),用于指定查询结果中需要包含哪些列。
|
|
|
|
|
* 第五个参数是selection,表示查询时要使用的筛选条件。
|
|
|
|
|
* 最后一个参数是一个字符串数组,表示用于替换查询语句中占位符的值。
|
|
|
|
|
*/
|
|
|
|
|
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");
|
|
|
|
|
}, NoteColumns.TOP+" DESC,"+NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private final class BackgroundQueryHandler extends AsyncQueryHandler {
|
|
|
|
@ -420,17 +539,27 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
super(contentResolver);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onQueryComplete
|
|
|
|
|
* @description 用于处理异步查询完成后的回调。
|
|
|
|
|
* @param token 参数来判断当前是哪个查询完成了。根据不同的查询标识(token),执行相应的操作。
|
|
|
|
|
*/
|
|
|
|
|
@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);
|
|
|
|
|
//调用showFolderListMenu(cursor)方法,显示文件夹列表菜单。
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Query folder failed");
|
|
|
|
|
//在日志中记录查询文件夹失败的错误信息。
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
@ -439,32 +568,48 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method showFolderListMenu
|
|
|
|
|
* @description 用于显示文件夹列表菜单。
|
|
|
|
|
*/
|
|
|
|
|
private void showFolderListMenu(Cursor cursor) {
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
|
|
|
|
|
builder.setTitle(R.string.menu_title_select_folder);
|
|
|
|
|
final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor);
|
|
|
|
|
builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
|
|
|
|
|
|
|
|
|
|
//设置对话框的列表项和点击事件监听器。
|
|
|
|
|
//将适配器设置为对话框的列表项,并在点击列表项时执行相应的操作。
|
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
|
DataUtils.batchMoveToFolder(mContentResolver,
|
|
|
|
|
mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which));
|
|
|
|
|
Toast.makeText(
|
|
|
|
|
//显示一条消息,内容为移动的笔记数量和所选文件夹的名称。
|
|
|
|
|
NotesListActivity.this,
|
|
|
|
|
getString(R.string.format_move_notes_to_folder,
|
|
|
|
|
mNotesListAdapter.getSelectedCount(),
|
|
|
|
|
adapter.getFolderName(NotesListActivity.this, which)),
|
|
|
|
|
Toast.LENGTH_SHORT).show();
|
|
|
|
|
mModeCallBack.finishActionMode();
|
|
|
|
|
//结束动作模式(Action Mode),即退出多选模式。
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
builder.show();
|
|
|
|
|
//显示文件夹列表菜单对话框
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method createNewNote
|
|
|
|
|
* @description 用于创建新的笔记
|
|
|
|
|
* @param * intent 来启动一个名为NoteEditActivity的活动,
|
|
|
|
|
* ACTION_INSERT_OR_EDIT表示要执行插入或编辑操作
|
|
|
|
|
* Notes.INTENT_EXTRA_FOLDER_ID则是传递当前文件夹的ID
|
|
|
|
|
*/
|
|
|
|
|
private void createNewNote() {
|
|
|
|
|
Intent intent = new Intent(this, NoteEditActivity.class);
|
|
|
|
|
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
|
|
|
|
|
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId);
|
|
|
|
|
this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE);
|
|
|
|
|
//通过startActivityForResult方法启动活动,并传递了一个请求码(REQUEST_CODE_NEW_NOTE),以便在活动返回结果时进行区分。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void batchDelete() {
|
|
|
|
@ -504,20 +649,28 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}.execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method deleteFolder
|
|
|
|
|
* @description 避免意外情况下删除根文件夹
|
|
|
|
|
* @date: 2024-01-09 14:54
|
|
|
|
|
* @author: 作者名
|
|
|
|
|
* @param folderId,表示要删除的文件夹的ID
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void deleteFolder(long folderId) {
|
|
|
|
|
if (folderId == Notes.ID_ROOT_FOLDER) {
|
|
|
|
|
Log.e(TAG, "Wrong folder id, should not happen " + folderId);
|
|
|
|
|
return;
|
|
|
|
|
//在方法内部,首先通过条件判断检查folderId是否等于Notes.ID_ROOT_FOLDER(根文件夹的ID)。
|
|
|
|
|
// 如果是根文件夹的ID,则记录错误日志并返回,不执行删除操作。
|
|
|
|
|
}
|
|
|
|
|
//该方法接收一个参数folderId,表示要删除的文件夹的ID。
|
|
|
|
|
//
|
|
|
|
|
//在方法内部,首先通过条件判断检查folderId是否等于Notes.ID_ROOT_FOLDER(根文件夹的ID)。如果是根文件夹的ID,则记录错误日志并返回,不执行删除操作。
|
|
|
|
|
//
|
|
|
|
|
//这段代码的作用是避免意外情况下删除根文件夹,因为根文件夹通常是系统的关键文件夹,不应该被删除。如果传入的folderId等于根文件夹的ID,会输出错误日志并直接返回,避免继续执行删除根文件夹的操作。
|
|
|
|
|
|
|
|
|
|
HashSet<Long> ids = new HashSet<Long>();
|
|
|
|
|
ids.add(folderId);
|
|
|
|
|
//创建一个HashSet<Long>对象,并将folderId添加到该集合中
|
|
|
|
|
HashSet<AppWidgetAttribute> widgets = DataUtils.getFolderNoteWidget(mContentResolver,
|
|
|
|
|
folderId);
|
|
|
|
|
//调用DataUtils.getFolderNoteWidget()方法获取与该文件夹相关联的小部件。将结果保存在widgets变量中。
|
|
|
|
|
if (!isSyncMode()) {
|
|
|
|
|
// if not synced, delete folder directly
|
|
|
|
|
DataUtils.batchDeleteNotes(mContentResolver, ids);
|
|
|
|
@ -530,11 +683,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
|
|
|
|
|
&& widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
|
|
|
|
|
updateWidget(widget.widgetId, widget.widgetType);
|
|
|
|
|
//遍历widgets集合中的每个小部件,并根据小部件的ID和类型调用updateWidget()方法进行小部件的更新操作。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method openNode
|
|
|
|
|
* @description 用于打开笔记。
|
|
|
|
|
*/
|
|
|
|
|
private void openNode(NoteItemData data) {
|
|
|
|
|
Intent intent = new Intent(this, NoteEditActivity.class);
|
|
|
|
|
intent.setAction(Intent.ACTION_VIEW);
|
|
|
|
@ -542,44 +700,45 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method openFolder
|
|
|
|
|
* @description 打开指定的文件夹
|
|
|
|
|
* @param data,表示要打开的文件夹
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void openFolder(NoteItemData data) {
|
|
|
|
|
mCurrentFolderId = data.getId();
|
|
|
|
|
//将当前文件夹的ID设置为参数data的ID,并调用startAsyncNotesListQuery()方法开始异步查询当前文件夹下的笔记列表。
|
|
|
|
|
startAsyncNotesListQuery();
|
|
|
|
|
//根据文件夹的ID判断当前状态:
|
|
|
|
|
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
|
|
|
|
|
mState = ListEditState.CALL_RECORD_FOLDER;
|
|
|
|
|
mAddNewNote.setVisibility(View.GONE);
|
|
|
|
|
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则将状态设置为ListEditState.CALL_RECORD_FOLDER,并隐藏添加新笔记按钮;
|
|
|
|
|
} else {
|
|
|
|
|
mState = ListEditState.SUB_FOLDER;
|
|
|
|
|
//将状态设置为ListEditState.SUB_FOLDER。
|
|
|
|
|
}
|
|
|
|
|
//根据文件夹的ID设置标题栏的文本:
|
|
|
|
|
if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
|
|
|
|
|
mTitleBar.setText(R.string.call_record_folder_name);
|
|
|
|
|
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则设置标题栏的文本为字符串资源R.string.call_record_folder_name;
|
|
|
|
|
} else {
|
|
|
|
|
mTitleBar.setText(data.getSnippet());
|
|
|
|
|
//否则,设置标题栏的文本为文件夹的名称(通过调用data.getSnippet()方法获取)。
|
|
|
|
|
}
|
|
|
|
|
mTitleBar.setVisibility(View.VISIBLE);
|
|
|
|
|
//将标题栏设置为可见状态。
|
|
|
|
|
}
|
|
|
|
|
//该方法接收一个参数data,表示要打开的文件夹。
|
|
|
|
|
//
|
|
|
|
|
//首先,将当前文件夹的ID设置为参数data的ID,并调用startAsyncNotesListQuery()方法开始异步查询当前文件夹下的笔记列表。
|
|
|
|
|
//
|
|
|
|
|
//接下来,根据文件夹的ID判断当前状态:
|
|
|
|
|
//
|
|
|
|
|
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则将状态设置为ListEditState.CALL_RECORD_FOLDER,并隐藏添加新笔记按钮;
|
|
|
|
|
//否则,将状态设置为ListEditState.SUB_FOLDER。
|
|
|
|
|
//然后,根据文件夹的ID设置标题栏的文本:
|
|
|
|
|
//
|
|
|
|
|
//如果文件夹的ID为Notes.ID_CALL_RECORD_FOLDER,则设置标题栏的文本为字符串资源R.string.call_record_folder_name;
|
|
|
|
|
//否则,设置标题栏的文本为文件夹的名称(通过调用data.getSnippet()方法获取)。
|
|
|
|
|
//最后,将标题栏设置为可见状态。
|
|
|
|
|
//
|
|
|
|
|
//总之,这段代码实现了打开文件夹的功能,根据文件夹的ID设置不同的状态和标题,并更新UI显示。
|
|
|
|
|
|
|
|
|
|
//当按钮控件的 id 为 btn_new_note 的按钮被点击时,该方法会调用 createNewNote() 方法。
|
|
|
|
|
public void onClick(View v) {
|
|
|
|
|
if (v.getId() == R.id.btn_new_note) {
|
|
|
|
|
createNewNote();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//显示软键盘
|
|
|
|
|
private void showSoftInput() {
|
|
|
|
|
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
if (inputMethodManager != null) {
|
|
|
|
@ -587,19 +746,30 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//隐藏软键盘
|
|
|
|
|
private void hideSoftInput(View view) {
|
|
|
|
|
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
|
|
|
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method showCreateOrModifyFolderDialog
|
|
|
|
|
* @description 用于创建或者是修改文件夹
|
|
|
|
|
* @param *接收一个参数create,用于指示是创建文件夹还是修改文件夹。
|
|
|
|
|
*/
|
|
|
|
|
private void showCreateOrModifyFolderDialog(final boolean create) {
|
|
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
|
|
|
|
|
//在方法内部,首先创建一个AlertDialog.Builder对象,并通过LayoutInflater从XML布局文件中实例化一个视图。
|
|
|
|
|
final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
|
|
|
|
|
showSoftInput();
|
|
|
|
|
//获取EditText对象用于输入文件夹名称,并调用showSoftInput()方法显示软键盘。
|
|
|
|
|
|
|
|
|
|
//根据create参数的值,判断是创建文件夹还是修改文件夹。如果是修改文件夹,
|
|
|
|
|
if (!create) {
|
|
|
|
|
if (mFocusNoteDataItem != null) {
|
|
|
|
|
etName.setText(mFocusNoteDataItem.getSnippet());
|
|
|
|
|
// 从mFocusNoteDataItem中获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
|
|
|
|
|
builder.setTitle(getString(R.string.menu_folder_change_name));
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "The long click data item is null");
|
|
|
|
@ -608,6 +778,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
} else {
|
|
|
|
|
etName.setText("");
|
|
|
|
|
builder.setTitle(this.getString(R.string.menu_create_folder));
|
|
|
|
|
// 如果是创建文件夹,则将EditText的文本设置为空,并设置对话框的标题为创建文件夹。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder.setPositiveButton(android.R.string.ok, null);
|
|
|
|
@ -676,23 +847,28 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
//该方法接收一个参数create,用于指示是创建文件夹还是修改文件夹。
|
|
|
|
|
//
|
|
|
|
|
//在方法内部,首先创建一个AlertDialog.Builder对象,并通过LayoutInflater从XML布局文件中实例化一个视图。
|
|
|
|
|
// 获取EditText对象用于输入文件夹名称,并调用showSoftInput()方法显示软键盘。
|
|
|
|
|
//
|
|
|
|
|
//根据create参数的值,判断是创建文件夹还是修改文件夹。如果是修改文件夹,
|
|
|
|
|
// 则从mFocusNoteDataItem中获取文件夹名称,并设置对话框的标题为对应的修改文件夹名称;
|
|
|
|
|
// 如果是创建文件夹,则将EditText的文本设置为空,并设置对话框的标题为创建文件夹。
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onBackPressed
|
|
|
|
|
* @description 用于处理用户按下返回按钮的操作
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onBackPressed() {
|
|
|
|
|
switch (mState) {
|
|
|
|
|
//通过switch语句检查当前的状态(mState)
|
|
|
|
|
case SUB_FOLDER:
|
|
|
|
|
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
|
|
|
|
mState = ListEditState.NOTE_LIST;
|
|
|
|
|
startAsyncNotesListQuery();
|
|
|
|
|
mTitleBar.setVisibility(View.GONE);
|
|
|
|
|
break;
|
|
|
|
|
/*
|
|
|
|
|
如果当前状态为SUB_FOLDER(子文件夹),
|
|
|
|
|
则将mCurrentFolderId设置为根文件夹的ID(Notes.ID_ROOT_FOLDER),
|
|
|
|
|
将状态设置为笔记列表状态(ListEditState.NOTE_LIST),
|
|
|
|
|
并调用startAsyncNotesListQuery()方法开始异步查询笔记列表。
|
|
|
|
|
同时,隐藏标题栏(mTitleBar.setVisibility(View.GONE))
|
|
|
|
|
*/
|
|
|
|
|
case CALL_RECORD_FOLDER:
|
|
|
|
|
mCurrentFolderId = Notes.ID_ROOT_FOLDER;
|
|
|
|
|
mState = ListEditState.NOTE_LIST;
|
|
|
|
@ -700,27 +876,42 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
mTitleBar.setVisibility(View.GONE);
|
|
|
|
|
startAsyncNotesListQuery();
|
|
|
|
|
break;
|
|
|
|
|
/*
|
|
|
|
|
如果当前状态为CALL_RECORD_FOLDER(通话记录文件夹),
|
|
|
|
|
则同样将mCurrentFolderId设置为根文件夹的ID,
|
|
|
|
|
将状态设置为笔记列表状态,显示添加新笔记按钮(mAddNewNote.setVisibility(View.VISIBLE)),
|
|
|
|
|
隐藏标题栏,并调用startAsyncNotesListQuery()方法开始异步查询笔记列表。
|
|
|
|
|
*/
|
|
|
|
|
case NOTE_LIST:
|
|
|
|
|
super.onBackPressed();
|
|
|
|
|
//调用父类的onBackPressed()方法,执行默认的返回操作。
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method updateWidget
|
|
|
|
|
* @description 用于更新小部件(widget)
|
|
|
|
|
*/
|
|
|
|
|
private void updateWidget(int appWidgetId, int appWidgetType) {
|
|
|
|
|
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
|
|
|
|
//根据appWidgetType的不同值,设置不同的NoteWidgetProvider类作为接收广播的目标。
|
|
|
|
|
if (appWidgetType == Notes.TYPE_WIDGET_2X) {
|
|
|
|
|
intent.setClass(this, NoteWidgetProvider_2x.class);
|
|
|
|
|
//设置NoteWidgetProvider_2x类作为目标;
|
|
|
|
|
} else if (appWidgetType == Notes.TYPE_WIDGET_4X) {
|
|
|
|
|
intent.setClass(this, NoteWidgetProvider_4x.class);
|
|
|
|
|
//则设置NoteWidgetProvider_4x类作为目标。
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "Unspported widget type");
|
|
|
|
|
//不匹配任何已知的类型,则记录一个错误日志并返回
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
|
|
|
|
|
appWidgetId
|
|
|
|
|
appWidgetId//将appWidgetId作为额外参数放入意图中,并通过sendBroadcast方法发送广播。
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
sendBroadcast(intent);
|
|
|
|
@ -738,17 +929,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onContextMenuClosed
|
|
|
|
|
* @description 在上下文菜单关闭时调用的方法
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public void onContextMenuClosed(Menu menu) {
|
|
|
|
|
if (mNotesListView != null) {
|
|
|
|
|
mNotesListView.setOnCreateContextMenuListener(null);
|
|
|
|
|
//然后通过调用 setOnCreateContextMenuListener(null) 方法将上下文菜单的创建监听器设置为 null,即移除了上下文菜单的创建监听器。
|
|
|
|
|
}
|
|
|
|
|
super.onContextMenuClosed(menu);
|
|
|
|
|
//调用 super.onContextMenuClosed(menu) 方法来执行父类的相应操作。
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onContextItemSelected
|
|
|
|
|
* @description 用于处理上下文菜单项的选择操作
|
|
|
|
|
* @return 返回true表示操作已经成功处理 如果为空,则记录错误日志并返回false
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onContextItemSelected(MenuItem item) {
|
|
|
|
|
if (mFocusNoteDataItem == null) {
|
|
|
|
|
//通过检查mFocusNoteDataItem是否为空来确保当前长按操作的数据项不为空
|
|
|
|
|
Log.e(TAG, "The long click data item is null");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@ -756,6 +959,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
case MENU_FOLDER_VIEW:
|
|
|
|
|
openFolder(mFocusNoteDataItem);
|
|
|
|
|
break;
|
|
|
|
|
//如果用户选择了“查看文件夹”菜单项,则调用openFolder()方法打开该文件夹。
|
|
|
|
|
case MENU_FOLDER_DELETE:
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
|
|
|
builder.setTitle(getString(R.string.alert_title_delete));
|
|
|
|
@ -770,9 +974,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
builder.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
builder.show();
|
|
|
|
|
break;
|
|
|
|
|
//如果用户选择了“删除文件夹”菜单项,则弹出一个提示对话框,
|
|
|
|
|
// 并在用户确认删除操作后调用deleteFolder()方法执行相应的数据库操作。
|
|
|
|
|
case MENU_FOLDER_CHANGE_NAME:
|
|
|
|
|
showCreateOrModifyFolderDialog(false);
|
|
|
|
|
break;
|
|
|
|
|
//如果用户选择了“重命名文件夹”菜单项,则调用showCreateOrModifyFolderDialog()方法显示创建或修改文件夹的对话框。
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -780,9 +987,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onPrepareOptionsMenu
|
|
|
|
|
* @description 用于在菜单准备显示时进行处理的。
|
|
|
|
|
* 它会根据当前的状态(mState)来加载不同的菜单布局,并设置相应的标题。
|
|
|
|
|
* @return 方法返回true,表示菜单已经被处理完毕。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
|
|
|
menu.clear();
|
|
|
|
|
//通过调用menu.clear()方法清除菜单中的所有项。
|
|
|
|
|
|
|
|
|
|
//根据mState的不同值,使用getMenuInflater().inflate()方法加载对应的菜单布局文件。
|
|
|
|
|
if (mState == ListEditState.NOTE_LIST) {
|
|
|
|
|
getMenuInflater().inflate(R.menu.note_list, menu);
|
|
|
|
|
// set sync or sync_cancel
|
|
|
|
@ -798,9 +1014,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onOptionsItemSelected
|
|
|
|
|
* @description 每当用户选择菜单项时,Android 系统会调用该方法,并传入被选中的菜单项(MenuItem)。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
|
|
|
|
int itemId = item.getItemId();
|
|
|
|
|
//该方法首先获取被选中菜单项的ID,然后根据不同的ID执行相应的操作。
|
|
|
|
|
if (itemId == R.id.menu_new_folder) {
|
|
|
|
|
showCreateOrModifyFolderDialog(true);
|
|
|
|
|
} else if (itemId == R.id.menu_export_text) {
|
|
|
|
@ -823,32 +1044,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
onSearchRequested();
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
/*
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_new_folder,则调用showCreateOrModifyFolderDialog(true)方法,显示创建或修改文件夹的对话框。
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_export_text,则调用exportNoteToText()方法,将笔记导出为文本。
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_sync,则根据当前是否处于同步模式(isSyncMode())分别启动或取消同步服务(GTaskSyncService)或打开设置活动(startPreferenceActivity)。
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_setting,则打开设置活动(startPreferenceActivity)。
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_new_note,则创建新的笔记(createNewNote)。
|
|
|
|
|
* 如果选中的菜单项是R.id.menu_search,则执行搜索请求(onSearchRequested)。
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
//每当用户选择菜单项时,Android 系统会调用该方法,并传入被选中的菜单项(MenuItem)。该方法首先获取被选中菜单项的ID,然后根据不同的ID执行相应的操作。
|
|
|
|
|
//
|
|
|
|
|
//具体来说:
|
|
|
|
|
//
|
|
|
|
|
//如果选中的菜单项是R.id.menu_new_folder,则调用showCreateOrModifyFolderDialog(true)方法,显示创建或修改文件夹的对话框。
|
|
|
|
|
//如果选中的菜单项是R.id.menu_export_text,则调用exportNoteToText()方法,将笔记导出为文本。
|
|
|
|
|
//如果选中的菜单项是R.id.menu_sync,则根据当前是否处于同步模式(isSyncMode())分别启动或取消同步服务(GTaskSyncService)或打开设置活动(startPreferenceActivity)。
|
|
|
|
|
//如果选中的菜单项是R.id.menu_setting,则打开设置活动(startPreferenceActivity)。
|
|
|
|
|
//如果选中的菜单项是R.id.menu_new_note,则创建新的笔记(createNewNote)。
|
|
|
|
|
//如果选中的菜单项是R.id.menu_search,则执行搜索请求(onSearchRequested)。
|
|
|
|
|
//最后,该方法返回true,表示菜单项的选择事件已经得到处理。
|
|
|
|
|
//
|
|
|
|
|
//总之,该方法根据用户选择的菜单项执行不同的操作,包括创建新文件夹、导出笔记、同步服务控制、打开设置活动、创建新笔记和执行搜索请求等。
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onSearchRequested
|
|
|
|
|
* @description nSearchRequested方法是一个覆盖方法,用于在用户点击搜索按钮或者执行搜索手势时被调用。
|
|
|
|
|
* @param *搜索关键字(null表示没有指定关键字),
|
|
|
|
|
* 是否全局搜索(false表示只搜索当前应用程序),
|
|
|
|
|
* 应用程序数据(null表示没有额外的应用程序数据),
|
|
|
|
|
* 以及是否由用户触发的搜索(false表示不是由用户触发)。
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onSearchRequested() {
|
|
|
|
|
startSearch(null, false, null /* appData */, false);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
//nSearchRequested方法是一个覆盖方法,用于在用户点击搜索按钮或者执行搜索手势时被调用。
|
|
|
|
|
//
|
|
|
|
|
//在这段代码中,首先调用了startSearch方法来启动搜索功能。startSearch方法接受四个参数:搜索关键字(null表示没有指定关键字),是否全局搜索(false表示只搜索当前应用程序),应用程序数据(null表示没有额外的应用程序数据),以及是否由用户触发的搜索(false表示不是由用户触发)。
|
|
|
|
|
//
|
|
|
|
|
//然后,返回值为true,表示该方法已经处理了搜索请求,并不需要其他的默认处理。
|
|
|
|
|
//
|
|
|
|
|
//总之,该代码片段实现了在搜索请求时调用startSearch方法,并返回true表示已经处理了该搜索请求。
|
|
|
|
|
private void exportNoteToText() {
|
|
|
|
|
final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
|
|
|
|
|
new AsyncTask<Void, Void, Integer>() {
|
|
|
|
@ -890,25 +1108,23 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
}.execute();
|
|
|
|
|
}
|
|
|
|
|
//首先,定义了一个名为exportNoteToText的私有方法,没有任何参数。
|
|
|
|
|
//
|
|
|
|
|
//在该方法中,首先通过BackupUtils.getInstance(NotesListActivity.this)获取一个备份工具类的实例。然后创建一个异步任务(AsyncTask)来执行导出操作。
|
|
|
|
|
//
|
|
|
|
|
//在异步任务的doInBackground方法中,调用backup.exportToText()方法来执行导出操作,并返回一个结果值。
|
|
|
|
|
//
|
|
|
|
|
//在异步任务的onPostExecute方法中,根据导出的结果值进行不同的处理:
|
|
|
|
|
//
|
|
|
|
|
//如果结果值等于BackupUtils.STATE_SD_CARD_UNMOUONTED,表示SD卡未挂载,弹出一个对话框提示导出失败和SD卡未挂载的错误信息。
|
|
|
|
|
//如果结果值等于BackupUtils.STATE_SUCCESS,表示导出成功,弹出一个对话框提示导出成功和导出文件的位置信息。
|
|
|
|
|
//如果结果值等于BackupUtils.STATE_SYSTEM_ERROR,表示导出失败,弹出一个对话框提示导出失败的错误信息。
|
|
|
|
|
//在最后,通过调用execute方法来执行异步任务。
|
|
|
|
|
|
|
|
|
|
//用于检查是否处于同步模式
|
|
|
|
|
private boolean isSyncMode() {
|
|
|
|
|
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method startPreferenceActivity
|
|
|
|
|
* @description 用于启动应用程序的“偏好设置”屏幕
|
|
|
|
|
* @param
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private void startPreferenceActivity() {
|
|
|
|
|
Activity from = getParent() != null ? getParent() : this;
|
|
|
|
|
//通过检查父活动是否存在来确定从哪个活动中启动偏好设置屏幕。
|
|
|
|
|
Intent intent = new Intent(from, NotesPreferenceActivity.class);
|
|
|
|
|
//创建一个新的意图(Intent)对象,并将其目标设置为NotesPreferenceActivity类。
|
|
|
|
|
from.startActivityIfNeeded(intent, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -953,6 +1169,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method startQueryDestinationFolders
|
|
|
|
|
* @description 用于开始查询目标文件夹列表。
|
|
|
|
|
* @param
|
|
|
|
|
* *FOLDER_LIST_QUERY_TOKEN:查询令牌,用于标识此次查询。
|
|
|
|
|
* null:附加到查询令牌的对象,这里为null。
|
|
|
|
|
* Notes.CONTENT_NOTE_URI:要查询的URI,表示笔记内容。
|
|
|
|
|
* FoldersListAdapter.PROJECTION:要返回的数据列数组。
|
|
|
|
|
* selection:查询的条件字符串。
|
|
|
|
|
* new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER), String.valueOf(mCurrentFolderId) }:查询条件中的参数值。
|
|
|
|
|
* NoteColumns.MODIFIED_DATE + " DESC":查询结果按照修改日期降序排列。
|
|
|
|
|
*/
|
|
|
|
|
private void startQueryDestinationFolders() {
|
|
|
|
|
String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?";
|
|
|
|
|
selection = (mState == ListEditState.NOTE_LIST) ? selection:
|
|
|
|
@ -971,20 +1199,31 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt
|
|
|
|
|
NoteColumns.MODIFIED_DATE + " DESC");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @method onItemLongClick
|
|
|
|
|
* @description 用于处理列表项的长按事件
|
|
|
|
|
* @return 返回false表示事件未被消耗,以便继续处理其他可能的事件。
|
|
|
|
|
*/
|
|
|
|
|
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
|
|
|
|
|
if (view instanceof NotesListItem) {
|
|
|
|
|
//通过检查view是否是NotesListItem的实例来确定长按的列表项类型。
|
|
|
|
|
mFocusNoteDataItem = ((NotesListItem) view).getItemData();
|
|
|
|
|
if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
|
|
|
|
|
if (mNotesListView.startActionMode(mModeCallBack) != null) {
|
|
|
|
|
mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
|
|
|
|
|
//调用mModeCallBack.onItemCheckedStateChanged()方法更新选择状态。
|
|
|
|
|
mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
|
|
|
|
//调用mNotesListView.performHapticFeedback()方法进行触觉反馈,表示长按操作已触发。
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "startActionMode fails");
|
|
|
|
|
}
|
|
|
|
|
} else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
|
|
|
|
|
mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener);
|
|
|
|
|
//如果数据项的类型为文件夹类型(Notes.TYPE_FOLDER),则设置列表视图的上下文菜单创建监听器(mFolderOnCreateContextMenuListener)。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
//返回false表示事件未被消耗,以便继续处理其他可能的事件。
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|