小米便签

小米便签
main
Sunique_L 1 year ago
parent 52b47764da
commit 77ce191c89

@ -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,

@ -29,7 +29,6 @@ import android.widget.NumberPicker;
// 定义一个公共类DateTimePicker它继承自FrameLayout
public class DateTimePicker extends FrameLayout {
// 定义一个默认的启用状态常量值为true
private static final boolean DEFAULT_ENABLE_STATE = true;

@ -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
// 定义一个公开的整型方法 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

@ -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();
}
/**
* ModeCallbackListView.MultiChoiceModeListenerOnMenuItemClickListener
*
*/
private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
// 创建下拉菜单对象和ActionMode对象用于处理多选模式下的菜单和动作模式等交互事件。
private DropdownMenu mDropDownMenu;
private ActionMode mActionMode;
private MenuItem mMoveMenu; // 菜单项移动操作项
/**
* ActionModeActionMode
* @param mode ActionMode
* @param menu
* @return ActionModetruefalse
*/
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 truefalse
*/
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+94Unit: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);

Loading…
Cancel
Save