From 9f1064c71846632e864e3acd7b598cb72d261abc Mon Sep 17 00:00:00 2001 From: Joker21a <1095435669@qq.com> Date: Sun, 7 Jan 2024 11:28:40 +0800 Subject: [PATCH] 1.7 --- .../net/micode/notes/model/WorkingNote.java | 182 ++++- .../micode/notes/ui/NotesListActivity.java | 712 ++++++++++++++++-- 2 files changed, 819 insertions(+), 75 deletions(-) diff --git a/src/main/java/net/micode/notes/model/WorkingNote.java b/src/main/java/net/micode/notes/model/WorkingNote.java index be081e4..4fd3cf6 100644 --- a/src/main/java/net/micode/notes/model/WorkingNote.java +++ b/src/main/java/net/micode/notes/model/WorkingNote.java @@ -31,9 +31,26 @@ import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.TextNote; import net.micode.notes.tool.ResourceParser.NoteBgResources; - +/** + * + * @ProjectName: xiaomibianqian + * @Package: model + * @ClassName: WorkingNote + * @Description: 创建了一个正在工作的便签类,其中有大量的参数,包括参量类、布尔值类、区分类的变量 + * 另外,封装了一系列的函数,其中有返回私有变量的,与数据库进行操作的,在不同情况下操作的(如新建的便签与修改的便签) + * 主要交互的包、类:NoteEditActivities,Notes(from data)Note NoteListActivity SqlData + * 另外,有创建一些接口,比如NoteSettingChangedListener,在NoteEditActivities中具体实现 + * + * @Author: zhoushiyu_br + * @CreateDate: 2023.12.16 + * @UpdateUser: 更新者: + * @UpdateDate: 2023.12.21 + * @UpdateRemark: 更新说明: + * @Version: 这次更新主要是修改了之前代码批注不够规范的问题,结合上课毛教员对于问题的指出,对格式进行了优化——PickupRAIN + */ public class WorkingNote { // Note for the working note + //这个在Note里面定义了Note类的基本类型, private Note mNote; // Note Id private long mNoteId; @@ -43,26 +60,41 @@ public class WorkingNote { private int mMode; private long mAlertDate; + //最后的修改日期 private long mModifiedDate; + //定义的颜色的ID private int mBgColorId; + //定义了一个int类型,用来定位到哪一个小组件被使用 private int mWidgetId; + //定义了一个int类型,用来区分使用了什么类型的小组件 private int mWidgetType; + //用来定位便签放在哪个文件夹 private long mFolderId; private Context mContext; + //定义为静态变量,保证不能再被更改。防止数据出现异常 private static final String TAG = "WorkingNote"; + //定义一个布尔变量,用来保存是否要被删除。通过查看用法,发现在后面保存|修改的时候要进行判断。 private boolean mIsDeleted; - + //定义了一个接口,具体是在NoteEditActivities中实现,实现对于便签是否修改的监听 private NoteSettingChangedListener mNoteSettingStatusListener; - + /** + * 定义一个数组,保存DataColumn数组当中的一些列变量。关于DataColumn的注解我写在了定义处。 + * 之所以用一个字符串数组来调用DataColumn接口,是为了“方便在进行数据库操作时可以一次性指定需要查询的列”? + * 这个数组只有在loadNoteData这个函数的时候进行了调用。将数据加载到 + * 12.22更新,我学习了getContentResolver()的用法 + * 实际上,getContentResolver是用来查询数据库的,这里定义的Projection是所有属性的集合。数据库查询,按列进行 + * 在按列查询时,在数据库访问到底,只需要在数组中继续访问即可。关于函数详解我会写在函数的定义处; + */ public static final String[] DATA_PROJECTION = new String[] { + //在Note里面定义一个接口类型 DataColumns.ID, DataColumns.CONTENT, DataColumns.MIME_TYPE, @@ -71,7 +103,7 @@ public class WorkingNote { DataColumns.DATA3, DataColumns.DATA4, }; - +//这里的用法基本同上方,不过这些接口最后使用在数据库中 public static final String[] NOTE_PROJECTION = new String[] { NoteColumns.PARENT_ID, NoteColumns.ALERTED_DATE, @@ -80,7 +112,9 @@ public class WorkingNote { NoteColumns.WIDGET_TYPE, NoteColumns.MODIFIED_DATE }; - + /** + * 定义了一系列的基础值。 + */ private static final int DATA_ID_COLUMN = 0; private static final int DATA_CONTENT_COLUMN = 1; @@ -101,11 +135,21 @@ public class WorkingNote { private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - // New note construct + /** + * @method: WorkingNote + * @description: 初始化一个新的操作的Note + * @date: 2024/1/6 11:28 + * @author: 周石宇 + * @param: [android.content.Context, long]:[context, folderId] + * @return: + */ private WorkingNote(Context context, long folderId) { + + + mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); + mAlertDate = 0;//这里为什么是0还存疑 + mModifiedDate = System.currentTimeMillis();//获取系统时间,保存给最后修改时间 mFolderId = folderId; mNote = new Note(); mNoteId = 0; @@ -113,7 +157,8 @@ public class WorkingNote { mMode = 0; mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } - + //由于传入了noteId,所以是对一个已经存在的便签进行操作。 + //由于一些基本的已经定义,所以传入的变量很少。 // Existing note construct private WorkingNote(Context context, long noteId, long folderId) { mContext = context; @@ -124,11 +169,24 @@ public class WorkingNote { loadNote(); } + /** + * @author: zhoushiyu_PickupRAIN + * @methodsName: loadNote + * @description: 创建游标,对数据库进行操作。首先从传入的URI中找到数据库地址,对元素数组进行逐列筛选。 + * @param: 虽然没传入,,但是说明一下 + * ->Notes.CONTENT_NOTE_URI:数据库的地址,根据URI找到相应数据库 + * ->NOTE_PROJECTION :属性列表,包含了所有的表头 + * ->这里就能很容易理解为什么NOTE_PROJECTION为什么只在这里调用,也没有初始化。 + * @return: String + * @throws: Nopes + * + */ private void loadNote() { + //定义一个cursor游标,用来操作数据。这里传入了很多量,如URI、Id、和来自Projection的一系列。 Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, null, null); - + //设置一个cursor,按行提取各种信息,保存到对应的变量中 if (cursor != null) { if (cursor.moveToFirst()) { mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); @@ -145,22 +203,38 @@ public class WorkingNote { } loadNoteData(); } - + /** + * @method: loadNoteData + * @description: 基本同上一个函数。值得注意的是这里对数据进行了筛选(通过selection),还对MIME进行了判断后加载 + * @date: 2024/1/6 11:29 + * @author: 周石宇 + * @param: []:[] + * @return: void + */ private void loadNoteData() { - Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, + + + + Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { String.valueOf(mNoteId) }, null); if (cursor != null) { + // 检查是否有数据 if (cursor.moveToFirst()) { do { + // 获取类型 String type = cursor.getString(DATA_MIME_TYPE_COLUMN); if (DataConstants.NOTE.equals(type)) { + // 获取内容 mContent = cursor.getString(DATA_CONTENT_COLUMN); + // 获取模式 mMode = cursor.getInt(DATA_MODE_COLUMN); + // 获取ID mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); } else if (DataConstants.CALL_NOTE.equals(type)) { + // 设置通话ID mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); } else { Log.d(TAG, "Wrong note type with type:" + type); @@ -174,33 +248,61 @@ public class WorkingNote { } } - public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, + + /** + * @method: createEmptyNote + * @description: 创建一个空的笔记 + * @date: 2024/1/2 10:21 + * @author: 周石宇 + * @param: [android.content.Context, long, int, int, int]:[context, folderId, widgetId, widgetType, defaultBgColorId] + * @return: net.micode.notes.model.WorkingNote + */ +public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, + int widgetType, int defaultBgColorId) { + // 创建一个新的WorkingNote实例 WorkingNote note = new WorkingNote(context, folderId); + // 设置笔记的背景颜色 note.setBgColorId(defaultBgColorId); + // 设置笔记的widgetId note.setWidgetId(widgetId); + // 设置笔记的widgetType note.setWidgetType(widgetType); + // 返回新的WorkingNote实例 return note; } public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } - - public synchronized boolean saveNote() { + /** + * @method: saveNote + * @description: 保存笔记 + * @date: 2024/1/2 10:23 + * @author: 周石宇 + * @param: []:[] + * @return: boolean + */ +public synchronized boolean saveNote() { + + // 如果笔记 worth saving if (isWorthSaving()) { + // 如果笔记不存在数据库中 if (!existInDatabase()) { + // 获取新笔记id if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { Log.e(TAG, "Create new note fail with id:" + mNoteId); return false; } } +//由于没有这个便签,所以报错,并返回false - mNote.syncNote(mContext, mNoteId); + mNote.syncNote(mContext, mNoteId);//这一行是同步信息的操作 /** * Update widget content if there exist any widget of this note */ + //对小组件的各种属性进行判断,来确定是否有组件,进行保存 if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { @@ -212,11 +314,26 @@ public class WorkingNote { } } + /** + * 以下定义、封装了一系列的实用函数,用于一些私有量的设置与判断 + * + */ public boolean existInDatabase() { return mNoteId > 0; } + /** + * @method: isWorthSaving + * @description: 判断是否值得保存,即判断是否需要保存到数据库 + * @date: 2024/1/2 10:24 + * @author: 周石宇 + * @param: []:[] + * @return: boolean + */ private boolean isWorthSaving() { + + + if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { return false; @@ -224,8 +341,19 @@ public class WorkingNote { return true; } } + /** + * @method: setOnSettingStatusChangedListener + * @description: 用来记录状态设定是否有发生过更改。 + * @date: 2024/1/2 10:24 + * @author: 周石宇 + * @param: [net.micode.notes.model.WorkingNote.NoteSettingChangedListener]:[l] + * @return: void + */ public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { + + + mNoteSettingStatusListener = l; } @@ -256,8 +384,18 @@ public class WorkingNote { mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); } } - + /** + * @method: setCheckListMode + * @description: 在EditActivities中使用,用来设定在list时的状态 + * @date: 2024/1/6 11:30 + * @author: 周石宇 + * @param: [int]:[mode] + * @return: void + */ public void setCheckListMode(int mode) { + + + if (mMode != mode) { if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); @@ -288,6 +426,14 @@ public class WorkingNote { } } + /** + * 从这里一直向上大概的都是一些设置状态的函数。 + * 原因是设置的私有量,保证数据的可靠性 + * 具体使用在onOptionsItemSelected NoteEditActivities类,中调用 + */ + + + //这里的callNote我没有搞懂 public void convertToCallNote(String phoneNumber, long callDate) { mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); @@ -341,7 +487,7 @@ public class WorkingNote { public int getWidgetType() { return mWidgetType; } - +//声明了一个接口,具体都在EditActivies中进行实现。主要是一个监听(listener),来设置各个量的改变 public interface NoteSettingChangedListener { /** * Called when the background color of current note has just changed diff --git a/src/main/java/net/micode/notes/ui/NotesListActivity.java b/src/main/java/net/micode/notes/ui/NotesListActivity.java index 6db3761..9789ffb 100644 --- a/src/main/java/net/micode/notes/ui/NotesListActivity.java +++ b/src/main/java/net/micode/notes/ui/NotesListActivity.java @@ -77,8 +77,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; - +/** + * @class: NotesListActivity + * @extends: Activity + * @implements: OnClickListener, OnItemLongClickListener + * @description: 主要实现小米便签刚进入界面。该类为一种main Activity,(xml中有定义)覆盖点击事件监听及长按事件监听类。。 + * @author: 王毅 + * @date: 2024/1/5 16:17 + */ public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { + private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; private static final int FOLDER_LIST_QUERY_TOKEN = 1; @@ -135,8 +143,19 @@ 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: 创建Activity,启动其生命周期。完成设置界面样式、初始化资源、且在用户第一次使用App时进行介绍 + * @date: 2024/1/2 10:26 + * @author: 王毅 + * @param: [android.os.Bundle]:[savedInstanceState] + * @return: void + */ @Override protected void onCreate(Bundle savedInstanceState) { + + + super.onCreate(savedInstanceState); setContentView(R.layout.note_list); initResources(); @@ -147,8 +166,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt setAppInfoFromRawRes(); } + /** + * @method: onActivityResult + * @description: intent返回数据接收函数。形参为请求码、结果码、其他intent返回的数据。主要与NoteEditActivity交互 + * @date: 2024/1/2 10:27 + * @author: 高浏洋 + * @param: [int, int, android.content.Intent]:[requestCode, resultCode, data] + * @return: void + */ @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); @@ -157,19 +187,38 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * @method: setAppInfoFromRawRes + * @description: 第一次使用App时调用,显示introduction。 + * @date: 2024/1/5 16:18 + * @author: 高浏洋 + * @param: []:[] + * @return: void + */ private void setAppInfoFromRawRes() { + + + + 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); if (in != null) { + // 创建输入流读取器 InputStreamReader isr = new InputStreamReader(in); + // 创建缓冲流读取器 BufferedReader br = new BufferedReader(isr); + // 创建字符数组 char [] buf = new char[1024]; + // 定义读取长度 int len = 0; + // 循环读取 while ((len = br.read(buf)) > 0) { + // 将读取的字符串添加到字符串缓冲区 sb.append(buf, 0, len); } } else { @@ -195,6 +244,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt ResourceParser.RED); note.setWorkingText(sb.toString()); if (note.saveNote()) { + // 保存笔记成功,保存添加笔记的偏好设置 sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); } else { Log.e(TAG, "Save introduction note error"); @@ -202,14 +252,35 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } } - + /** + * @method: onStart + * @description: onCreate调用后回调,此Activity对用户可见。 + * @date: 2024/1/5 16:19 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ @Override protected void onStart() { + + + super.onStart(); startAsyncNotesListQuery(); } + /** + * @method: initResources + * @description: 初始化资源 + * @date: 2024/1/5 16:20 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void initResources() { + + + mContentResolver = this.getContentResolver(); mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); mCurrentFolderId = Notes.ID_ROOT_FOLDER; @@ -231,30 +302,62 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt mModeCallBack = new ModeCallback(); } + /** + * @class: ModeCallback + * @implements: ListView.MultiChoiceModeListener, OnMenuItemClickListener + * @description: 定义了ActionMode的使用。便签长按事件通过ActionMode执行。 + * 便签长按后出现选择(多个)便签删除的菜单栏,其在ActionBar中显示。 + * @author: 王毅 + * @date: 2024/1/5 16:21 + */ private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { + private DropdownMenu mDropDownMenu; private ActionMode mActionMode; private MenuItem mMoveMenu; + /** + * @method: onCreateActionMode + * @description: ActionMode创建函数,形参为创建的ActionMode及需要通过该ActionMode显示的Menu对象 + * @date: 2024/1/5 16:23 + * @author: 高浏阳 + * @param: [android.view.ActionMode, android.view.Menu]:[mode, menu] + * @return: boolean + */ public boolean onCreateActionMode(ActionMode mode, Menu menu) { + + + getMenuInflater().inflate(R.menu.note_list_options, menu); + // 设置菜单项的点击事件 menu.findItem(R.id.delete).setOnMenuItemClickListener(this); + // 获取移动菜单 mMoveMenu = menu.findItem(R.id.move); + // 如果当前文件夹是通话记录文件夹或者用户文件夹的数量为0,则隐藏移动菜单 if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER || DataUtils.getUserFolderCount(mContentResolver) == 0) { mMoveMenu.setVisible(false); } else { + // 否则显示移动菜单 mMoveMenu.setVisible(true); + // 设置移动菜单的点击事件 mMoveMenu.setOnMenuItemClickListener(this); } + // 保存当前模式 mActionMode = mode; + // 设置列表选择模式 mNotesListAdapter.setChoiceMode(true); + // 设置列表不可点击 mNotesListView.setLongClickable(false); + // 隐藏添加新笔记按钮 mAddNewNote.setVisibility(View.GONE); + // 创建自定义菜单 View customView = LayoutInflater.from(NotesListActivity.this).inflate( R.layout.note_list_dropdown_menu, null); + // 设置自定义菜单 mode.setCustomView(customView); + // 创建下拉菜单 mDropDownMenu = new DropdownMenu(NotesListActivity.this, (Button) customView.findViewById(R.id.selection_menu), R.menu.note_list_dropdown); @@ -269,16 +372,31 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } + /** + * @method: updateMenu + * @description: 用于进行多选(全选)时菜单栏界面的更新 + * @date: 2024/1/5 16:23 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void updateMenu() { + + + + //获取已选择的项数 int selectedCount = mNotesListAdapter.getSelectedCount(); - // Update dropdown menu + //根据已选择的项数,设置菜单标题 String format = getResources().getString(R.string.menu_select_title, selectedCount); mDropDownMenu.setTitle(format); + //设置菜单中的action_select_all的标题 MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); if (item != null) { + //如果已选择全部,则设置action_select_all的标题为menu_deselect_all if (mNotesListAdapter.isAllSelected()) { item.setChecked(true); item.setTitle(R.string.menu_deselect_all); + //否则设置action_select_all的标题为menu_select_all } else { item.setChecked(false); item.setTitle(R.string.menu_select_all); @@ -286,33 +404,100 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + + /** + * @method: onPrepareActionMode + * @description: //重新刷新菜单栏时调用 + * @date: 2024/1/5 16:26 + * @author: 高浏阳 + * @param: [android.view.ActionMode, android.view.Menu]:[mode, menu] + * @return: boolean + */ public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + + + // TODO Auto-generated method stub return false; } + /** + * @method: onActionItemClicked + * @description: 菜单栏点击动作按钮时调用、形参为ActionMode与点击的菜单项 + * @date: 2024/1/5 16:26 + * @author: 高浏阳 + * @param: [android.view.ActionMode, android.view.MenuItem]:[mode, item] + * @return: boolean + */ public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + + + // TODO Auto-generated method stub return false; } + /** + * @method: onDestroyActionMode + * @description: 销毁或退出ActionMode时调用 + * @date: 2024/1/5 16:26 + * @author: 高浏阳 + * @param: [android.view.ActionMode]:[mode] + * @return: void + */ public void onDestroyActionMode(ActionMode mode) { + + + mNotesListAdapter.setChoiceMode(false); mNotesListView.setLongClickable(true); mAddNewNote.setVisibility(View.VISIBLE); } + /** + * @method: finishActionMode + * @description: 结束ActionMode时调用 + * @date: 2024/1/5 16:27 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ public void finishActionMode() { + + + mActionMode.finish(); } + /** + * @method: onItemCheckedStateChanged + * @description: 描述一下方法的作用 + * @date: 2024/1/5 16:27 + * @author: 高浏阳 + * @param: [android.view.ActionMode, int, long, boolean]:[mode, position, id, checked] + * @return: void + */ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, + + + boolean checked) { mNotesListAdapter.setCheckedItem(position, checked); updateMenu(); } + /** + * @method: onMenuItemClick + * @description: 菜单项点击时调用。 + * @date: 2024/1/6 11:04 + * @author: 高浏阳 + * @param: [android.view.MenuItem]:[item] + * @return: boolean + */ public boolean onMenuItemClick(MenuItem item) { + + + if (mNotesListAdapter.getSelectedCount() == 0) { Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), Toast.LENGTH_SHORT).show(); @@ -321,21 +506,29 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt int itemId = item.getItemId(); if (itemId == R.id.delete) { + // 创建一个AlertDialog.Builder对象,用于构建AlertDialog AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + // 设置标题 builder.setTitle(getString(R.string.alert_title_delete)); + // 设置图标 builder.setIcon(android.R.drawable.ic_dialog_alert); + // 设置消息 builder.setMessage(getString(R.string.alert_message_delete_notes, mNotesListAdapter.getSelectedCount())); + // 设置确定按钮 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - batchDelete(); + batchDelete();//批处理删除 } }); + // 设置取消按钮 builder.setNegativeButton(android.R.string.cancel, null); + // 显示AlertDialog builder.show(); } else if (itemId == R.id.move) { + // 启动移动到文件夹查询 startQueryDestinationFolders(); } else { return false; @@ -344,61 +537,77 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * @class: NewNoteOnTouchListener + * @implements: OnTouchListener + * @description: 新便签触摸事件监听类。根据触摸事件(比如手在屏幕滑动)修正视图的位置参数 + * @author: 王毅 + * @date: 2024/1/6 11:05 + */ private class NewNoteOnTouchListener implements OnTouchListener { + + + public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: { - Display display = getWindowManager().getDefaultDisplay(); - int screenHeight = display.getHeight(); - int newNoteViewHeight = mAddNewNote.getHeight(); - int start = screenHeight - newNoteViewHeight; - int eventY = start + (int) event.getY(); - /** - * Minus TitleBar's height - */ - if (mState == ListEditState.SUB_FOLDER) { - eventY -= mTitleBar.getHeight(); - start -= mTitleBar.getHeight(); - } - /** - * HACKME:When click the transparent part of "New Note" button, dispatch - * the event to the list view behind this button. The transparent part of - * "New Note" button could be expressed by formula y=-0.12x+94(Unit:pixel) - * and the line top of the button. The coordinate based on left of the "New - * Note" button. The 94 represents maximum height of the transparent part. - * Notice that, if the background of the button changes, the formula should - * also change. This is very bad, just for the UI designer's strong requirement. - */ - if (event.getY() < (event.getX() * (-0.12) + 94)) { - View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - - mNotesListView.getFooterViewsCount()); - if (view != null && view.getBottom() > start - && (view.getTop() < (start + 94))) { - mOriginY = (int) event.getY(); - mDispatchY = eventY; - event.setLocation(event.getX(), mDispatchY); - mDispatch = true; - return mNotesListView.dispatchTouchEvent(event); - } - } - break; + int action = event.getAction(); + if (action == MotionEvent.ACTION_DOWN) { + //获取当前屏幕的高度 + Display display = getWindowManager().getDefaultDisplay(); + int screenHeight = display.getHeight(); + //获取新建笔记视图的高度 + int newNoteViewHeight = mAddNewNote.getHeight(); + //计算新建笔记视图的起始位置 + int start = screenHeight - newNoteViewHeight; + //计算当前点击的y坐标 + int eventY = start + (int) event.getY(); + /** + * Minus TitleBar's height + */ + //如果当前状态是子文件夹,则减去标题栏的高度 + if (mState == ListEditState.SUB_FOLDER) { + eventY -= mTitleBar.getHeight(); + start -= mTitleBar.getHeight(); } - case MotionEvent.ACTION_MOVE: { - if (mDispatch) { - mDispatchY += (int) event.getY() - mOriginY; + /** + * HACKME:When click the transparent part of "New Note" button, dispatch + * the event to the list view behind this button. The transparent part of + * "New Note" button could be expressed by formula y=-0.12x+94(Unit:pixel) + * and the line top of the button. The coordinate based on left of the "New + * Note" button. The 94 represents maximum height of the transparent part. + * Notice that, if the background of the button changes, the formula should + * also change. This is very bad, just for the UI designer's strong requirement. + */ + if (event.getY() < (event.getX() * (-0.12) + 94)) { + // 获取最后一个可见的View + View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 + - mNotesListView.getFooterViewsCount()); + if (view != null && view.getBottom() > start + && (view.getTop() < (start + 94))) { + // 记录Y轴的起始位置 + mOriginY = (int) event.getY(); + // 记录Y轴的偏移量 + mDispatchY = eventY; + // 设置新的坐标 event.setLocation(event.getX(), mDispatchY); + // 设置偏移量 + mDispatch = true; return mNotesListView.dispatchTouchEvent(event); } - break; } - default: { - if (mDispatch) { - event.setLocation(event.getX(), mDispatchY); - mDispatch = false; - return mNotesListView.dispatchTouchEvent(event); - } - break; + } else if (action == MotionEvent.ACTION_MOVE) { + // 移动时,将Y坐标值增加 + if (mDispatch) { + mDispatchY += (int) event.getY() - mOriginY; + event.setLocation(event.getX(), mDispatchY); + return mNotesListView.dispatchTouchEvent(event); + } + } else { + // 结束时,将Y坐标值设置为0 + if (mDispatch) { + event.setLocation(event.getX(), mDispatchY); + mDispatch = false; + return mNotesListView.dispatchTouchEvent(event); } } return false; @@ -406,7 +615,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }; + /** + * @method: startAsyncNotesListQuery + * @description: 已同步便签查询。当进入一个新文件夹时会向数据库发送查询当前文件夹下的便签请求。返回查询结果。这是一个异步查询进程 + * @date: 2024/1/6 11:06 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ + private void startAsyncNotesListQuery() { + + + String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION : NORMAL_SELECTION; mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, @@ -415,18 +636,41 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); } - private final class BackgroundQueryHandler extends AsyncQueryHandler { + /** + * @class: BackgroundQueryHandler + * @extends: AsyncQueryHandler + * @description: 背景查询消息处理类。主要功能是将查询后得到的便签在界面显示 + * @author: 王毅 + * @date: 2024/1/6 11:07 + */ + + private final class BackgroundQueryHandler extends AsyncQueryHandler{ + public BackgroundQueryHandler(ContentResolver contentResolver) { super(contentResolver); } + /** + * @method: onQueryComplete + * @description: 下面就是查询结束后对返回数据的处理,完成界面更新 + * @date: 2024/1/6 11:08 + * @author: 高浏阳 + * @param: [int, java.lang.Object, android.database.Cursor]:[token, cookie, cursor] + * @return: void + */ @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 { @@ -439,27 +683,46 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + + /** + * @method: showFolderListMenu + * @description: 通过游标显示文件夹列表菜单,功能为移动便签至某个文件件 + * @date: 2024/1/6 11:08 + * @author: 高浏阳 + * @param: [android.database.Cursor]:[cursor] + * @return: void + */ private void showFolderListMenu(Cursor cursor) { + + + AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); + // 设置标题 builder.setTitle(R.string.menu_title_select_folder); + // 创建一个FoldersListAdapter对象 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(); + // 结束ActionMode mModeCallBack.finishActionMode(); } }); builder.show(); } + //创建新便签。主要是创建intent并启动。 private void createNewNote() { Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); @@ -467,7 +730,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); } + + /** + * @method: batchDelete + * @description: 批处理删除。用于多个标签删除时 + * @date: 2024/1/6 11:15 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void batchDelete() { + + + new AsyncTask>() { protected HashSet doInBackground(Void... unused) { HashSet widgets = mNotesListAdapter.getSelectedWidget(); @@ -504,7 +779,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }.execute(); } + /** + * @method: deleteFolder + * @description: 文件夹删除功能 + * @date: 2024/1/6 11:16 + * @author: 高浏阳 + * @param: [long]:[folderId] + * @return: void + */ private void deleteFolder(long folderId) { + + + if (folderId == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Wrong folder id, should not happen " + folderId); return; @@ -531,102 +817,200 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * @method: openNode + * @description: 打开便签功能。形参为NoteItemData,其为文件夹或便签的实例。 + * @date: 2024/1/6 11:17 + * @author: 高浏阳 + * @param: [net.micode.notes.ui.NoteItemData]:[data] + * @return: void + */ private void openNode(NoteItemData data) { + + + Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_VIEW); intent.putExtra(Intent.EXTRA_UID, data.getId()); this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE); } +/** + * @method openFolder + * @description 打开文件夹方法 + * @date: 2023/12/21 7:54 + * @author: 王毅 + * @param + * @return + */ + //打开文件夹功能 private void openFolder(NoteItemData data) { + // 设置当前文件夹的ID mCurrentFolderId = data.getId(); + // 开始异步查询笔记列表 startAsyncNotesListQuery(); + // 如果当前文件夹的ID等于Notes.ID_CALL_RECORD_FOLDER if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + // 设置当前状态为CALL_RECORD_FOLDER mState = ListEditState.CALL_RECORD_FOLDER; + // 隐藏添加新笔记按钮 mAddNewNote.setVisibility(View.GONE); } else { + // 否则设置当前状态为SUB_FOLDER mState = ListEditState.SUB_FOLDER; } + // 如果当前文件夹的ID等于Notes.ID_CALL_RECORD_FOLDER if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { + // 设置标题栏文本为call_record_folder_name mTitleBar.setText(R.string.call_record_folder_name); } else { + // 否则设置标题栏文本为data.getSnippet() mTitleBar.setText(data.getSnippet()); } + // 设置标题栏可见 mTitleBar.setVisibility(View.VISIBLE); } + /** + * @method: onClick + * @description: 视图点击事件。实现创建便签。 + * @date: 2024/1/6 11:17 + * @author: 高浏阳 + * @param: [android.view.View]:[v] + * @return: void + */ + public void onClick(View v) { + + + if (v.getId() == R.id.btn_new_note) { createNewNote(); } } + /** + * @method: showSoftInput + * @description: 显示软键盘 + * @date: 2024/1/6 11:17 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void showSoftInput() { + + + InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager != null) { inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } } - + /** + * @method: hideSoftInput + * @description: 不显示软键盘 + * @date: 2024/1/6 11:18 + * @author: 高浏阳 + * @param: [android.view.View]:[view] + * @return: void + */ private void hideSoftInput(View view) { + + + + //获取输入法管理服务 InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + //隐藏输入法 inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); } + //文件夹新建、查看及重命名功能。 + /** + * @method showCreateOrModifyFolderDialog + * @description 显示创建或修改文件夹对话框 + * @date: 2023/12/21 9:44 + * @author: 王毅 + * @param :[boolean]:[create] + * @return void + */ 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); final EditText etName = (EditText) view.findViewById(R.id.et_foler_name); + // 显示输入框 showSoftInput(); if (!create) { if (mFocusNoteDataItem != null) { + // 设置文本框中的文本为当前文件夹的摘要 etName.setText(mFocusNoteDataItem.getSnippet()); + // 设置标题为修改文件夹名称 builder.setTitle(getString(R.string.menu_folder_change_name)); } else { Log.e(TAG, "The long click data item is null"); return; } } else { + // 创建文件夹,清空文本框 etName.setText(""); + // 设置标题为创建文件夹 builder.setTitle(this.getString(R.string.menu_create_folder)); } - + //设置确定按钮 builder.setPositiveButton(android.R.string.ok, null); + //设置取消按钮 builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { + //隐藏软键盘 hideSoftInput(etName); } }); + //创建对话框 final Dialog dialog = builder.setView(view).show(); + //获取确定按钮 final Button positive = (Button)dialog.findViewById(android.R.id.button1); positive.setOnClickListener(new OnClickListener() { public void onClick(View v) { + //隐藏软键盘 hideSoftInput(etName); + //获取输入框中的文本 String name = etName.getText().toString(); + //检查输入的文本是否已经存在 if (DataUtils.checkVisibleFolderName(mContentResolver, name)) { + //如果存在,则提示用户 Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name), Toast.LENGTH_LONG).show(); + //将光标移动到输入框的末尾 etName.setSelection(0, etName.length()); return; } + //新建文件夹的关键 + //如果输入的文本不存在 if (!create) { + //如果输入的文本不为空 if (!TextUtils.isEmpty(name)) { + //创建一个ContentValues对象 ContentValues values = new ContentValues(); + //将输入的文本添加到ContentValues对象中 values.put(NoteColumns.SNIPPET, name); values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); values.put(NoteColumns.LOCAL_MODIFIED, 1); + //更新指定id的记录 mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID + "=?", new String[] { String.valueOf(mFocusNoteDataItem.getId()) }); } } else if (!TextUtils.isEmpty(name)) { + //创建一个ContentValues对象 ContentValues values = new ContentValues(); + //将输入的文本添加到ContentValues对象中 values.put(NoteColumns.SNIPPET, name); values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + //插入新记录 mContentResolver.insert(Notes.CONTENT_NOTE_URI, values); } + //关闭对话框 dialog.dismiss(); } }); @@ -644,6 +1028,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } public void onTextChanged(CharSequence s, int start, int before, int count) { + // 当输入框内容发生变化时,判断输入框内容是否为空,如果为空,则禁用positive按钮,否则启用positive按钮 if (TextUtils.isEmpty(etName.getText())) { positive.setEnabled(false); } else { @@ -657,24 +1042,44 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } }); } - + /** + * @method: onBackPressed + * @description: 用于处理子Acitivity返回父Activity。相当于对按下“返回箭头”的处理。即返回NotesListActivity活动。 + * @date: 2024/1/6 11:18 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ @Override public void onBackPressed() { + + + switch (mState) { case SUB_FOLDER: + // 设置当前文件夹ID为根文件夹ID mCurrentFolderId = Notes.ID_ROOT_FOLDER; + // 设置当前状态为NOTE_LIST mState = ListEditState.NOTE_LIST; + // 开始异步查询笔记列表 startAsyncNotesListQuery(); + // 设置标题栏不可见 mTitleBar.setVisibility(View.GONE); break; case CALL_RECORD_FOLDER: + // 设置当前文件夹ID为根文件夹ID mCurrentFolderId = Notes.ID_ROOT_FOLDER; + // 设置当前状态为NOTE_LIST mState = ListEditState.NOTE_LIST; + // 设置添加新笔记按钮可见 mAddNewNote.setVisibility(View.VISIBLE); + // 设置标题栏不可见 mTitleBar.setVisibility(View.GONE); + // 开始异步查询笔记列表 startAsyncNotesListQuery(); break; case NOTE_LIST: + // 调用父类的onBackPressed方法 super.onBackPressed(); break; default: @@ -682,68 +1087,158 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + /** + * @method: updateWidget + * @description: 更新小组件 + * @date: 2024/1/6 11:19 + * @author: 高浏阳 + * @param: [int, int]:[appWidgetId, appWidgetType] + * @return: void + */ private void updateWidget(int appWidgetId, int appWidgetType) { + + + Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); + // 判断widget的类型 if (appWidgetType == Notes.TYPE_WIDGET_2X) { + // 设置widget的更新类 intent.setClass(this, NoteWidgetProvider_2x.class); } else if (appWidgetType == Notes.TYPE_WIDGET_4X) { + // 设置widget的更新类 intent.setClass(this, NoteWidgetProvider_4x.class); } else { Log.e(TAG, "Unspported widget type"); return; } + // 设置更新widget的id intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId }); + // 发送更新widget的广播 sendBroadcast(intent); + // 设置更新结果 setResult(RESULT_OK, intent); } + + /** + * @class: NotesListActivity + * @extends: + * @description: 实现按文件夹item的上下文菜单的回调函数,查看、删除、修改文件夹名称的浮动菜单栏(ContextMenu)创建(就是长按后出现) + * @author: 王毅 + * @date: 2023/12/23 9:28 + */ private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { + //创建ContextMenu,形参为创建的菜单、长按事件绑定的视图、视图元素信息 + + + /** + * @method: onCreateContextMenu + * @description: 构造长按文件夹item的上下文菜单 + * @date: 2023/12/23 9:12 + * @author: 王毅 + * @param: [android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo]:[menu, v, menuInfo] + * @return: void + */ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + + + + // 如果mFocusNoteDataItem不为空 if (mFocusNoteDataItem != null) { + // 设置菜单的标题为mFocusNoteDataItem的摘要 menu.setHeaderTitle(mFocusNoteDataItem.getSnippet()); + // 添加菜单项,菜单项的ID为MENU_FOLDER_VIEW,文本为R.string.menu_folder_view menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view); + // 添加菜单项,菜单项的ID为MENU_FOLDER_DELETE,文本为R.string.menu_folder_delete menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete); + // 添加菜单项,菜单项的ID为MENU_FOLDER_CHANGE_NAME,文本为R.string.menu_folder_change_name menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name); } } }; + //下面都是对浮动菜单栏的一些函数 + + /** + * @method onContextMenuClosed + * @description 浮动菜单栏关闭 + * @date: 2023/12/21 8:32 + * @author: 王毅 + * param [android.view.Menu]:[menu] + * @return void + */ @Override public void onContextMenuClosed(Menu menu) { + + + + // 移除对mNotesListView的监听 + // 否则,当用户在列表项上右键时,会调用onContextMenuClosed()方法 + + // 移除对mNotesListView的监听 if (mNotesListView != null) { mNotesListView.setOnCreateContextMenuListener(null); } super.onContextMenuClosed(menu); } + //浮动菜单栏点击按钮后事件处理。 + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent ev) { + return super.dispatchGenericMotionEvent(ev); + } + /** + * @method onContextItemSelected + * @description 长按文件夹图标后显示的菜单选项 + * @date: 2023/12/23 8:53 + * @author: 王毅 + * @param: [android.view.MenuItem]:[item] + * @return: boolean + */ @Override public boolean onContextItemSelected(MenuItem item) { + + + // 判断当前焦点数据项是否为空 if (mFocusNoteDataItem == null) { Log.e(TAG, "The long click data item is null"); return false; } + // 根据根据点击菜单项id进行判断 switch (item.getItemId()) { + // 打开文件夹 case MENU_FOLDER_VIEW: openFolder(mFocusNoteDataItem); break; + // 删除文件夹 case MENU_FOLDER_DELETE: + // 实例化一个Builder类 AlertDialog.Builder builder = new AlertDialog.Builder(this); + // 设置标题 builder.setTitle(getString(R.string.alert_title_delete)); + // 设置图标 builder.setIcon(android.R.drawable.ic_dialog_alert); + // 设置消息 builder.setMessage(getString(R.string.alert_message_delete_folder)); + // 设置确定按钮 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { + // 删除文件夹 deleteFolder(mFocusNoteDataItem.getId()); } }); + // 设置取消按钮 builder.setNegativeButton(android.R.string.cancel, null); + // 显示对话框 builder.show(); break; + // 修改文件夹名称 case MENU_FOLDER_CHANGE_NAME: showCreateOrModifyFolderDialog(false); break; @@ -754,58 +1249,111 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } + //下面是OptionsMenu菜单创建的有关函数。 + // + /** + * @method: onPrepareOptionsMenu + * @description: 针对不同界面打开不同的选项菜单,OptionsMenu创建 + * @date: 2023/12/23 9:55 + * @author: 王毅 + * @param: [android.view.Menu]:[menu] + * @return: boolean + */ @Override public boolean onPrepareOptionsMenu(Menu menu) { menu.clear(); if (mState == ListEditState.NOTE_LIST) { + // 加载note_list菜单 getMenuInflater().inflate(R.menu.note_list, menu); // set sync or sync_cancel + // 设置sync或sync_cancel menu.findItem(R.id.menu_sync).setTitle( GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync); } else if (mState == ListEditState.SUB_FOLDER) { + // 加载sub_folder菜单 getMenuInflater().inflate(R.menu.sub_folder, menu); } else if (mState == ListEditState.CALL_RECORD_FOLDER) { + // 加载call_record_folder菜单 getMenuInflater().inflate(R.menu.call_record_folder, menu); } else { Log.e(TAG, "Wrong state:" + mState); } return true; } - + /** + * @method: onOptionsItemSelected + * @description: 点击不同的选项菜单栏打开不同的界面 + * @date: 2023/12/24 10:07 + * @author: 王毅 + * @param: [android.view.MenuItem]:[item] + * @return: boolean + */ @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_new_folder) { + // 创建或修改文件夹 showCreateOrModifyFolderDialog(true); } else if (itemId == R.id.menu_export_text) { + // 导出笔记到文本 exportNoteToText(); } else if (itemId == R.id.menu_sync) { + // 同步笔记 if (isSyncMode()) { if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) { + // 开始同步 GTaskSyncService.startSync(this); } else { + // 取消同步 GTaskSyncService.cancelSync(this); } } else { + // 开始偏好设置 startPreferenceActivity(); } } else if (itemId == R.id.menu_setting) { + // 开始偏好设置 startPreferenceActivity(); } else if (itemId == R.id.menu_new_note) { + // 创建新笔记 createNewNote(); } else if (itemId == R.id.menu_search) { + // 请求搜索 onSearchRequested(); } return true; } + /** + * @method: onSearchRequested + * @description: 搜索栏功能实现(就是最上面那个搜索便签得的),调用了ui组件 + * @date: 2024/1/6 11:20 + * @author: 高浏阳 + * @param: []:[] + * @return: boolean + */ @Override public boolean onSearchRequested() { + + + startSearch(null, false, null /* appData */, false); return true; } + //下面使用了异步线程类AsynTask。可在类中可以直接进行UI操作,并将后台计算的结果及时的交给UI线程进行UI界面显示。 + /** + * @method: exportNoteToText + * @description: 将便签内容输出为文本 + * @date: 2024/1/6 11:21 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void exportNoteToText() { + + + final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); new AsyncTask() { @@ -817,6 +1365,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt @Override protected void onPostExecute(Integer result) { if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) { + // 弹出提示框,提示SD卡未卸载 AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this .getString(R.string.failed_sdcard_export)); @@ -825,6 +1374,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt builder.setPositiveButton(android.R.string.ok, null); builder.show(); } else if (result == BackupUtils.STATE_SUCCESS) { + // 弹出提示框,提示SD卡导出成功 AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this .getString(R.string.success_sdcard_export)); @@ -834,6 +1384,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt builder.setPositiveButton(android.R.string.ok, null); builder.show(); } else if (result == BackupUtils.STATE_SYSTEM_ERROR) { + // 弹出提示框,提示SD卡导出失败 AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); builder.setTitle(NotesListActivity.this .getString(R.string.failed_sdcard_export)); @@ -851,19 +1402,52 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } + /** + * @method: startPreferenceActivity + * @description: 用于跳转到保存的设置界面。这个maybe在isSyncMode==0时调用。作用在没进行过保存设置时。 + * @date: 2024/1/6 11:22 + * @author: 高浏阳 + * @param: []:[] + * @return: void + */ private void startPreferenceActivity() { + + + Activity from = getParent() != null ? getParent() : this; Intent intent = new Intent(from, NotesPreferenceActivity.class); from.startActivityIfNeeded(intent, -1); } + /** + * @class: OnListItemClickListener + * @implements OnItemClickListener + * @description: 点击事件监听类 + * @author: 王毅 + * @date: 2024/1/6 11:22 + */ private class OnListItemClickListener implements OnItemClickListener { + + /** + * @method: onItemClick + * @description: 点击事件处理。将点击事件其与视图绑定。 + * @date: 2024/1/6 11:23 + * @author: 高浏阳 + * @param: [android.widget.AdapterView, android.view.View, int, long]:[parent, view, position, id] + * @return: void + */ public void onItemClick(AdapterView parent, View view, int position, long id) { + + + if (view instanceof NotesListItem) { NoteItemData item = ((NotesListItem) view).getItemData(); + // 判断是否处于选择模式 if (mNotesListAdapter.isInChoiceMode()) { + // 如果当前是笔记,则调用选择回调函数 if (item.getType() == Notes.TYPE_NOTE) { + // 减去头部视图的数量 position = position - mNotesListView.getHeaderViewsCount(); mModeCallBack.onItemCheckedStateChanged(null, position, id, !mNotesListAdapter.isSelectedItem(position)); @@ -873,9 +1457,11 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt switch (mState) { case NOTE_LIST: + // 如果当前是文件夹或者系统文件夹,则打开文件夹 if (item.getType() == Notes.TYPE_FOLDER || item.getType() == Notes.TYPE_SYSTEM) { openFolder(item); + // 如果当前是笔记,则打开笔记 } else if (item.getType() == Notes.TYPE_NOTE) { openNode(item); } else { @@ -884,6 +1470,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt break; case SUB_FOLDER: case CALL_RECORD_FOLDER: + // 如果当前是笔记,则打开笔记 if (item.getType() == Notes.TYPE_NOTE) { openNode(item); } else { @@ -898,6 +1485,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } + private void startQueryDestinationFolders() { String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; selection = (mState == ListEditState.NOTE_LIST) ? selection: @@ -915,8 +1503,18 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }, NoteColumns.MODIFIED_DATE + " DESC"); } - + /** + * @method onItemLongClick + * @description 处理用户长按控件时的行为 + * @date: 2023/12/21 8:37 + * @author: 王毅 + * @param :[android.widget.AdapterView, android.view.View, int, long]:[parent, view, position, id] + * @return boolean + */ public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + + + if (view instanceof NotesListItem) { mFocusNoteDataItem = ((NotesListItem) view).getItemData(); if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {