From 77ce191c8983daee907e0524dbeaee559ae3f960 Mon Sep 17 00:00:00 2001 From: Sunique_L <2758798112@qq.com> Date: Tue, 21 May 2024 23:07:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E7=B1=B3=E4=BE=BF=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 小米便签 --- src/net/micode/notes/model/WorkingNote.java | 222 +++-- src/net/micode/notes/ui/DateTimePicker.java | 1 - src/net/micode/notes/ui/NoteItemData.java | 2 +- .../micode/notes/ui/NotesListActivity.java | 853 +++++++++++------- 4 files changed, 639 insertions(+), 439 deletions(-) diff --git a/src/net/micode/notes/model/WorkingNote.java b/src/net/micode/notes/model/WorkingNote.java index be081e4..ead1b62 100644 --- a/src/net/micode/notes/model/WorkingNote.java +++ b/src/net/micode/notes/model/WorkingNote.java @@ -32,119 +32,167 @@ import net.micode.notes.data.Notes.TextNote; import net.micode.notes.tool.ResourceParser.NoteBgResources; -public class WorkingNote { - // Note for the working note - private Note mNote; - // Note Id - private long mNoteId; - // Note content - private String mContent; - // Note mode - private int mMode; +//声明一个公共类WorkingNote +public class WorkingNote { - private long mAlertDate; + // 用于存储工作笔记的Note对象 + // Note是一个自定义类,用于表示笔记的内容、属性等 + private Note mNote; - private long mModifiedDate; + // 笔记的唯一标识符 + private long mNoteId; - private int mBgColorId; + // 笔记的内容 + private String mContent; - private int mWidgetId; + // 笔记的模式,可能表示编辑、查看等不同的状态 + private int mMode; - private int mWidgetType; + // 提醒日期,可能用于提醒用户某个时间点需要处理这个笔记 + private long mAlertDate; - private long mFolderId; + // 修改日期,记录笔记最后一次被修改的时间 + private long mModifiedDate; - private Context mContext; + // 背景颜色ID,用于指定笔记的背景颜色 + private int mBgColorId; - private static final String TAG = "WorkingNote"; + // 小部件ID,可能用于与某个小部件关联 + private int mWidgetId; - private boolean mIsDeleted; + // 小部件类型,用于区分不同类型的小部件 + private int mWidgetType; - private NoteSettingChangedListener mNoteSettingStatusListener; + // 文件夹ID,表示笔记所属的文件夹的ID + private long mFolderId; - public static final String[] DATA_PROJECTION = new String[] { - DataColumns.ID, - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, - }; + // 上下文对象,用于与Android系统交互,例如访问资源、启动活动等 + private Context mContext; - public static final String[] NOTE_PROJECTION = new String[] { - NoteColumns.PARENT_ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, - NoteColumns.MODIFIED_DATE - }; + // 日志的标签,通常用于在日志中标识发出的日志信息属于哪个类或模块 + private static final String TAG = "WorkingNote"; - private static final int DATA_ID_COLUMN = 0; + // 标记笔记是否已被删除,是一个布尔值 + private boolean mIsDeleted; - private static final int DATA_CONTENT_COLUMN = 1; + // 当Note的某些设置发生变化时,会被调用的监听器接口 + // NoteSettingChangedListener是一个自定义接口,当笔记的设置发生变化时,实现该接口的类会被通知 + private NoteSettingChangedListener mNoteSettingStatusListener; - private static final int DATA_MIME_TYPE_COLUMN = 2; + // 定义一个静态常量数组,包含从数据表中检索笔记数据时使用的列名 + // 这个数组包含了从数据表中检索笔记数据时需要的列的名称 + public static final String[] DATA_PROJECTION = new String[] { + DataColumns.ID, // 数据列ID,表示笔记的唯一标识符 + DataColumns.CONTENT, // 数据列CONTENT,表示笔记的内容 + DataColumns.MIME_TYPE, // 数据列MIME_TYPE,表示笔记的MIME类型(例如文本、图片等) + DataColumns.DATA1, // 数据列DATA1,表示其他数据1(具体含义不明) + DataColumns.DATA2, // 数据列DATA2,表示其他数据2(具体含义不明) + DataColumns.DATA3, // 数据列DATA3,表示其他数据3(具体含义不明) + DataColumns.DATA4, // 数据列DATA4,表示其他数据4(具体含义不明) + }; +} - private static final int DATA_MODE_COLUMN = 3; - private static final int NOTE_PARENT_ID_COLUMN = 0; +//声明一个公共类WorkingNote +public class WorkingNote { - private static final int NOTE_ALERTED_DATE_COLUMN = 1; + // 定义一个静态最终的字符串数组,用于从数据表中检索笔记数据的列名 + public static final String[] NOTE_PROJECTION = new String[] { + NoteColumns.PARENT_ID, // 数据列PARENT_ID,表示笔记的父ID + NoteColumns.ALERTED_DATE, // 数据列ALERTED_DATE,表示提醒日期 + NoteColumns.BG_COLOR_ID, // 数据列BG_COLOR_ID,表示背景颜色ID + NoteColumns.WIDGET_ID, // 数据列WIDGET_ID,表示小部件ID + NoteColumns.WIDGET_TYPE, // 数据列WIDGET_TYPE,表示小部件类型 + NoteColumns.MODIFIED_DATE // 数据列MODIFIED_DATE,表示修改日期 + }; - private static final int NOTE_BG_COLOR_ID_COLUMN = 2; + // 定义一个静态最终的整数常量,表示数据ID列的索引 + private static final int DATA_ID_COLUMN = 0; - private static final int NOTE_WIDGET_ID_COLUMN = 3; + // 定义一个静态最终的整数常量,表示内容列的索引 + private static final int DATA_CONTENT_COLUMN = 1; - private static final int NOTE_WIDGET_TYPE_COLUMN = 4; + // 定义一个静态最终的整数常量,表示MIME类型列的索引 + private static final int DATA_MIME_TYPE_COLUMN = 2; - private static final int NOTE_MODIFIED_DATE_COLUMN = 5; + // 定义一个静态最终的整数常量,表示模式列的索引 + private static final int DATA_MODE_COLUMN = 3; - // New note construct - private WorkingNote(Context context, long folderId) { - mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); - mFolderId = folderId; - mNote = new Note(); - mNoteId = 0; - mIsDeleted = false; - mMode = 0; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; - } + // 定义一个静态最终的整数常量,表示笔记的父ID列的索引 + private static final int NOTE_PARENT_ID_COLUMN = 0; - // Existing note construct - private WorkingNote(Context context, long noteId, long folderId) { - mContext = context; - mNoteId = noteId; - mFolderId = folderId; - mIsDeleted = false; - mNote = new Note(); - loadNote(); - } + // 定义一个静态最终的整数常量,表示提醒日期列的索引 + private static final int NOTE_ALERTED_DATE_COLUMN = 1; - private void loadNote() { - Cursor cursor = mContext.getContentResolver().query( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, - null, null); + // 定义一个静态最终的整数常量,表示背景颜色ID列的索引 + private static final int NOTE_BG_COLOR_ID_COLUMN = 2; + + // 定义一个静态最终的整数常量,表示小部件ID列的索引 + private static final int NOTE_WIDGET_ID_COLUMN = 3; + + // 定义一个静态最终的整数常量,表示小部件类型列的索引 + private static final int NOTE_WIDGET_TYPE_COLUMN = 4; + + // 定义一个静态最终的整数常量,表示修改日期列的索引 + private static final int NOTE_MODIFIED_DATE_COLUMN = 5; + + // 新的笔记构造方法,需要传入上下文和小部件ID参数 + // New note construct + private WorkingNote(Context context, long folderId) { + mContext = context; // 设置上下文对象 + mAlertDate = 0; // 将提醒日期设置为0,可能表示还没有设置提醒日期 + mModifiedDate = System.currentTimeMillis(); // 将修改日期设置为当前时间戳 + mFolderId = folderId; // 设置文件夹ID + mNote = new Note(); // 创建一个新的Note对象,可能用于存储笔记的内容、属性等 + mNoteId = 0; // 将笔记ID设置为0,可能表示这是一个新创建的笔记,还没有分配唯一的ID + mIsDeleted = false; // 将删除标记设置为false,表示这个笔记还没有被删除 + mMode = 0; // 将模式设置为0,可能表示这是一个默认的模式或状态 + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 将小部件类型设置为一个无效的值,可能是一个错误或未完成的代码片段 + } +} + + + // Existing note construct +//定义一个私有构造函数,用于创建WorkingNote对象 +private WorkingNote(Context context, long noteId, long folderId) { + mContext = context; // 设置上下文对象 + mNoteId = noteId; // 设置笔记ID + mFolderId = folderId; // 设置文件夹ID + mIsDeleted = false; // 默认设置笔记未被删除 + mNote = new Note(); // 创建一个新的Note对象 + loadNote(); // 调用loadNote方法加载笔记数据 +} + +//定义一个私有方法,用于加载并初始化笔记数据 +private void loadNote() { + // 使用ContentResolver查询指定ID的笔记数据 + Cursor cursor = mContext.getContentResolver().query( + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, + null, null); + + // 检查查询结果是否为空 + if (cursor != null) { + // 如果查询结果不为空,移动到第一条记录(即我们的笔记) + if (cursor.moveToFirst()) { + // 从查询结果中获取笔记的父ID、背景颜色ID、小部件ID、小部件类型、提醒日期和修改日期 + mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); + mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); // 这里可能存在拼写错误,应该是mNote的属性,而不是mBgColorId + mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); + mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); + mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); + } + // 关闭游标以释放资源 + cursor.close(); + } else { + // 如果查询结果为空,记录错误日志并抛出异常,表示无法找到具有指定ID的笔记 + Log.e(TAG, "No note with id:" + mNoteId); + throw new IllegalArgumentException("Unable to find note with id " + mNoteId); + } + // 加载笔记数据(这可能是从数据库或其他地方获取与笔记相关的更多数据) + loadNoteData(); +} - if (cursor != null) { - if (cursor.moveToFirst()) { - mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); - mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); - mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); - mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); - mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); - } - cursor.close(); - } else { - Log.e(TAG, "No note with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note with id " + mNoteId); - } - loadNoteData(); - } private void loadNoteData() { Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, diff --git a/src/net/micode/notes/ui/DateTimePicker.java b/src/net/micode/notes/ui/DateTimePicker.java index 97c4a54..0072f11 100644 --- a/src/net/micode/notes/ui/DateTimePicker.java +++ b/src/net/micode/notes/ui/DateTimePicker.java @@ -29,7 +29,6 @@ import android.widget.NumberPicker; // 定义一个公共类DateTimePicker,它继承自FrameLayout public class DateTimePicker extends FrameLayout { - // 定义一个默认的启用状态常量,值为true private static final boolean DEFAULT_ENABLE_STATE = true; diff --git a/src/net/micode/notes/ui/NoteItemData.java b/src/net/micode/notes/ui/NoteItemData.java index 8fa6f16..a351e45 100644 --- a/src/net/micode/notes/ui/NoteItemData.java +++ b/src/net/micode/notes/ui/NoteItemData.java @@ -226,4 +226,4 @@ public class NoteItemData { return mWidgetType; } - // 定义一个公开的整型方法 getWidgetId,返回值是 mWidgetId 的值,这个方法可能用于获取部件ID。部件可能是UI的一部分或者应用的一部分。 部件ID可能是唯一标识部件的值。 同样的部件可能在屏幕上多次出现,但是每个实例都有唯一的ID。 每个部件ID都存储在部件管理器的内部数据结构中。 通过使用部件ID,可以引用和操作特定的部件实例。 这可能对于在运行时对部件进行动态控制非常有用。 在Android中,部件ID通常是整数类型。 例如,在View类中有一个名为getId的方法,它返回View的ID。 这个ID就是View的实例在屏幕上的唯一标识符。 ID可以是任何整数类型(int),因此你可以使用任何整数作为ID。 在Android中,ID的默认范围是-1到2147483647(如果使用Java)。 在使用C++时,范围可能会有所不同。 ID的值在部件的生命周期中保持不变。 ID为0表示没有给部件指定ID。 在给定ID的情况下,你可以通过使用findViewById或findView \ No newline at end of file + // 定义一个公开的整型方法 getWidgetId,返回值是 mWidgetId 的值,这个方法可能用于获取部件ID。部件可能是UI的一部分或者应用的一部分。 部件ID可能是唯一标识部件的值。 同样的部件可能在屏幕上多次出现,但是每个实例都有唯一的ID。 每个部件ID都存储在部件管理器的内部数据结构中。 通过使用部件ID,可以引用和操作特定的部件实例。 这可能对于在运行时对部件进行动态控制非常有用。 在Android中,部件ID通常是整数类型。 例如,在View类中有一个名为getId的方法,它返回View的ID。 这个ID就是View的实例在屏幕上的唯一标识符。 ID可以是任何整数类型(int),因此你可以使用任何整数作为ID。 在Android中,ID的默认范围是-1到2147483647(如果使用Java)。 在使用C++时,范围可能会有所不同。 ID的值在部件的生命周期中保持不变。 ID为0表示没有给部件指定ID。 在给定ID的情况下,你可以通过使用findViewById或findView \ No newline at end of file diff --git a/src/net/micode/notes/ui/NotesListActivity.java b/src/net/micode/notes/ui/NotesListActivity.java index e843aec..1c6ad59 100644 --- a/src/net/micode/notes/ui/NotesListActivity.java +++ b/src/net/micode/notes/ui/NotesListActivity.java @@ -78,130 +78,195 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; -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; - - private static final int MENU_FOLDER_DELETE = 0; - - private static final int MENU_FOLDER_VIEW = 1; - - private static final int MENU_FOLDER_CHANGE_NAME = 2; - - private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; - - private enum ListEditState { - NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER - }; - - private ListEditState mState; - - private BackgroundQueryHandler mBackgroundQueryHandler; - - private NotesListAdapter mNotesListAdapter; - - private ListView mNotesListView; - - private Button mAddNewNote; - - private boolean mDispatch; - - private int mOriginY; - - private int mDispatchY; - - private TextView mTitleBar; - - private long mCurrentFolderId; - - private ContentResolver mContentResolver; - - private ModeCallback mModeCallBack; - - private static final String TAG = "NotesListActivity"; - - public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; - - private NoteItemData mFocusNoteDataItem; - - 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.note_list); - initResources(); - - /** - * Insert an introduction when user firstly use this application - */ - setAppInfoFromRawRes(); - } - - @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); - } - } +//导入所需的类 +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.ListView; +import android.widget.TextView; + +//导入自定义的NoteItemData类,该类可能用于存储笔记数据 +import net.micode.notes.NoteItemData; + +//导入自定义的Notes类,该类可能包含一些常量,如笔记类型等 +import net.micode.notes.Notes; + +//导入自定义的NoteColumns类,该类可能包含一些与笔记相关的列名 +import net.micode.notes.NoteColumns; + +//导入自定义的ModeCallback接口,该接口可能用于回调某种模式的状态或结果 +import net.micode.notes.ModeCallback; + +//定义一个用于记录笔记列表状态的枚举类ListEditState +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; + + // 定义菜单项的ID,用于删除文件夹、查看文件夹和更改文件夹名称的操作 + private static final int MENU_FOLDER_DELETE = 0; + private static final int MENU_FOLDER_VIEW = 1; + private static final int MENU_FOLDER_CHANGE_NAME = 2; + + // 定义一个用于存储应用程序偏好的键 + private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; + + // 定义一个枚举类型,用于记录笔记列表的状态(如普通笔记列表、子文件夹、通话记录文件夹) + private enum ListEditState { + NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER + }; + + // 记录当前笔记列表的状态 + private ListEditState mState; + + // 用于在后台执行查询的处理器 + private BackgroundQueryHandler mBackgroundQueryHandler; + + // 用于显示笔记列表的适配器 + private NotesListAdapter mNotesListAdapter; + + // 用于显示笔记列表的ListView组件 + private ListView mNotesListView; + + // 添加新笔记的按钮组件 + private Button mAddNewNote; + + // 一个标志,指示是否正在分发事件(可能是用于防止重复点击) + private boolean mDispatch; + + // 记录事件的原始Y坐标和分发的Y坐标(可能是用于处理滚动事件) + private int mOriginY; + private int mDispatchY; + + // 标题栏的TextView组件(可能是用于显示当前选中的文件夹名称) + private TextView mTitleBar; + + // 当前选中的文件夹ID(可能是用于筛选要显示的笔记) + private long mCurrentFolderId; + + // Android的内容解析器,用于访问数据库中的笔记数据 + private ContentResolver mContentResolver; + + // 一个回调接口,可能用于在更改模式时接收回调(例如,更改文件夹名称后的回调) + private ModeCallback mModeCallBack; + + // 定义一个用于日志记录的标签(可能是用于调试或日志记录) + private static final String TAG = "NotesListActivity"; + + // 定义一个常量,用于控制笔记列表视图的滚动速度(可能是用于滚动动画效果) + public static final int NOTES_LISTVIEW_SCROLL_RATE = 30; + + // 当前选中的笔记项的数据对象(可能是用于显示选中的笔记项的详细信息) + private NoteItemData mFocusNoteDataItem; + + // 定义查询笔记时使用的筛选条件(可能是用于筛选特定类型的笔记或子文件夹) + + +//定义一个常量,表示普通选择条件的查询字符串 +private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?"; + +//定义一个常量,表示根文件夹的选择条件的查询字符串 +private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>" + Notes.TYPE_SYSTEM + ")"; + +//重写Activity的onCreate方法 +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); // 调用父类的onCreate方法 + setContentView(R.layout.note_list); // 设置布局为note_list.xml + initResources(); // 初始化资源(可能是初始化一些UI组件或数据) + + // 当用户第一次使用此应用程序时,插入介绍信息 + setAppInfoFromRawRes(); +} + +//重写Activity的onActivityResult方法 +@Override +protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK // 如果返回的结果码是RESULT_OK(表示操作成功) + && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { // 并且请求码是打开节点或新建节点的请求码 + mNotesListAdapter.changeCursor(null); // 改变适配器的数据源为空,可能是为了清空列表 + } else { + super.onActivityResult(requestCode, resultCode, data); // 否则,调用父类的onActivityResult方法 + } +} - 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 { - Log.e(TAG, "Read introduction file error"); - return; - } - } catch (IOException e) { - e.printStackTrace(); - return; - } finally { - if(in != null) { - try { - in.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } +/** + * 从应用的资源文件中获取应用程序信息 + */ +private void setAppInfoFromRawRes() { + // 获取默认的SharedPreferences对象,用于存储应用的一些偏好设置 + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); + + // 检查SharedPreferences中是否已经设置了介绍信息,如果没有,则继续下面的操作 + if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { + // 创建一个StringBuilder对象,用于拼接读取到的文件内容 + StringBuilder sb = new StringBuilder(); + + // 尝试从资源文件中打开"introduction"文件 + InputStream in = null; + try { + in = getResources().openRawResource(R.raw.introduction); + + // 如果文件成功打开 + if (in != null) { + // 创建一个InputStreamReader对象,用于将字节流转换为字符流 + InputStreamReader isr = new InputStreamReader(in); + + // 创建一个BufferedReader对象,用于按行读取字符流 + BufferedReader br = new BufferedReader(isr); + + // 创建一个字符数组,用于缓存读取到的文件内容 + char [] buf = new char[1024]; + int len = 0; + + // 按行读取文件内容,并添加到StringBuilder中 + while ((len = br.read(buf)) > 0) { + sb.append(buf, 0, len); + } + } else { + // 如果文件打开失败,打印错误日志,并结束函数执行 + Log.e(TAG, "Read introduction file error"); + return; + } + } catch (IOException e) { + // 如果在读取文件过程中出现异常,打印异常堆栈信息,并结束函数执行 + e.printStackTrace(); + return; + } finally { + // 无论是否出现异常,都尝试关闭已打开的输入流 + if(in != null) { + try { + in.close(); + } catch (IOException e) { + // 如果关闭输入流失败,打印异常堆栈信息 + e.printStackTrace(); + } + } + } + + // 创建一个新的工作笔记(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()) { + sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); + } else { + // 如果保存工作笔记失败,打印错误日志,并结束函数执行 + Log.e(TAG, "Save introduction note error"); + return; + } + } +} - 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()) { - sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); - } else { - Log.e(TAG, "Save introduction note error"); - return; - } - } - } @Override protected void onStart() { @@ -209,44 +274,86 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt startAsyncNotesListQuery(); } - private void initResources() { - mContentResolver = this.getContentResolver(); - mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mNotesListView = (ListView) findViewById(R.id.notes_list); - mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), - null, false); - mNotesListView.setOnItemClickListener(new OnListItemClickListener()); - mNotesListView.setOnItemLongClickListener(this); - mNotesListAdapter = new NotesListAdapter(this); - mNotesListView.setAdapter(mNotesListAdapter); - mAddNewNote = (Button) findViewById(R.id.btn_new_note); - mAddNewNote.setOnClickListener(this); - mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); - mDispatch = false; - mDispatchY = 0; - mOriginY = 0; - mTitleBar = (TextView) findViewById(R.id.tv_title_bar); - mState = ListEditState.NOTE_LIST; - mModeCallBack = new ModeCallback(); - } - - private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { - private DropdownMenu mDropDownMenu; - private ActionMode mActionMode; - private MenuItem mMoveMenu; - - 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); - if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER - || DataUtils.getUserFolderCount(mContentResolver) == 0) { - mMoveMenu.setVisible(false); - } else { - mMoveMenu.setVisible(true); - mMoveMenu.setOnMenuItemClickListener(this); - } + /** + * 初始化资源 + */ + private void initResources() { + // 获取ContentResolver对象,用于访问应用程序中的内容提供者 + mContentResolver = this.getContentResolver(); + + // 创建一个后台查询处理器,用于在后台处理数据库查询操作 + mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); + + // 设置当前文件夹ID为根文件夹ID + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + + // 获取ListView对象,用于显示笔记列表 + mNotesListView = (ListView) findViewById(R.id.notes_list); + + // 向ListView添加一个底部视图,可能是用于显示一些额外的信息或控件 + mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), + null, false); + + // 设置ListView的Item点击监听器为OnListItemClickListener对象 + mNotesListView.setOnItemClickListener(new OnListItemClickListener()); + + // 设置ListView的Item长按监听器为当前类对象(this),即实现了OnItemLongClickListener接口 + mNotesListView.setOnItemLongClickListener(this); + + // 创建一个笔记列表适配器,用于将数据与视图进行绑定 + mNotesListAdapter = new NotesListAdapter(this); + + // 将适配器设置到ListView上,以显示数据 + mNotesListView.setAdapter(mNotesListAdapter); + + // 获取一个按钮对象,可能是用于添加新笔记的按钮 + mAddNewNote = (Button) findViewById(R.id.btn_new_note); + + // 设置按钮的点击监听器为当前类对象(this),即实现了OnClickListener接口 + mAddNewNote.setOnClickListener(this); + + // 设置按钮的触摸监听器为NewNoteOnTouchListener对象,用于处理触摸事件 + mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); + + // 初始化一些变量,如dispatch(可能是用于处理拖动手势的变量)等 + mDispatch = false; + mDispatchY = 0; + mOriginY = 0; + + // 获取一个TextView对象,可能是标题栏的一部分 + mTitleBar = (TextView) findViewById(R.id.tv_title_bar); + + // 设置当前的状态为笔记列表状态(ListEditState.NOTE_LIST) + mState = ListEditState.NOTE_LIST; + + // 创建一个回调模式对象,用于处理不同的菜单选项和动作模式等交互事件 + mModeCallBack = new ModeCallback(); + } + + /** + * ModeCallback内部类,实现了ListView.MultiChoiceModeListener和OnMenuItemClickListener接口。 + * 用于处理列表的多选模式和菜单项点击事件。 + */ + private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { + // 创建下拉菜单对象和ActionMode对象,用于处理多选模式下的菜单和动作模式等交互事件。 + private DropdownMenu mDropDownMenu; + private ActionMode mActionMode; + private MenuItem mMoveMenu; // 菜单项移动操作项 + + /** + * 当ActionMode被创建时调用。用于初始化ActionMode的菜单。 + * @param mode ActionMode对象,用于处理多选模式下的交互事件。 + * @param menu 菜单对象,用于显示菜单项。 + * @return 是否成功创建ActionMode。如果成功创建返回true,否则返回false。 + */ + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // 使用指定的菜单项初始化ActionMode的菜单。这里是从R.menu.note_list_options加载菜单项。 + getMenuInflater().inflate(R.menu.note_list_options, menu); + // 在菜单中查找“删除”菜单项,并将其点击事件设置为当前类对象(this)。 + menu.findItem(R.id.delete).setOnMenuItemClickListener(this); + // 获取“移动”菜单项并保存到mMoveMenu变量中。如果“移动”菜单项存在的话。 + mMoveMenu = menu.findItem(R.id.move); + // 检查焦点笔记数据项的父ID是否为“调用记录文件夹”ID或用户文件夹数量是否为0。如果是的话,则隐藏“移动”菜单项。否则显示“移动” mActionMode = mode; mNotesListAdapter.setChoiceMode(true); mNotesListView.setLongClickable(false); @@ -269,199 +376,245 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } - private void updateMenu() { - int selectedCount = mNotesListAdapter.getSelectedCount(); - // Update dropdown menu - String format = getResources().getString(R.string.menu_select_title, selectedCount); - 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 { - item.setChecked(false); - item.setTitle(R.string.menu_select_all); - } - } - } - - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - // TODO Auto-generated method stub - return false; - } - - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // TODO Auto-generated method stub - return false; - } - - public void onDestroyActionMode(ActionMode mode) { - mNotesListAdapter.setChoiceMode(false); - mNotesListView.setLongClickable(true); - mAddNewNote.setVisibility(View.VISIBLE); + /** + * 更新菜单 + */ + private void updateMenu() { + // 获取已选择的数量 + int selectedCount = mNotesListAdapter.getSelectedCount(); + + // 更新下拉菜单的标题 + String format = getResources().getString(R.string.menu_select_title, selectedCount); + 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 { + item.setChecked(false); + item.setTitle(R.string.menu_select_all); // 设置标题为“全选” + } + } + } + + /** + * 在准备ActionMode时返回是否成功准备 + */ + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // TODO: 需要实现该方法来返回是否成功准备ActionMode + return false; + } + + /** + * 处理ActionMode的菜单项点击事件 + */ + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + // TODO: 需要实现该方法来处理菜单项点击事件 + return false; + } + + /** + * 当ActionMode销毁时执行的操作 + */ + public void onDestroyActionMode(ActionMode mode) { + // 取消选择模式,使列表项可长按,并显示添加新笔记的按钮 + mNotesListAdapter.setChoiceMode(false); + mNotesListView.setLongClickable(true); + mAddNewNote.setVisibility(View.VISIBLE); + } + + /** + * 结束ActionMode的方法 + */ + public void finishActionMode() { + mActionMode.finish(); // 结束ActionMode + } + + /** + * 当列表项的选中状态改变时调用此方法 + */ + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { + // 更新列表项的选中状态,并调用updateMenu()更新菜单状态 + mNotesListAdapter.setCheckedItem(position, checked); + updateMenu(); } - - public void finishActionMode() { - mActionMode.finish(); - } - - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - mNotesListAdapter.setCheckedItem(position, checked); - updateMenu(); + + + /** + * 处理菜单项点击事件 + * + * @param item 被点击的菜单项 + * @return 如果事件被成功处理,返回true;否则返回false + */ + public boolean onMenuItemClick(MenuItem item) { + // 如果没有任何项目被选中 + if (mNotesListAdapter.getSelectedCount() == 0) { + // 显示一个Toast提示没有选中的项目 + Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none), + Toast.LENGTH_SHORT).show(); + // 返回true表示事件被成功处理 + return true; + } + + // 根据菜单项的ID进行不同的操作 + switch (item.getItemId()) { + case R.id.delete: + // 创建一个删除确认对话框 + 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(); + } + }); + builder.setNegativeButton(android.R.string.cancel, null); // 设置取消按钮的文本为“取消”,不执行任何操作 + builder.show(); // 显示对话框 + break; // 结束case R.id.delete分支 + case R.id.move: + // 开始查询目标文件夹,用于移动操作 + startQueryDestinationFolders(); + break; // 结束case R.id.move分支 + default: + // 如果不是上述两种情况,返回false表示事件未被成功处理 + return false; + } + // 无论哪种情况,最后都返回true表示事件被成功处理 + return true; } - - 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; - } - - switch (item.getItemId()) { - case R.id.delete: - 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(); - } - }); - builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); - break; - case R.id.move: - startQueryDestinationFolders(); - break; - default: - return false; - } - return true; + + + // 定义一个私有内部类 NewNoteOnTouchListener,实现 OnTouchListener 接口 + private class NewNoteOnTouchListener implements OnTouchListener { + + // 实现 onTouch 方法,接收一个 View 和一个 MotionEvent 对象 + 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; + // 获取触摸事件在屏幕上的Y坐标 + int eventY = start + (int) event.getY(); + + /** + * 减去标题栏的高度 + */ + if (mState == ListEditState.SUB_FOLDER) { + // 如果当前状态是子文件夹状态,减去标题栏的高度 + eventY -= mTitleBar.getHeight(); + // 更新新笔记视图在屏幕上的起始位置 + start -= mTitleBar.getHeight(); + } + + // 如果触摸事件的Y坐标小于某个条件,执行以下操作 + 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))) { + // 保存触摸事件的Y坐标为起始位置 + mOriginY = (int) event.getY(); + // 更新新笔记视图在屏幕上的起始位置为事件Y坐标 + mDispatchY = eventY; + // 重置触摸事件的位置为新的X和Y坐标 + event.setLocation(event.getX(), mDispatchY); + // 设置一个标志位表示需要分发触摸事件给列表视图 + mDispatch = true; + // 分发触摸事件给列表视图并返回结果 + return mNotesListView.dispatchTouchEvent(event); + } + } + break; // 结束触摸事件的动作是 ACTION_DOWN 的分支 + } + case MotionEvent.ACTION_MOVE: { + // 如果设置了需要分发触摸事件的标志位,执行以下操作 + if (mDispatch) { + // 更新新笔记视图在屏幕上的起始位置为触摸事件的Y坐标减去起始位置的Y坐标加上起始位置的Y坐标(这里可能有一个错误) + mDispatchY += (int) event.getY() - mOriginY; + // 重置触摸事件的位置为新的X和Y坐标(这里可能有一个错误) + event.setLocation(event.getX(), mDispatchY); + // 分发触摸事件给列表视图并返回结果(这里可能有一个错误) + return mNotesListView.dispatchTouchEvent(event); + } + break; // 结束触摸事件的动作是 ACTION_MOVE 的分支(这里可能有一个错误) + } + } // 结束 switch 语句(这里可能有一个错误) + return false; // 如果不满足任何条件,返回 false(这里可能有一个错误) + } // 结束 onTouch 方法(这里可能有一个错误) + } // 结束 NewNoteOnTouchListener 类(这里可能有一个错误) + + + // 启动异步笔记列表查询 + private void startAsyncNotesListQuery() { + // 根据当前文件夹ID选择查询条件 + 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"); + } + + // 背景查询处理器,继承自AsyncQueryHandler + 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: // 如果token是笔记列表查询令牌 + // 更改笔记列表适配器的游标 + mNotesListAdapter.changeCursor(cursor); + break; + case FOLDER_LIST_QUERY_TOKEN: // 如果token是文件夹列表查询令牌 + if (cursor != null && cursor.getCount() > 0) { + // 显示文件夹列表菜单 + showFolderListMenu(cursor); + } else { + Log.e(TAG, "Query folder failed"); // 否则,记录错误日志 + } + break; + default: + return; // 其他情况直接返回 + } + } + } + + // 显示文件夹列表菜单的方法 + 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() { // 设置适配器并添加点击监听器 + // 这里应该是显示文件夹列表的点击事件处理代码,但您没有提供完整代码。 + }); } - } - - 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; - } - case MotionEvent.ACTION_MOVE: { - if (mDispatch) { - mDispatchY += (int) event.getY() - mOriginY; - event.setLocation(event.getX(), mDispatchY); - return mNotesListView.dispatchTouchEvent(event); - } - break; - } - default: { - if (mDispatch) { - event.setLocation(event.getX(), mDispatchY); - mDispatch = false; - return mNotesListView.dispatchTouchEvent(event); - } - break; - } - } - return false; - } - - }; - - 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"); - } - - 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: - return; - } - } - } - - 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(); - } - }); - builder.show(); - } - + private void createNewNote() { Intent intent = new Intent(this, NoteEditActivity.class); intent.setAction(Intent.ACTION_INSERT_OR_EDIT);